Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


More detailed error handling on msr writes
[palacios.git] / palacios / src / devices / apic.c
1 /* 
2  * This file is part of the Palacios Virtual Machine Monitor developed
3  * by the V3VEE Project with funding from the United States National 
4  * Science Foundation and the Department of Energy.  
5  *
6  * The V3VEE Project is a joint project between Northwestern University
7  * and the University of New Mexico.  You can find out more at 
8  * http://www.v3vee.org
9  *
10  * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu> 
11  * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
12  * All rights reserved.
13  *
14  * Authors: Jack Lange <jarusl@cs.northwestern.edu>
15  *          Peter Dinda <pdinda@northwestern.edu> (SMP)
16  *
17  * This is free software.  You are permitted to use,
18  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
19  */
20
21
22 #include <devices/apic.h>
23 #include <devices/apic_regs.h>
24 #include <palacios/vmm.h>
25 #include <palacios/vmm_msr.h>
26 #include <palacios/vmm_sprintf.h>
27 #include <palacios/vm_guest.h>
28 #include <palacios/vmm_types.h>
29
30
31 #include <palacios/vmm_queue.h>
32 #include <palacios/vmm_lock.h>
33
34 /* The locking in this file is nasty.
35  * There are 3 different locking approaches that are taken, depending on the APIC operation
36  * 1. Queue locks. Actual irq insertions are done via queueing irq ops at the dest apic. 
37  *    The destination apic's core is responsible for draining the queue, and actually 
38  *    setting the vector table. 
39  * 2. State lock. This is a standard lock taken when internal apic state is read/written. 
40  *    When an irq's destination is determined this lock is taken to examine the apic's 
41  *    addressability. 
42  * 3. VM barrier lock. This is taken when actual VM core state is changed (via SIPI). 
43  */
44
45
46
47 #ifndef V3_CONFIG_DEBUG_APIC
48 #undef PrintDebug
49 #define PrintDebug(fmt, args...)
50 #else
51
52 static char * shorthand_str[] = { 
53     "(no shorthand)",
54     "(self)",
55     "(all)",
56     "(all-but-me)",
57 };
58
59 static char * deliverymode_str[] = { 
60     "(fixed)",
61     "(lowest priority)",
62     "(SMI)",
63     "(reserved)",
64     "(NMI)",
65     "(INIT)",
66     "(Start Up)",
67     "(ExtInt)",
68 };
69
70 #endif
71
72 typedef enum { APIC_TMR_INT, APIC_THERM_INT, APIC_PERF_INT, 
73                APIC_LINT0_INT, APIC_LINT1_INT, APIC_ERR_INT } apic_irq_type_t;
74
75 #define APIC_FIXED_DELIVERY  0x0
76 #define APIC_LOWEST_DELIVERY 0x1
77 #define APIC_SMI_DELIVERY    0x2
78 #define APIC_RES1_DELIVERY   0x3
79 #define APIC_NMI_DELIVERY    0x4
80 #define APIC_INIT_DELIVERY   0x5
81 #define APIC_SIPI_DELIVERY   0x6
82 #define APIC_EXTINT_DELIVERY 0x7
83
84 #define APIC_SHORTHAND_NONE        0x0
85 #define APIC_SHORTHAND_SELF        0x1
86 #define APIC_SHORTHAND_ALL         0x2
87 #define APIC_SHORTHAND_ALL_BUT_ME  0x3
88
89 #define APIC_DEST_PHYSICAL    0x0
90 #define APIC_DEST_LOGICAL     0x1
91
92
93 #define BASE_ADDR_MSR     0x0000001B
94 #define DEFAULT_BASE_ADDR 0xfee00000
95
96 #define APIC_ID_OFFSET                    0x020
97 #define APIC_VERSION_OFFSET               0x030
98 #define TPR_OFFSET                        0x080
99 #define APR_OFFSET                        0x090
100 #define PPR_OFFSET                        0x0a0
101 #define EOI_OFFSET                        0x0b0
102 #define REMOTE_READ_OFFSET                0x0c0
103 #define LDR_OFFSET                        0x0d0
104 #define DFR_OFFSET                        0x0e0
105 #define SPURIOUS_INT_VEC_OFFSET           0x0f0
106
107 #define ISR_OFFSET0                       0x100   // 0x100 - 0x170
108 #define ISR_OFFSET1                       0x110   // 0x100 - 0x170
109 #define ISR_OFFSET2                       0x120   // 0x100 - 0x170
110 #define ISR_OFFSET3                       0x130   // 0x100 - 0x170
111 #define ISR_OFFSET4                       0x140   // 0x100 - 0x170
112 #define ISR_OFFSET5                       0x150   // 0x100 - 0x170
113 #define ISR_OFFSET6                       0x160   // 0x100 - 0x170
114 #define ISR_OFFSET7                       0x170   // 0x100 - 0x170
115
116 #define TRIG_OFFSET0                      0x180   // 0x180 - 0x1f0
117 #define TRIG_OFFSET1                      0x190   // 0x180 - 0x1f0
118 #define TRIG_OFFSET2                      0x1a0   // 0x180 - 0x1f0
119 #define TRIG_OFFSET3                      0x1b0   // 0x180 - 0x1f0
120 #define TRIG_OFFSET4                      0x1c0   // 0x180 - 0x1f0
121 #define TRIG_OFFSET5                      0x1d0   // 0x180 - 0x1f0
122 #define TRIG_OFFSET6                      0x1e0   // 0x180 - 0x1f0
123 #define TRIG_OFFSET7                      0x1f0   // 0x180 - 0x1f0
124
125
126 #define IRR_OFFSET0                       0x200   // 0x200 - 0x270
127 #define IRR_OFFSET1                       0x210   // 0x200 - 0x270
128 #define IRR_OFFSET2                       0x220   // 0x200 - 0x270
129 #define IRR_OFFSET3                       0x230   // 0x200 - 0x270
130 #define IRR_OFFSET4                       0x240   // 0x200 - 0x270
131 #define IRR_OFFSET5                       0x250   // 0x200 - 0x270
132 #define IRR_OFFSET6                       0x260   // 0x200 - 0x270
133 #define IRR_OFFSET7                       0x270   // 0x200 - 0x270
134
135
136 #define ESR_OFFSET                        0x280
137 #define INT_CMD_LO_OFFSET                 0x300
138 #define INT_CMD_HI_OFFSET                 0x310
139 #define TMR_LOC_VEC_TBL_OFFSET            0x320
140 #define THERM_LOC_VEC_TBL_OFFSET          0x330
141 #define PERF_CTR_LOC_VEC_TBL_OFFSET       0x340
142 #define LINT0_VEC_TBL_OFFSET              0x350
143 #define LINT1_VEC_TBL_OFFSET              0x360
144 #define ERR_VEC_TBL_OFFSET                0x370
145 #define TMR_INIT_CNT_OFFSET               0x380
146 #define TMR_CUR_CNT_OFFSET                0x390
147 #define TMR_DIV_CFG_OFFSET                0x3e0
148 #define EXT_APIC_FEATURE_OFFSET           0x400
149 #define EXT_APIC_CMD_OFFSET               0x410
150 #define SEOI_OFFSET                       0x420
151
152 #define IER_OFFSET0                       0x480   // 0x480 - 0x4f0
153 #define IER_OFFSET1                       0x490   // 0x480 - 0x4f0
154 #define IER_OFFSET2                       0x4a0   // 0x480 - 0x4f0
155 #define IER_OFFSET3                       0x4b0   // 0x480 - 0x4f0
156 #define IER_OFFSET4                       0x4c0   // 0x480 - 0x4f0
157 #define IER_OFFSET5                       0x4d0   // 0x480 - 0x4f0
158 #define IER_OFFSET6                       0x4e0   // 0x480 - 0x4f0
159 #define IER_OFFSET7                       0x4f0   // 0x480 - 0x4f0
160
161 #define EXT_INT_LOC_VEC_TBL_OFFSET0       0x500   // 0x500 - 0x530
162 #define EXT_INT_LOC_VEC_TBL_OFFSET1       0x510   // 0x500 - 0x530
163 #define EXT_INT_LOC_VEC_TBL_OFFSET2       0x520   // 0x500 - 0x530
164 #define EXT_INT_LOC_VEC_TBL_OFFSET3       0x530   // 0x500 - 0x530
165
166 struct apic_msr {
167     union {
168         uint64_t value;
169         struct {
170             uint8_t rsvd;
171             uint8_t bootstrap_cpu : 1;
172             uint8_t rsvd2         : 2;
173             uint8_t apic_enable   : 1;
174             uint64_t base_addr    : 40;
175             uint32_t rsvd3        : 12;
176         } __attribute__((packed));
177     } __attribute__((packed));
178 } __attribute__((packed));
179
180
181
182
183 typedef enum {INIT_ST, 
184               SIPI, 
185               STARTED} ipi_state_t; 
186
187 struct apic_dev_state;
188
189 struct apic_state {
190     addr_t base_addr;
191
192     /* MSRs */
193     struct apic_msr base_addr_msr;
194
195
196     /* memory map registers */
197
198     struct lapic_id_reg lapic_id;
199     struct apic_ver_reg apic_ver;
200     struct ext_apic_ctrl_reg ext_apic_ctrl;
201     struct local_vec_tbl_reg local_vec_tbl;
202     struct tmr_vec_tbl_reg tmr_vec_tbl;
203     struct tmr_div_cfg_reg tmr_div_cfg;
204     struct lint_vec_tbl_reg lint0_vec_tbl;
205     struct lint_vec_tbl_reg lint1_vec_tbl;
206     struct perf_ctr_loc_vec_tbl_reg perf_ctr_loc_vec_tbl;
207     struct therm_loc_vec_tbl_reg therm_loc_vec_tbl;
208     struct err_vec_tbl_reg err_vec_tbl;
209     struct err_status_reg err_status;
210     struct spurious_int_reg spurious_int;
211     struct int_cmd_reg int_cmd;
212     struct log_dst_reg log_dst;
213     struct dst_fmt_reg dst_fmt;
214     struct arb_prio_reg arb_prio;
215     struct task_prio_reg task_prio;
216     struct proc_prio_reg proc_prio;
217     struct ext_apic_feature_reg ext_apic_feature;
218     struct spec_eoi_reg spec_eoi;
219   
220
221     uint32_t tmr_cur_cnt;
222     uint32_t tmr_init_cnt;
223     uint32_t missed_ints;
224
225     struct local_vec_tbl_reg ext_intr_vec_tbl[4];
226
227     uint32_t rem_rd_data;
228
229
230     ipi_state_t ipi_state;
231
232     uint8_t int_req_reg[32];
233     uint8_t int_svc_reg[32];
234     uint8_t int_en_reg[32];
235     uint8_t trig_mode_reg[32];
236
237     struct guest_info * core;
238
239     void * controller_handle;
240
241     struct v3_timer * timer;
242
243
244     struct v3_queue irq_queue;
245
246     uint32_t eoi;
247
248
249 };
250
251
252
253
254 struct apic_dev_state {
255     int num_apics;
256   
257     v3_lock_t state_lock;
258
259     struct apic_state apics[0];
260 } __attribute__((packed));
261
262
263
264
265
266 static int apic_read(struct guest_info * core, addr_t guest_addr, void * dst, uint_t length, void * priv_data);
267 static int apic_write(struct guest_info * core, addr_t guest_addr, void * src, uint_t length, void * priv_data);
268
269 // No lcoking done
270 static void init_apic_state(struct apic_state * apic, uint32_t id) {
271     apic->base_addr = DEFAULT_BASE_ADDR;
272
273     if (id == 0) { 
274         // boot processor, enabled
275         apic->base_addr_msr.value = 0x0000000000000900LL;
276     } else {
277         // ap processor, enabled
278         apic->base_addr_msr.value = 0x0000000000000800LL;
279     }
280
281     // same base address regardless of ap or main
282     apic->base_addr_msr.value |= ((uint64_t)DEFAULT_BASE_ADDR); 
283
284     PrintDebug("apic %u: (init_apic_state): msr=0x%llx\n",id, apic->base_addr_msr.value);
285
286     PrintDebug("apic %u: (init_apic_state): Sizeof Interrupt Request Register %d, should be 32\n",
287                id, (uint_t)sizeof(apic->int_req_reg));
288
289     memset(apic->int_req_reg, 0, sizeof(apic->int_req_reg));
290     memset(apic->int_svc_reg, 0, sizeof(apic->int_svc_reg));
291     memset(apic->int_en_reg, 0xff, sizeof(apic->int_en_reg));
292     memset(apic->trig_mode_reg, 0, sizeof(apic->trig_mode_reg));
293
294     apic->eoi = 0x00000000;
295     apic->rem_rd_data = 0x00000000;
296     apic->tmr_init_cnt = 0x00000000;
297     apic->tmr_cur_cnt = 0x00000000;
298     apic->missed_ints = 0;
299
300     apic->lapic_id.val = id;
301     
302     apic->ipi_state = INIT_ST;
303
304     // The P6 has 6 LVT entries, so we set the value to (6-1)...
305     apic->apic_ver.val = 0x80050010;
306
307     apic->task_prio.val = 0x00000000;
308     apic->arb_prio.val = 0x00000000;
309     apic->proc_prio.val = 0x00000000;
310     apic->log_dst.val = 0x00000000;
311     apic->dst_fmt.val = 0xffffffff;
312     apic->spurious_int.val = 0x000000ff;
313     apic->err_status.val = 0x00000000;
314     apic->int_cmd.val = 0x0000000000000000LL;
315     apic->tmr_vec_tbl.val = 0x00010000;
316     apic->therm_loc_vec_tbl.val = 0x00010000;
317     apic->perf_ctr_loc_vec_tbl.val = 0x00010000;
318     apic->lint0_vec_tbl.val = 0x00010000;
319     apic->lint1_vec_tbl.val = 0x00010000;
320     apic->err_vec_tbl.val = 0x00010000;
321     apic->tmr_div_cfg.val = 0x00000000;
322     //apic->ext_apic_feature.val = 0x00000007;
323     apic->ext_apic_feature.val = 0x00040007;
324     apic->ext_apic_ctrl.val = 0x00000000;
325     apic->spec_eoi.val = 0x00000000;
326
327
328     v3_init_queue(&(apic->irq_queue));
329
330
331 }
332
333
334
335
336
337 static int read_apic_msr(struct guest_info * core, uint_t msr, v3_msr_t * dst, void * priv_data) {
338     struct apic_dev_state * apic_dev = (struct apic_dev_state *)priv_data;
339     struct apic_state * apic = &(apic_dev->apics[core->vcpu_id]);
340
341     PrintDebug("apic %u: core %u: MSR read\n", apic->lapic_id.val, core->vcpu_id);
342
343     dst->value = apic->base_addr;
344
345     return 0;
346 }
347
348
349 static int write_apic_msr(struct guest_info * core, uint_t msr, v3_msr_t src, void * priv_data) {
350     struct apic_dev_state * apic_dev = (struct apic_dev_state *)priv_data;
351     struct apic_state * apic = &(apic_dev->apics[core->vcpu_id]);
352     struct v3_mem_region * old_reg = v3_get_mem_region(core->vm_info, core->vcpu_id, apic->base_addr);
353
354
355     PrintDebug("apic %u: core %u: MSR write\n", apic->lapic_id.val, core->vcpu_id);
356
357     if (old_reg == NULL) {
358         // uh oh...
359         PrintError("apic %u: core %u: APIC Base address region does not exit...\n",
360                    apic->lapic_id.val, core->vcpu_id);
361         return -1;
362     }
363     
364
365
366     v3_delete_mem_region(core->vm_info, old_reg);
367
368     apic->base_addr = src.value;
369
370     if (v3_hook_full_mem(core->vm_info, core->vcpu_id, apic->base_addr, 
371                          apic->base_addr + PAGE_SIZE_4KB, 
372                          apic_read, apic_write, apic_dev) == -1) {
373         PrintError("apic %u: core %u: Could not hook new APIC Base address\n",
374                    apic->lapic_id.val, core->vcpu_id);
375
376         return -1;
377     }
378
379
380     return 0;
381 }
382
383
384
385
386
387 // irq_num is the bit offset into a 256 bit buffer...
388 static int activate_apic_irq(struct apic_state * apic, uint32_t irq_num) {
389     int major_offset = (irq_num & ~0x00000007) >> 3;
390     int minor_offset = irq_num & 0x00000007;
391     uint8_t * req_location = apic->int_req_reg + major_offset;
392     uint8_t * en_location = apic->int_en_reg + major_offset;
393     uint8_t flag = 0x1 << minor_offset;
394
395
396     PrintDebug("apic %u: core %d: Raising APIC IRQ %d\n", apic->lapic_id.val, apic->core->vcpu_id, irq_num);
397
398     if (*req_location & flag) {
399         PrintDebug("Interrupt %d  coallescing\n", irq_num);
400         return 0;
401     }
402
403     if (*en_location & flag) {
404         *req_location |= flag;
405         return 1;
406     } else {
407         PrintDebug("apic %u: core %d: Interrupt  not enabled... %.2x\n", 
408                    apic->lapic_id.val, apic->core->vcpu_id, *en_location);
409     }
410
411     return 0;
412 }
413
414
415 static int add_apic_irq_entry(struct apic_state * apic, uint8_t irq_num) {
416
417     if (irq_num <= 15) {
418         PrintError("core %d: Attempting to raise an invalid interrupt: %d\n", 
419                     apic->core->vcpu_id, irq_num);
420         return -1;
421     }
422
423     v3_enqueue(&(apic->irq_queue), (addr_t)irq_num);
424
425     return 0;
426 }
427
428 static void drain_irq_entries(struct apic_state * apic) {
429     uint32_t irq = 0;
430
431     while ((irq = (uint32_t)v3_dequeue(&(apic->irq_queue))) != 0) {
432         activate_apic_irq(apic, irq);
433     }
434
435 }
436
437
438
439
440 static int get_highest_isr(struct apic_state * apic) {
441     int i = 0, j = 0;
442
443     // We iterate backwards to find the highest priority
444     for (i = 31; i >= 0; i--) {
445         uint8_t  * svc_major = apic->int_svc_reg + i;
446     
447         if ((*svc_major) & 0xff) {
448             for (j = 7; j >= 0; j--) {
449                 uint8_t flag = 0x1 << j;
450                 if ((*svc_major) & flag) {
451                     return ((i * 8) + j);
452                 }
453             }
454         }
455     }
456
457     return -1;
458 }
459  
460
461
462 static int get_highest_irr(struct apic_state * apic) {
463     int i = 0, j = 0;
464
465     // We iterate backwards to find the highest priority
466     for (i = 31; i >= 0; i--) {
467         uint8_t  * req_major = apic->int_req_reg + i;
468     
469         if ((*req_major) & 0xff) {
470             for (j = 7; j >= 0; j--) {
471                 uint8_t flag = 0x1 << j;
472                 if ((*req_major) & flag) {
473                     return ((i * 8) + j);
474                 }
475             }
476         }
477     }
478
479     return -1;
480 }
481  
482
483
484
485 static int apic_do_eoi(struct apic_state * apic) {
486     int isr_irq = get_highest_isr(apic);
487
488     if (isr_irq != -1) {
489         int major_offset = (isr_irq & ~0x00000007) >> 3;
490         int minor_offset = isr_irq & 0x00000007;
491         uint8_t flag = 0x1 << minor_offset;
492         uint8_t * svc_location = apic->int_svc_reg + major_offset;
493         
494         PrintDebug("apic %u: core ?: Received APIC EOI for IRQ %d\n", apic->lapic_id.val,isr_irq);
495         
496         *svc_location &= ~flag;
497
498 #ifdef V3_CONFIG_CRAY_XT
499         
500         if ((isr_irq == 238) || 
501             (isr_irq == 239)) {
502             PrintDebug("apic %u: core ?: Acking IRQ %d\n", apic->lapic_id.val,isr_irq);
503         }
504         
505         if (isr_irq == 238) {
506             V3_ACK_IRQ(238);
507         }
508 #endif
509     } else {
510         //PrintError("apic %u: core ?: Spurious EOI...\n",apic->lapic_id.val);
511     }
512         
513     return 0;
514 }
515  
516
517 static int activate_internal_irq(struct apic_state * apic, apic_irq_type_t int_type) {
518     uint32_t vec_num = 0;
519     uint32_t del_mode = 0;
520     int masked = 0;
521
522
523     switch (int_type) {
524         case APIC_TMR_INT:
525             vec_num = apic->tmr_vec_tbl.vec;
526             del_mode = APIC_FIXED_DELIVERY;
527             masked = apic->tmr_vec_tbl.mask;
528             break;
529         case APIC_THERM_INT:
530             vec_num = apic->therm_loc_vec_tbl.vec;
531             del_mode = apic->therm_loc_vec_tbl.msg_type;
532             masked = apic->therm_loc_vec_tbl.mask;
533             break;
534         case APIC_PERF_INT:
535             vec_num = apic->perf_ctr_loc_vec_tbl.vec;
536             del_mode = apic->perf_ctr_loc_vec_tbl.msg_type;
537             masked = apic->perf_ctr_loc_vec_tbl.mask;
538             break;
539         case APIC_LINT0_INT:
540             vec_num = apic->lint0_vec_tbl.vec;
541             del_mode = apic->lint0_vec_tbl.msg_type;
542             masked = apic->lint0_vec_tbl.mask;
543             break;
544         case APIC_LINT1_INT:
545             vec_num = apic->lint1_vec_tbl.vec;
546             del_mode = apic->lint1_vec_tbl.msg_type;
547             masked = apic->lint1_vec_tbl.mask;
548             break;
549         case APIC_ERR_INT:
550             vec_num = apic->err_vec_tbl.vec;
551             del_mode = APIC_FIXED_DELIVERY;
552             masked = apic->err_vec_tbl.mask;
553             break;
554         default:
555             PrintError("apic %u: core ?: Invalid APIC interrupt type\n", apic->lapic_id.val);
556             return -1;
557     }
558
559     // interrupt is masked, don't send
560     if (masked == 1) {
561         PrintDebug("apic %u: core ?: Inerrupt is masked\n", apic->lapic_id.val);
562         return 0;
563     }
564
565     if (del_mode == APIC_FIXED_DELIVERY) {
566         //PrintDebug("Activating internal APIC IRQ %d\n", vec_num);
567         return add_apic_irq_entry(apic, vec_num);
568     } else {
569         PrintError("apic %u: core ?: Unhandled Delivery Mode\n", apic->lapic_id.val);
570         return -1;
571     }
572 }
573
574
575
576 static inline int should_deliver_cluster_ipi(struct apic_dev_state * apic_dev,
577                                              struct guest_info * dst_core, 
578                                              struct apic_state * dst_apic, uint8_t mda) {
579
580     int ret = 0;
581
582
583     if  ( ((mda & 0xf0) == (dst_apic->log_dst.dst_log_id & 0xf0)) &&  /* (I am in the cluster and */
584           ((mda & 0x0f) & (dst_apic->log_dst.dst_log_id & 0x0f)) ) {  /*  I am in the set)        */
585         ret = 1;
586     } else {
587         ret = 0;
588     }
589
590
591     if (ret == 1) {
592         PrintDebug("apic %u core %u: accepting clustered IRQ (mda 0x%x == log_dst 0x%x)\n",
593                    dst_apic->lapic_id.val, dst_core->vcpu_id, mda, 
594                    dst_apic->log_dst.dst_log_id);
595     } else {
596         PrintDebug("apic %u core %u: rejecting clustered IRQ (mda 0x%x != log_dst 0x%x)\n",
597                    dst_apic->lapic_id.val, dst_core->vcpu_id, mda, 
598                    dst_apic->log_dst.dst_log_id);
599     }
600
601     return ret;
602
603 }
604
605 static inline int should_deliver_flat_ipi(struct apic_dev_state * apic_dev,
606                                           struct guest_info * dst_core,
607                                           struct apic_state * dst_apic, uint8_t mda) {
608
609     int ret = 0;
610
611
612     if ((dst_apic->log_dst.dst_log_id & mda) != 0) {  // I am in the set 
613         ret = 1;
614     } else {
615         ret = 0;
616     }
617
618
619     if (ret == 1) {
620         PrintDebug("apic %u core %u: accepting flat IRQ (mda 0x%x == log_dst 0x%x)\n",
621                    dst_apic->lapic_id.val, dst_core->vcpu_id, mda, 
622                    dst_apic->log_dst.dst_log_id);
623     } else {
624         PrintDebug("apic %u core %u: rejecting flat IRQ (mda 0x%x != log_dst 0x%x)\n",
625                    dst_apic->lapic_id.val, dst_core->vcpu_id, mda, 
626                    dst_apic->log_dst.dst_log_id);
627     }
628
629
630     return ret;
631 }
632
633
634
635 static int should_deliver_ipi(struct apic_dev_state * apic_dev, 
636                               struct guest_info * dst_core, 
637                               struct apic_state * dst_apic, uint8_t mda) {
638     addr_t flags = 0;
639     int ret = 0;
640
641     flags = v3_lock_irqsave(apic_dev->state_lock);
642
643     if (dst_apic->dst_fmt.model == 0xf) {
644
645         if (mda == 0xff) {
646             /* always deliver broadcast */
647             ret = 1;
648         } else {
649             ret = should_deliver_flat_ipi(apic_dev, dst_core, dst_apic, mda);
650         }
651     } else if (dst_apic->dst_fmt.model == 0x0) {
652
653         if (mda == 0xff) {
654             /*  always deliver broadcast */
655             ret = 1;
656         } else {
657             ret = should_deliver_cluster_ipi(apic_dev, dst_core, dst_apic, mda);
658         }
659
660     } else {
661         ret = -1;
662     }
663     
664     v3_unlock_irqrestore(apic_dev->state_lock, flags);
665
666
667     if (ret == -1) {
668         PrintError("apic %u core %u: invalid destination format register value 0x%x for logical mode delivery.\n", 
669                    dst_apic->lapic_id.val, dst_core->vcpu_id, dst_apic->dst_fmt.model);
670     }
671
672     return ret;
673 }
674
675
676
677
678 // Only the src_apic pointer is used
679 static int deliver_ipi(struct apic_state * src_apic, 
680                        struct apic_state * dst_apic, 
681                        uint32_t vector, uint8_t del_mode) {
682
683
684     struct guest_info * dst_core = dst_apic->core;
685
686
687     switch (del_mode) {
688
689         case APIC_FIXED_DELIVERY:  
690         case APIC_LOWEST_DELIVERY: {
691             // lowest priority - 
692             // caller needs to have decided which apic to deliver to!
693
694             PrintDebug("delivering IRQ %d to core %u\n", vector, dst_core->vcpu_id); 
695
696             add_apic_irq_entry(dst_apic, vector);
697             
698 #ifdef V3_CONFIG_MULTITHREAD_OS
699             if (dst_apic != src_apic) { 
700                 PrintDebug(" non-local core with new interrupt, forcing it to exit now\n"); 
701                 v3_interrupt_cpu(dst_core->vm_info, dst_core->pcpu_id, 0);
702             }
703 #endif
704
705
706             break;
707         }
708         case APIC_INIT_DELIVERY: { 
709
710             PrintDebug(" INIT delivery to core %u\n", dst_core->vcpu_id);
711
712             // TODO: any APIC reset on dest core (shouldn't be needed, but not sure...)
713
714             // Sanity check
715             if (dst_apic->ipi_state != INIT_ST) { 
716                 PrintError(" Warning: core %u is not in INIT state (mode = %d), ignored (assuming this is the deassert)\n",
717                            dst_core->vcpu_id, dst_apic->ipi_state);
718                 // Only a warning, since INIT INIT SIPI is common
719                 break;
720             }
721
722             // We transition the target core to SIPI state
723             dst_apic->ipi_state = SIPI;  // note: locking should not be needed here
724
725             // That should be it since the target core should be
726             // waiting in host on this transition
727             // either it's on another core or on a different preemptive thread
728             // in both cases, it will quickly notice this transition 
729             // in particular, we should not need to force an exit here
730
731             PrintDebug(" INIT delivery done\n");
732
733             break;                                                      
734         }
735         case APIC_SIPI_DELIVERY: { 
736
737             // Sanity check
738             if (dst_apic->ipi_state != SIPI) { 
739                 PrintError(" core %u is not in SIPI state (mode = %d), ignored!\n",
740                            dst_core->vcpu_id, dst_apic->ipi_state);
741                 break;
742             }
743
744             v3_reset_vm_core(dst_core, vector);
745
746             PrintDebug(" SIPI delivery (0x%x -> 0x%x:0x0) to core %u\n",
747                        vector, dst_core->segments.cs.selector, dst_core->vcpu_id);
748             // Maybe need to adjust the APIC?
749             
750             // We transition the target core to SIPI state
751             dst_core->core_run_state = CORE_RUNNING;  // note: locking should not be needed here
752             dst_apic->ipi_state = STARTED;
753             
754             // As with INIT, we should not need to do anything else
755             
756             PrintDebug(" SIPI delivery done\n");
757             
758             break;                                                      
759         }
760
761         case APIC_EXTINT_DELIVERY: // EXTINT
762             /* Two possible things to do here: 
763              * 1. Ignore the IPI and assume the 8259a (PIC) will handle it
764              * 2. Add 32 to the vector and inject it...
765              * We probably just want to do 1 here, and assume the raise_irq() will hit the 8259a.
766              */
767             return 0;
768
769         case APIC_SMI_DELIVERY: 
770         case APIC_RES1_DELIVERY: // reserved                                            
771         case APIC_NMI_DELIVERY:
772         default:
773             PrintError("IPI %d delivery is unsupported\n", del_mode); 
774             return -1;
775     }
776     
777     return 0;
778     
779 }
780
781 static struct apic_state * find_physical_apic(struct apic_dev_state * apic_dev, uint32_t dst_idx) {
782     struct apic_state * dst_apic = NULL;
783     addr_t flags;
784     int i;
785
786     flags = v3_lock_irqsave(apic_dev->state_lock);
787
788     if ( (dst_idx > 0) && (dst_idx < apic_dev->num_apics) ) { 
789         // see if it simply is the core id
790         if (apic_dev->apics[dst_idx].lapic_id.val == dst_idx) { 
791              dst_apic = &(apic_dev->apics[dst_idx]);
792         }
793     }
794
795     for (i = 0; i < apic_dev->num_apics; i++) { 
796         if (apic_dev->apics[i].lapic_id.val == dst_idx) { 
797             dst_apic =  &(apic_dev->apics[i]);
798         }
799     }
800
801     v3_unlock_irqrestore(apic_dev->state_lock, flags);
802
803     return dst_apic;
804
805 }
806
807
808 static int route_ipi(struct apic_dev_state * apic_dev,
809                      struct apic_state * src_apic, 
810                      struct int_cmd_reg * icr) {
811     struct apic_state * dest_apic = NULL;
812
813
814     PrintDebug("apic: IPI %s %u from apic %p to %s %s %u (icr=0x%llx)\n",
815                deliverymode_str[icr->del_mode], 
816                icr->vec, 
817                src_apic,               
818                (icr->dst_mode == 0) ? "(physical)" : "(logical)", 
819                shorthand_str[icr->dst_shorthand], 
820                icr->dst,
821                icr->val);
822
823
824     switch (icr->dst_shorthand) {
825
826         case APIC_SHORTHAND_NONE:  // no shorthand
827             if (icr->dst_mode == APIC_DEST_PHYSICAL) { 
828
829                 dest_apic = find_physical_apic(apic_dev, icr->dst);
830                 
831                 if (dest_apic == NULL) { 
832                     PrintError("apic: Attempted send to unregistered apic id=%u\n", icr->dst);
833                     return -1;
834                 }
835
836                 if (deliver_ipi(src_apic, dest_apic, 
837                                 icr->vec, icr->del_mode) == -1) {
838                     PrintError("apic: Could not deliver IPI\n");
839                     return -1;
840                 }
841
842
843                 PrintDebug("apic: done\n");
844
845             } else if (icr->dst_mode == APIC_DEST_LOGICAL) {
846                 
847                 if (icr->del_mode != APIC_LOWEST_DELIVERY) { 
848                     int i;
849                     uint8_t mda = icr->dst;
850
851                     // logical, but not lowest priority
852                     // we immediately trigger
853                     // fixed, smi, reserved, nmi, init, sipi, etc
854
855                     
856                     for (i = 0; i < apic_dev->num_apics; i++) { 
857                         int del_flag = 0;
858                         
859                         dest_apic = &(apic_dev->apics[i]);
860                         
861                         del_flag = should_deliver_ipi(apic_dev, dest_apic->core, dest_apic, mda);
862                         
863                         if (del_flag == -1) {
864
865                             PrintError("apic: Error checking delivery mode\n");
866                             return -1;
867                         } else if (del_flag == 1) {
868
869                             if (deliver_ipi(src_apic, dest_apic, 
870                                             icr->vec, icr->del_mode) == -1) {
871                                 PrintError("apic: Error: Could not deliver IPI\n");
872                                 return -1;
873                             }
874                         }
875                     }
876                 } else {  // APIC_LOWEST_DELIVERY
877                     struct apic_state * cur_best_apic = NULL;
878                     uint8_t mda = icr->dst;
879                     int i;
880
881                     // logical, lowest priority
882
883                     for (i = 0; i < apic_dev->num_apics; i++) { 
884                         int del_flag = 0;
885
886                         dest_apic = &(apic_dev->apics[i]);
887                         
888                         del_flag = should_deliver_ipi(apic_dev, dest_apic->core, dest_apic, mda);
889                         
890                         if (del_flag == -1) {
891                             PrintError("apic: Error checking delivery mode\n");
892
893                             return -1;
894                         } else if (del_flag == 1) {
895                             // update priority for lowest priority scan
896                             addr_t flags = 0;
897
898                             flags = v3_lock_irqsave(apic_dev->state_lock);
899
900                             if (cur_best_apic == 0) {
901                                 cur_best_apic = dest_apic;  
902                             } else if (dest_apic->task_prio.val < cur_best_apic->task_prio.val) {
903                                 cur_best_apic = dest_apic;
904                             } 
905
906                             v3_unlock_irqrestore(apic_dev->state_lock, flags);
907
908                         }                       
909                     }
910
911                     // now we will deliver to the best one if it exists
912                     if (!cur_best_apic) { 
913                         PrintDebug("apic: lowest priority deliver, but no destinations!\n");
914                     } else {
915                         if (deliver_ipi(src_apic, cur_best_apic, 
916                                         icr->vec, icr->del_mode) == -1) {
917                             PrintError("apic: Error: Could not deliver IPI\n");
918                             return -1;
919                         }
920                         //V3_Print("apic: logical, lowest priority delivery to apic %u\n",cur_best_apic->lapic_id.val);
921                     }
922                 }
923             }
924
925             break;
926             
927         case APIC_SHORTHAND_SELF:  // self
928
929             if (src_apic == NULL) {    /* this is not an apic, but it's trying to send to itself??? */
930                 PrintError("apic: Sending IPI to self from generic IPI sender\n");
931                 break;
932             }
933
934
935
936             if (icr->dst_mode == APIC_DEST_PHYSICAL)  {  /* physical delivery */
937                 if (deliver_ipi(src_apic, src_apic, icr->vec, icr->del_mode) == -1) {
938                     PrintError("apic: Could not deliver IPI to self (physical)\n");
939                     return -1;
940                 }
941             } else if (icr->dst_mode == APIC_DEST_LOGICAL) {  /* logical delivery */
942                 PrintError("apic: use of logical delivery in self (untested)\n");
943
944                 if (deliver_ipi(src_apic, src_apic, icr->vec, icr->del_mode) == -1) {
945                     PrintError("apic: Could not deliver IPI to self (logical)\n");
946                     return -1;
947                 }
948             }
949
950             break;
951             
952         case APIC_SHORTHAND_ALL: 
953         case APIC_SHORTHAND_ALL_BUT_ME: { /* all and all-but-me */
954             /* assuming that logical verus physical doesn't matter
955                although it is odd that both are used */
956             int i;
957
958             for (i = 0; i < apic_dev->num_apics; i++) { 
959                 dest_apic = &(apic_dev->apics[i]);
960                 
961                 if ((dest_apic != src_apic) || (icr->dst_shorthand == APIC_SHORTHAND_ALL)) { 
962                     if (deliver_ipi(src_apic, dest_apic, icr->vec, icr->del_mode) == -1) {
963                         PrintError("apic: Error: Could not deliver IPI\n");
964                         return -1;
965                     }
966                 }
967             }
968
969             break;
970         }
971         default:
972             PrintError("apic: Error routing IPI, invalid Mode (%d)\n", icr->dst_shorthand);
973             return -1;
974     }
975  
976     return 0;
977 }
978
979
980 // External function, expected to acquire lock on apic
981 static int apic_read(struct guest_info * core, addr_t guest_addr, void * dst, uint_t length, void * priv_data) {
982     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(priv_data);
983     struct apic_state * apic = &(apic_dev->apics[core->vcpu_id]);
984     addr_t reg_addr  = guest_addr - apic->base_addr;
985     struct apic_msr * msr = (struct apic_msr *)&(apic->base_addr_msr.value);
986     uint32_t val = 0;
987
988
989     PrintDebug("apic %u: core %u: at %p: Read apic address space (%p)\n",
990                apic->lapic_id.val, core->vcpu_id, apic, (void *)guest_addr);
991
992     if (msr->apic_enable == 0) {
993         PrintError("apic %u: core %u: Read from APIC address space with disabled APIC, apic msr=0x%llx\n",
994                    apic->lapic_id.val, core->vcpu_id, apic->base_addr_msr.value);
995         return -1;
996     }
997
998
999     /* Because "May not be supported" doesn't matter to Linux developers... */
1000     /*   if (length != 4) { */
1001     /*     PrintError("Invalid apic read length (%d)\n", length); */
1002     /*     return -1; */
1003     /*   } */
1004
1005     switch (reg_addr & ~0x3) {
1006         case EOI_OFFSET:
1007             // Well, only an idiot would read from a architectural write only register
1008             // Oh, Hello Linux.
1009             //    PrintError("Attempting to read from write only register\n");
1010             //    return -1;
1011             break;
1012
1013             // data registers
1014         case APIC_ID_OFFSET:
1015             val = apic->lapic_id.val;
1016             break;
1017         case APIC_VERSION_OFFSET:
1018             val = apic->apic_ver.val;
1019             break;
1020         case TPR_OFFSET:
1021             val = apic->task_prio.val;
1022             break;
1023         case APR_OFFSET:
1024             val = apic->arb_prio.val;
1025             break;
1026         case PPR_OFFSET:
1027             val = apic->proc_prio.val;
1028             break;
1029         case REMOTE_READ_OFFSET:
1030             val = apic->rem_rd_data;
1031             break;
1032         case LDR_OFFSET:
1033             val = apic->log_dst.val;
1034             break;
1035         case DFR_OFFSET:
1036             val = apic->dst_fmt.val;
1037             break;
1038         case SPURIOUS_INT_VEC_OFFSET:
1039             val = apic->spurious_int.val;
1040             break;
1041         case ESR_OFFSET:
1042             val = apic->err_status.val;
1043             break;
1044         case TMR_LOC_VEC_TBL_OFFSET:
1045             val = apic->tmr_vec_tbl.val;
1046             break;
1047         case LINT0_VEC_TBL_OFFSET:
1048             val = apic->lint0_vec_tbl.val;
1049             break;
1050         case LINT1_VEC_TBL_OFFSET:
1051             val = apic->lint1_vec_tbl.val;
1052             break;
1053         case ERR_VEC_TBL_OFFSET:
1054             val = apic->err_vec_tbl.val;
1055             break;
1056         case TMR_INIT_CNT_OFFSET:
1057             val = apic->tmr_init_cnt;
1058             break;
1059         case TMR_DIV_CFG_OFFSET:
1060             val = apic->tmr_div_cfg.val;
1061             break;
1062
1063         case IER_OFFSET0:
1064             val = *(uint32_t *)(apic->int_en_reg);
1065             break;
1066         case IER_OFFSET1:
1067             val = *(uint32_t *)(apic->int_en_reg + 4);
1068             break;
1069         case IER_OFFSET2:
1070             val = *(uint32_t *)(apic->int_en_reg + 8);
1071             break;
1072         case IER_OFFSET3:
1073             val = *(uint32_t *)(apic->int_en_reg + 12);
1074             break;
1075         case IER_OFFSET4:
1076             val = *(uint32_t *)(apic->int_en_reg + 16);
1077             break;
1078         case IER_OFFSET5:
1079             val = *(uint32_t *)(apic->int_en_reg + 20);
1080             break;
1081         case IER_OFFSET6:
1082             val = *(uint32_t *)(apic->int_en_reg + 24);
1083             break;
1084         case IER_OFFSET7:
1085             val = *(uint32_t *)(apic->int_en_reg + 28);
1086             break;
1087
1088         case ISR_OFFSET0:
1089             val = *(uint32_t *)(apic->int_svc_reg);
1090             break;
1091         case ISR_OFFSET1:
1092             val = *(uint32_t *)(apic->int_svc_reg + 4);
1093             break;
1094         case ISR_OFFSET2:
1095             val = *(uint32_t *)(apic->int_svc_reg + 8);
1096             break;
1097         case ISR_OFFSET3:
1098             val = *(uint32_t *)(apic->int_svc_reg + 12);
1099             break;
1100         case ISR_OFFSET4:
1101             val = *(uint32_t *)(apic->int_svc_reg + 16);
1102             break;
1103         case ISR_OFFSET5:
1104             val = *(uint32_t *)(apic->int_svc_reg + 20);
1105             break;
1106         case ISR_OFFSET6:
1107             val = *(uint32_t *)(apic->int_svc_reg + 24);
1108             break;
1109         case ISR_OFFSET7:
1110             val = *(uint32_t *)(apic->int_svc_reg + 28);
1111             break;
1112    
1113         case TRIG_OFFSET0:
1114             val = *(uint32_t *)(apic->trig_mode_reg);
1115             break;
1116         case TRIG_OFFSET1:
1117             val = *(uint32_t *)(apic->trig_mode_reg + 4);
1118             break;
1119         case TRIG_OFFSET2:
1120             val = *(uint32_t *)(apic->trig_mode_reg + 8);
1121             break;
1122         case TRIG_OFFSET3:
1123             val = *(uint32_t *)(apic->trig_mode_reg + 12);
1124             break;
1125         case TRIG_OFFSET4:
1126             val = *(uint32_t *)(apic->trig_mode_reg + 16);
1127             break;
1128         case TRIG_OFFSET5:
1129             val = *(uint32_t *)(apic->trig_mode_reg + 20);
1130             break;
1131         case TRIG_OFFSET6:
1132             val = *(uint32_t *)(apic->trig_mode_reg + 24);
1133             break;
1134         case TRIG_OFFSET7:
1135             val = *(uint32_t *)(apic->trig_mode_reg + 28);
1136             break;
1137
1138         case IRR_OFFSET0:
1139             val = *(uint32_t *)(apic->int_req_reg);
1140             break;
1141         case IRR_OFFSET1:
1142             val = *(uint32_t *)(apic->int_req_reg + 4);
1143             break;
1144         case IRR_OFFSET2:
1145             val = *(uint32_t *)(apic->int_req_reg + 8);
1146             break;
1147         case IRR_OFFSET3:
1148             val = *(uint32_t *)(apic->int_req_reg + 12);
1149             break;
1150         case IRR_OFFSET4:
1151             val = *(uint32_t *)(apic->int_req_reg + 16);
1152             break;
1153         case IRR_OFFSET5:
1154             val = *(uint32_t *)(apic->int_req_reg + 20);
1155             break;
1156         case IRR_OFFSET6:
1157             val = *(uint32_t *)(apic->int_req_reg + 24);
1158             break;
1159         case IRR_OFFSET7:
1160             val = *(uint32_t *)(apic->int_req_reg + 28);
1161             break;
1162         case TMR_CUR_CNT_OFFSET:
1163             val = apic->tmr_cur_cnt;
1164             break;
1165
1166             // We are not going to implement these....
1167         case THERM_LOC_VEC_TBL_OFFSET:
1168             val = apic->therm_loc_vec_tbl.val;
1169             break;
1170         case PERF_CTR_LOC_VEC_TBL_OFFSET:
1171             val = apic->perf_ctr_loc_vec_tbl.val;
1172             break;
1173
1174  
1175
1176             // handled registers
1177         case INT_CMD_LO_OFFSET:    
1178             val = apic->int_cmd.lo;
1179             break;
1180         case INT_CMD_HI_OFFSET:
1181             val = apic->int_cmd.hi;
1182             break;
1183
1184             // handle current timer count
1185
1186             // Unhandled Registers
1187         case EXT_INT_LOC_VEC_TBL_OFFSET0:
1188             val = apic->ext_intr_vec_tbl[0].val;
1189             break;
1190         case EXT_INT_LOC_VEC_TBL_OFFSET1:
1191             val = apic->ext_intr_vec_tbl[1].val;
1192             break;
1193         case EXT_INT_LOC_VEC_TBL_OFFSET2:
1194             val = apic->ext_intr_vec_tbl[2].val;
1195             break;
1196         case EXT_INT_LOC_VEC_TBL_OFFSET3:
1197             val = apic->ext_intr_vec_tbl[3].val;
1198             break;
1199     
1200
1201         case EXT_APIC_FEATURE_OFFSET:
1202         case EXT_APIC_CMD_OFFSET:
1203         case SEOI_OFFSET:
1204
1205         default:
1206             PrintError("apic %u: core %u: Read from Unhandled APIC Register: %x (getting zero)\n", 
1207                        apic->lapic_id.val, core->vcpu_id, (uint32_t)reg_addr);
1208             return -1;
1209     }
1210
1211
1212     if (length == 1) {
1213         uint_t byte_addr = reg_addr & 0x3;
1214         uint8_t * val_ptr = (uint8_t *)dst;
1215     
1216         *val_ptr = *(((uint8_t *)&val) + byte_addr);
1217
1218     } else if ((length == 2) && 
1219                ((reg_addr & 0x3) != 0x3)) {
1220         uint_t byte_addr = reg_addr & 0x3;
1221         uint16_t * val_ptr = (uint16_t *)dst;
1222         *val_ptr = *(((uint16_t *)&val) + byte_addr);
1223
1224     } else if (length == 4) {
1225         uint32_t * val_ptr = (uint32_t *)dst;
1226         *val_ptr = val;
1227
1228     } else {
1229         PrintError("apic %u: core %u: Invalid apic read length (%d)\n", 
1230                    apic->lapic_id.val, core->vcpu_id, length);
1231         return -1;
1232     }
1233
1234     PrintDebug("apic %u: core %u: Read finished (val=%x)\n", 
1235                apic->lapic_id.val, core->vcpu_id, *(uint32_t *)dst);
1236
1237     return length;
1238 }
1239
1240
1241 /**
1242  *
1243  */
1244 static int apic_write(struct guest_info * core, addr_t guest_addr, void * src, uint_t length, void * priv_data) {
1245     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(priv_data);
1246     struct apic_state * apic = &(apic_dev->apics[core->vcpu_id]); 
1247     addr_t reg_addr  = guest_addr - apic->base_addr;
1248     struct apic_msr * msr = (struct apic_msr *)&(apic->base_addr_msr.value);
1249     uint32_t op_val = *(uint32_t *)src;
1250     addr_t flags = 0;
1251
1252     PrintDebug("apic %u: core %u: at %p and priv_data is at %p\n",
1253                apic->lapic_id.val, core->vcpu_id, apic, priv_data);
1254
1255     PrintDebug("apic %u: core %u: write to address space (%p) (val=%x)\n", 
1256                apic->lapic_id.val, core->vcpu_id, (void *)guest_addr, *(uint32_t *)src);
1257
1258     if (msr->apic_enable == 0) {
1259         PrintError("apic %u: core %u: Write to APIC address space with disabled APIC, apic msr=0x%llx\n",
1260                    apic->lapic_id.val, core->vcpu_id, apic->base_addr_msr.value);
1261         return -1;
1262     }
1263
1264
1265     if (length != 4) {
1266         PrintError("apic %u: core %u: Invalid apic write length (%d)\n", 
1267                    apic->lapic_id.val, length, core->vcpu_id);
1268         return -1;
1269     }
1270
1271     switch (reg_addr) {
1272         case REMOTE_READ_OFFSET:
1273         case APIC_VERSION_OFFSET:
1274         case APR_OFFSET:
1275         case IRR_OFFSET0:
1276         case IRR_OFFSET1:
1277         case IRR_OFFSET2:
1278         case IRR_OFFSET3:
1279         case IRR_OFFSET4:
1280         case IRR_OFFSET5:
1281         case IRR_OFFSET6:
1282         case IRR_OFFSET7:
1283         case ISR_OFFSET0:
1284         case ISR_OFFSET1:
1285         case ISR_OFFSET2:
1286         case ISR_OFFSET3:
1287         case ISR_OFFSET4:
1288         case ISR_OFFSET5:
1289         case ISR_OFFSET6:
1290         case ISR_OFFSET7:
1291         case TRIG_OFFSET0:
1292         case TRIG_OFFSET1:
1293         case TRIG_OFFSET2:
1294         case TRIG_OFFSET3:
1295         case TRIG_OFFSET4:
1296         case TRIG_OFFSET5:
1297         case TRIG_OFFSET6:
1298         case TRIG_OFFSET7:
1299         case PPR_OFFSET:
1300         case EXT_APIC_FEATURE_OFFSET:
1301
1302             PrintError("apic %u: core %u: Attempting to write to read only register %p (error)\n", 
1303                        apic->lapic_id.val, core->vcpu_id, (void *)reg_addr);
1304
1305             break;
1306
1307             // Data registers
1308         case APIC_ID_OFFSET:
1309             //V3_Print("apic %u: core %u: my id is being changed to %u\n", 
1310             //       apic->lapic_id.val, core->vcpu_id, op_val);
1311
1312             apic->lapic_id.val = op_val;
1313             break;
1314         case TPR_OFFSET:
1315             apic->task_prio.val = op_val;
1316             break;
1317         case LDR_OFFSET:
1318             PrintDebug("apic %u: core %u: setting log_dst.val to 0x%x\n",
1319                        apic->lapic_id.val, core->vcpu_id, op_val);
1320             flags = v3_lock_irqsave(apic_dev->state_lock);
1321             apic->log_dst.val = op_val;
1322             v3_unlock_irqrestore(apic_dev->state_lock, flags);
1323             break;
1324         case DFR_OFFSET:
1325             flags = v3_lock_irqsave(apic_dev->state_lock);
1326             apic->dst_fmt.val = op_val;
1327             v3_unlock_irqrestore(apic_dev->state_lock, flags);
1328             break;
1329         case SPURIOUS_INT_VEC_OFFSET:
1330             apic->spurious_int.val = op_val;
1331             break;
1332         case ESR_OFFSET:
1333             apic->err_status.val = op_val;
1334             break;
1335         case TMR_LOC_VEC_TBL_OFFSET:
1336             apic->tmr_vec_tbl.val = op_val;
1337             break;
1338         case THERM_LOC_VEC_TBL_OFFSET:
1339             apic->therm_loc_vec_tbl.val = op_val;
1340             break;
1341         case PERF_CTR_LOC_VEC_TBL_OFFSET:
1342             apic->perf_ctr_loc_vec_tbl.val = op_val;
1343             break;
1344         case LINT0_VEC_TBL_OFFSET:
1345             apic->lint0_vec_tbl.val = op_val;
1346             break;
1347         case LINT1_VEC_TBL_OFFSET:
1348             apic->lint1_vec_tbl.val = op_val;
1349             break;
1350         case ERR_VEC_TBL_OFFSET:
1351             apic->err_vec_tbl.val = op_val;
1352             break;
1353         case TMR_INIT_CNT_OFFSET:
1354             apic->tmr_init_cnt = op_val;
1355             apic->tmr_cur_cnt = op_val;
1356             break;
1357         case TMR_CUR_CNT_OFFSET:
1358             apic->tmr_cur_cnt = op_val;
1359             break;
1360         case TMR_DIV_CFG_OFFSET:
1361             PrintDebug("apic %u: core %u: setting tmr_div_cfg to 0x%x\n",
1362                        apic->lapic_id.val, core->vcpu_id, op_val);
1363             apic->tmr_div_cfg.val = op_val;
1364             break;
1365
1366
1367             // Enable mask (256 bits)
1368         case IER_OFFSET0:
1369             *(uint32_t *)(apic->int_en_reg) = op_val;
1370             break;
1371         case IER_OFFSET1:
1372             *(uint32_t *)(apic->int_en_reg + 4) = op_val;
1373             break;
1374         case IER_OFFSET2:
1375             *(uint32_t *)(apic->int_en_reg + 8) = op_val;
1376             break;
1377         case IER_OFFSET3:
1378             *(uint32_t *)(apic->int_en_reg + 12) = op_val;
1379             break;
1380         case IER_OFFSET4:
1381             *(uint32_t *)(apic->int_en_reg + 16) = op_val;
1382             break;
1383         case IER_OFFSET5:
1384             *(uint32_t *)(apic->int_en_reg + 20) = op_val;
1385             break;
1386         case IER_OFFSET6:
1387             *(uint32_t *)(apic->int_en_reg + 24) = op_val;
1388             break;
1389         case IER_OFFSET7:
1390             *(uint32_t *)(apic->int_en_reg + 28) = op_val;
1391             break;
1392
1393         case EXT_INT_LOC_VEC_TBL_OFFSET0:
1394             apic->ext_intr_vec_tbl[0].val = op_val;
1395             break;
1396         case EXT_INT_LOC_VEC_TBL_OFFSET1:
1397             apic->ext_intr_vec_tbl[1].val = op_val;
1398             break;
1399         case EXT_INT_LOC_VEC_TBL_OFFSET2:
1400             apic->ext_intr_vec_tbl[2].val = op_val;
1401             break;
1402         case EXT_INT_LOC_VEC_TBL_OFFSET3:
1403             apic->ext_intr_vec_tbl[3].val = op_val;
1404             break;
1405
1406
1407             // Action Registers
1408         case EOI_OFFSET:
1409             // do eoi 
1410             apic_do_eoi(apic);
1411             break;
1412
1413         case INT_CMD_LO_OFFSET: {
1414             // execute command 
1415
1416             struct int_cmd_reg tmp_icr;
1417
1418             apic->int_cmd.lo = op_val;
1419
1420             tmp_icr = apic->int_cmd;
1421
1422             //      V3_Print("apic %u: core %u: sending cmd 0x%llx to apic %u\n", 
1423             //       apic->lapic_id.val, core->vcpu_id,
1424             //       apic->int_cmd.val, apic->int_cmd.dst);
1425
1426             if (route_ipi(apic_dev, apic, &tmp_icr) == -1) { 
1427                 PrintError("IPI Routing failure\n");
1428                 return -1;
1429             }
1430
1431             break;
1432         }
1433         case INT_CMD_HI_OFFSET: {
1434             apic->int_cmd.hi = op_val;
1435             //V3_Print("apic %u: core %u: writing command high=0x%x\n", apic->lapic_id.val, core->vcpu_id,apic->int_cmd.hi);
1436             break;
1437         }
1438         // Unhandled Registers
1439         case EXT_APIC_CMD_OFFSET:
1440         case SEOI_OFFSET:
1441         default:
1442             PrintError("apic %u: core %u: Write to Unhandled APIC Register: %x (ignored)\n", 
1443                        apic->lapic_id.val, core->vcpu_id, (uint32_t)reg_addr);
1444
1445             return -1;
1446     }
1447
1448     PrintDebug("apic %u: core %u: Write finished\n", apic->lapic_id.val, core->vcpu_id);
1449
1450     return length;
1451
1452 }
1453
1454
1455
1456 /* Interrupt Controller Functions */
1457
1458
1459 static int apic_intr_pending(struct guest_info * core, void * private_data) {
1460     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(private_data);
1461     struct apic_state * apic = &(apic_dev->apics[core->vcpu_id]); 
1462     int req_irq = 0;    
1463     int svc_irq = 0;
1464
1465     // Activate all queued IRQ entries
1466     drain_irq_entries(apic);
1467
1468     // Check for newly activated entries
1469     req_irq = get_highest_irr(apic);
1470     svc_irq = get_highest_isr(apic);
1471
1472     //    PrintDebug("apic %u: core %u: req_irq=%d, svc_irq=%d\n",apic->lapic_id.val,info->vcpu_id,req_irq,svc_irq);
1473
1474     if ((req_irq >= 0) && 
1475         (req_irq > svc_irq)) {
1476         return 1;
1477     }
1478
1479     return 0;
1480 }
1481
1482
1483
1484 static int apic_get_intr_number(struct guest_info * core, void * private_data) {
1485     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(private_data);
1486     struct apic_state * apic = &(apic_dev->apics[core->vcpu_id]); 
1487     int req_irq = get_highest_irr(apic);
1488     int svc_irq = get_highest_isr(apic);
1489
1490     if (svc_irq == -1) {
1491         return req_irq;
1492     } else if (svc_irq < req_irq) {
1493         return req_irq;
1494     }
1495
1496     return -1;
1497 }
1498
1499
1500
1501 int v3_apic_send_ipi(struct v3_vm_info * vm, struct v3_gen_ipi * ipi, void * dev_data) {
1502     struct apic_dev_state * apic_dev = (struct apic_dev_state *)
1503         (((struct vm_device *)dev_data)->private_data);
1504     struct int_cmd_reg tmp_icr;
1505
1506     // zero out all the fields
1507     tmp_icr.val = 0;
1508
1509     tmp_icr.vec = ipi->vector;
1510     tmp_icr.del_mode = ipi->mode;
1511     tmp_icr.dst_mode = ipi->logical;
1512     tmp_icr.trig_mode = ipi->trigger_mode;
1513     tmp_icr.dst_shorthand = ipi->dst_shorthand;
1514     tmp_icr.dst = ipi->dst;
1515
1516
1517     return route_ipi(apic_dev, NULL, &tmp_icr);
1518 }
1519
1520
1521 int v3_apic_raise_intr(struct v3_vm_info * vm, uint32_t irq, uint32_t dst, void * dev_data) {
1522     struct apic_dev_state * apic_dev = (struct apic_dev_state *)
1523         (((struct vm_device*)dev_data)->private_data);
1524     struct apic_state * apic = &(apic_dev->apics[dst]); 
1525
1526     PrintDebug("apic %u core ?: raising interrupt IRQ %u (dst = %u).\n", apic->lapic_id.val, irq, dst); 
1527
1528     add_apic_irq_entry(apic, irq);
1529
1530 #ifdef V3_CONFIG_MULTITHREAD_OS   
1531     if ((V3_Get_CPU() != dst)) {
1532         v3_interrupt_cpu(vm, dst, 0);
1533     }
1534 #endif
1535
1536     return 0;
1537 }
1538
1539
1540
1541 static int apic_begin_irq(struct guest_info * core, void * private_data, int irq) {
1542     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(private_data);
1543     struct apic_state * apic = &(apic_dev->apics[core->vcpu_id]); 
1544     int major_offset = (irq & ~0x00000007) >> 3;
1545     int minor_offset = irq & 0x00000007;
1546     uint8_t *req_location = apic->int_req_reg + major_offset;
1547     uint8_t *svc_location = apic->int_svc_reg + major_offset;
1548     uint8_t flag = 0x01 << minor_offset;
1549
1550     if (*req_location & flag) {
1551         // we will only pay attention to a begin irq if we
1552         // know that we initiated it!
1553         *svc_location |= flag;
1554         *req_location &= ~flag;
1555     } else {
1556         // do nothing... 
1557         //PrintDebug("apic %u: core %u: begin irq for %d ignored since I don't own it\n",
1558         //         apic->lapic_id.val, core->vcpu_id, irq);
1559     }
1560
1561     return 0;
1562 }
1563
1564
1565 /* Timer Functions */
1566
1567 static void apic_inject_timer_intr(struct guest_info *core,
1568                                    void * priv_data) {
1569     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(priv_data);
1570     struct apic_state * apic = &(apic_dev->apics[core->vcpu_id]); 
1571     // raise irq
1572     PrintDebug("apic %u: core %u: Raising APIC Timer interrupt (periodic=%d) (icnt=%d)\n",
1573                apic->lapic_id.val, core->vcpu_id,
1574                apic->tmr_vec_tbl.tmr_mode, apic->tmr_init_cnt);
1575
1576     if (apic_intr_pending(core, priv_data)) {
1577         PrintDebug("apic %u: core %u: Overriding pending IRQ %d\n", 
1578                    apic->lapic_id.val, core->vcpu_id, 
1579                    apic_get_intr_number(core, priv_data));
1580     }
1581
1582     if (activate_internal_irq(apic, APIC_TMR_INT) == -1) {
1583         PrintError("apic %u: core %u: Could not raise Timer interrupt\n",
1584                    apic->lapic_id.val, core->vcpu_id);
1585     }
1586
1587     return;
1588 }
1589         
1590
1591
1592
1593 static void apic_update_time(struct guest_info * core, 
1594                              uint64_t cpu_cycles, uint64_t cpu_freq, 
1595                              void * priv_data) {
1596     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(priv_data);
1597     struct apic_state * apic = &(apic_dev->apics[core->vcpu_id]); 
1598
1599     // The 32 bit GCC runtime is a pile of shit
1600 #ifdef __V3_64BIT__
1601     uint64_t tmr_ticks = 0;
1602 #else 
1603     uint32_t tmr_ticks = 0;
1604 #endif
1605
1606     uint8_t tmr_div = *(uint8_t *)&(apic->tmr_div_cfg.val);
1607     uint_t shift_num = 0;
1608
1609
1610     // Check whether this is true:
1611     //   -> If the Init count is zero then the timer is disabled
1612     //      and doesn't just blitz interrupts to the CPU
1613     if ((apic->tmr_init_cnt == 0) || 
1614         ( (apic->tmr_vec_tbl.tmr_mode == APIC_TMR_ONESHOT) &&
1615           (apic->tmr_cur_cnt == 0))) {
1616         //PrintDebug("apic %u: core %u: APIC timer not yet initialized\n",apic->lapic_id.val,info->vcpu_id);
1617         return;
1618     }
1619
1620
1621     switch (tmr_div) {
1622         case APIC_TMR_DIV1:
1623             shift_num = 0;
1624             break;
1625         case APIC_TMR_DIV2:
1626             shift_num = 1;
1627             break;
1628         case APIC_TMR_DIV4:
1629             shift_num = 2;
1630             break;
1631         case APIC_TMR_DIV8:
1632             shift_num = 3;
1633             break;
1634         case APIC_TMR_DIV16:
1635             shift_num = 4;
1636             break;
1637         case APIC_TMR_DIV32:
1638             shift_num = 5;
1639             break;
1640         case APIC_TMR_DIV64:
1641             shift_num = 6;
1642             break;
1643         case APIC_TMR_DIV128:
1644             shift_num = 7;
1645             break;
1646         default:
1647             PrintError("apic %u: core %u: Invalid Timer Divider configuration\n",
1648                        apic->lapic_id.val, core->vcpu_id);
1649             return;
1650     }
1651
1652     tmr_ticks = cpu_cycles >> shift_num;
1653     //    PrintDebug("Timer Ticks: %p\n", (void *)tmr_ticks);
1654
1655     if (tmr_ticks < apic->tmr_cur_cnt) {
1656         apic->tmr_cur_cnt -= tmr_ticks;
1657 #ifdef V3_CONFIG_APIC_ENQUEUE_MISSED_TMR_IRQS
1658         if (apic->missed_ints && !apic_intr_pending(core, priv_data)) {
1659             PrintDebug("apic %u: core %u: Injecting queued APIC timer interrupt.\n",
1660                        apic->lapic_id.val, core->vcpu_id);
1661             apic_inject_timer_intr(core, priv_data);
1662             apic->missed_ints--;
1663         }
1664 #endif /* CONFIG_APIC_ENQUEUE_MISSED_TMR_IRQS */ 
1665     } else {
1666         tmr_ticks -= apic->tmr_cur_cnt;
1667         apic->tmr_cur_cnt = 0;
1668
1669         apic_inject_timer_intr(core, priv_data);
1670
1671         if (apic->tmr_vec_tbl.tmr_mode == APIC_TMR_PERIODIC) {
1672             int queued_ints = tmr_ticks / apic->tmr_init_cnt;
1673             tmr_ticks = tmr_ticks % apic->tmr_init_cnt;
1674             apic->tmr_cur_cnt = apic->tmr_init_cnt - tmr_ticks;
1675             apic->missed_ints += queued_ints;
1676         }
1677     }
1678
1679     return;
1680 }
1681
1682 static struct intr_ctrl_ops intr_ops = {
1683     .intr_pending = apic_intr_pending,
1684     .get_intr_number = apic_get_intr_number,
1685     .begin_irq = apic_begin_irq,
1686 };
1687
1688
1689 static struct v3_timer_ops timer_ops = {
1690     .update_timer = apic_update_time,
1691 };
1692
1693
1694
1695
1696 static int apic_free(struct apic_dev_state * apic_dev) {
1697     int i = 0;
1698     struct v3_vm_info * vm = NULL;
1699
1700     for (i = 0; i < apic_dev->num_apics; i++) {
1701         struct apic_state * apic = &(apic_dev->apics[i]);
1702         struct guest_info * core = apic->core;
1703         
1704         vm = core->vm_info;
1705
1706         v3_remove_intr_controller(core, apic->controller_handle);
1707
1708         if (apic->timer) {
1709             v3_remove_timer(core, apic->timer);
1710         }
1711
1712         // unhook memory
1713
1714     }
1715
1716     v3_unhook_msr(vm, BASE_ADDR_MSR);
1717
1718     V3_Free(apic_dev);
1719     return 0;
1720 }
1721
1722 #ifdef V3_CONFIG_CHECKPOINT
1723 static int apic_save(struct v3_chkpt_ctx * ctx, void * private_data) {
1724     struct apic_dev_state * apic_state = (struct apic_dev_state *)private_data;
1725     int i = 0;
1726
1727     V3_CHKPT_STD_SAVE(ctx, apic_state->num_apics);
1728
1729     //V3_CHKPT_STD_SAVE(ctx,apic_state->state_lock);
1730     for (i = 0; i < apic_state->num_apics; i++) {
1731
1732         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].base_addr);
1733         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].base_addr_msr);
1734         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].lapic_id);
1735         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].apic_ver);
1736         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].ext_apic_ctrl);
1737         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].local_vec_tbl);
1738         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].tmr_vec_tbl);
1739         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].tmr_div_cfg);
1740         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].lint0_vec_tbl);
1741         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].lint1_vec_tbl);
1742         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].perf_ctr_loc_vec_tbl);
1743         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].therm_loc_vec_tbl);
1744         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].err_vec_tbl);
1745         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].err_status);
1746         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].spurious_int);
1747         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].int_cmd);
1748         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].log_dst);
1749         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].dst_fmt);
1750         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].arb_prio);
1751         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].task_prio);
1752         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].proc_prio);
1753         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].ext_apic_feature);
1754         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].spec_eoi);
1755         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].tmr_cur_cnt);
1756         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].tmr_init_cnt);
1757         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].ext_intr_vec_tbl);
1758         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].rem_rd_data);
1759         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].ipi_state);
1760         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].int_req_reg);
1761         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].int_svc_reg);
1762         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].int_en_reg);
1763         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].trig_mode_reg);
1764         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].eoi);
1765
1766     }
1767
1768     return 0;
1769 }
1770
1771 static int apic_load(struct v3_chkpt_ctx * ctx, void * private_data) {
1772     struct apic_dev_state *apic_state = (struct apic_dev_state *)private_data;
1773     int i = 0;
1774
1775     V3_CHKPT_STD_LOAD(ctx,apic_state->num_apics);
1776
1777     for (i = 0; i < apic_state->num_apics; i++) {
1778         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].base_addr);
1779         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].base_addr_msr);
1780         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].lapic_id);
1781         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].apic_ver);
1782         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].ext_apic_ctrl);
1783         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].local_vec_tbl);
1784         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].tmr_vec_tbl);
1785         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].tmr_div_cfg);
1786         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].lint0_vec_tbl);
1787         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].lint1_vec_tbl);
1788         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].perf_ctr_loc_vec_tbl);
1789         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].therm_loc_vec_tbl);
1790         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].err_vec_tbl);
1791         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].err_status);
1792         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].spurious_int);
1793         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].int_cmd);
1794         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].log_dst);
1795         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].dst_fmt);
1796         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].arb_prio);
1797         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].task_prio);
1798         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].proc_prio);
1799         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].ext_apic_feature);
1800         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].spec_eoi);
1801         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].tmr_cur_cnt);
1802         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].tmr_init_cnt);
1803         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].ext_intr_vec_tbl);
1804         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].rem_rd_data);
1805         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].ipi_state);
1806         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].int_req_reg);
1807         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].int_svc_reg);
1808         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].int_en_reg);
1809         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].trig_mode_reg);
1810         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].eoi);
1811     }
1812
1813
1814     return 0;
1815 }
1816
1817 #endif
1818
1819 static struct v3_device_ops dev_ops = {
1820     .free = (int (*)(void *))apic_free,
1821 #ifdef V3_CONFIG_CHECKPOINT
1822     .save = apic_save,
1823     .load = apic_load
1824 #endif
1825 };
1826
1827
1828
1829 static int apic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
1830     char * dev_id = v3_cfg_val(cfg, "ID");
1831     struct apic_dev_state * apic_dev = NULL;
1832     int i = 0;
1833
1834     PrintDebug("apic: creating an APIC for each core\n");
1835
1836     apic_dev = (struct apic_dev_state *)V3_Malloc(sizeof(struct apic_dev_state) + 
1837                                                   sizeof(struct apic_state) * vm->num_cores);
1838
1839     apic_dev->num_apics = vm->num_cores;
1840     v3_lock_init(&(apic_dev->state_lock));
1841
1842     struct vm_device * dev = v3_add_device(vm, dev_id, &dev_ops, apic_dev);
1843
1844     if (dev == NULL) {
1845         PrintError("apic: Could not attach device %s\n", dev_id);
1846         V3_Free(apic_dev);
1847         return -1;
1848     }
1849
1850     
1851     for (i = 0; i < vm->num_cores; i++) {
1852         struct apic_state * apic = &(apic_dev->apics[i]);
1853         struct guest_info * core = &(vm->cores[i]);
1854
1855         apic->core = core;
1856
1857         init_apic_state(apic, i);
1858
1859         apic->controller_handle = v3_register_intr_controller(core, &intr_ops, apic_dev);
1860
1861         apic->timer = v3_add_timer(core, &timer_ops, apic_dev);
1862
1863         if (apic->timer == NULL) {
1864             PrintError("APIC: Failed to attach timer to core %d\n", i);
1865             v3_remove_device(dev);
1866             return -1;
1867         }
1868
1869         v3_hook_full_mem(vm, core->vcpu_id, apic->base_addr, apic->base_addr + PAGE_SIZE_4KB, apic_read, apic_write, apic_dev);
1870
1871         PrintDebug("apic %u: (setup device): done, my id is %u\n", i, apic->lapic_id.val);
1872     }
1873
1874 #ifdef V3_CONFIG_DEBUG_APIC
1875     for (i = 0; i < vm->num_cores; i++) {
1876         struct apic_state * apic = &(apic_dev->apics[i]);
1877         PrintDebug("apic: sanity check: apic %u (at %p) has id %u and msr value %llx and core at %p\n",
1878                    i, apic, apic->lapic_id.val, apic->base_addr_msr.value,apic->core);
1879     }
1880 #endif
1881
1882
1883     PrintDebug("apic: priv_data is at %p\n", apic_dev);
1884
1885     v3_hook_msr(vm, BASE_ADDR_MSR, read_apic_msr, write_apic_msr, apic_dev);
1886
1887     return 0;
1888 }
1889
1890
1891
1892 device_register("LAPIC", apic_init)