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.


Removed spurious print
[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
1437             break;
1438         }
1439         // Unhandled Registers
1440         case EXT_APIC_CMD_OFFSET:
1441         case SEOI_OFFSET:
1442         default:
1443             PrintError("apic %u: core %u: Write to Unhandled APIC Register: %x (ignored)\n", 
1444                        apic->lapic_id.val, core->vcpu_id, (uint32_t)reg_addr);
1445
1446             return -1;
1447     }
1448
1449     PrintDebug("apic %u: core %u: Write finished\n", apic->lapic_id.val, core->vcpu_id);
1450
1451     return length;
1452
1453 }
1454
1455
1456
1457 /* Interrupt Controller Functions */
1458
1459
1460 static int apic_intr_pending(struct guest_info * core, void * private_data) {
1461     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(private_data);
1462     struct apic_state * apic = &(apic_dev->apics[core->vcpu_id]); 
1463     int req_irq = 0;    
1464     int svc_irq = 0;
1465
1466     // Activate all queued IRQ entries
1467     drain_irq_entries(apic);
1468
1469     // Check for newly activated entries
1470     req_irq = get_highest_irr(apic);
1471     svc_irq = get_highest_isr(apic);
1472
1473     //    PrintDebug("apic %u: core %u: req_irq=%d, svc_irq=%d\n",apic->lapic_id.val,info->vcpu_id,req_irq,svc_irq);
1474
1475     if ((req_irq >= 0) && 
1476         (req_irq > svc_irq)) {
1477         return 1;
1478     }
1479
1480     return 0;
1481 }
1482
1483
1484
1485 static int apic_get_intr_number(struct guest_info * core, void * private_data) {
1486     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(private_data);
1487     struct apic_state * apic = &(apic_dev->apics[core->vcpu_id]); 
1488     int req_irq = get_highest_irr(apic);
1489     int svc_irq = get_highest_isr(apic);
1490
1491     if (svc_irq == -1) {
1492         return req_irq;
1493     } else if (svc_irq < req_irq) {
1494         return req_irq;
1495     }
1496
1497     return -1;
1498 }
1499
1500
1501
1502 int v3_apic_send_ipi(struct v3_vm_info * vm, struct v3_gen_ipi * ipi, void * dev_data) {
1503     struct apic_dev_state * apic_dev = (struct apic_dev_state *)
1504         (((struct vm_device *)dev_data)->private_data);
1505     struct int_cmd_reg tmp_icr;
1506
1507     // zero out all the fields
1508     tmp_icr.val = 0;
1509
1510     tmp_icr.vec = ipi->vector;
1511     tmp_icr.del_mode = ipi->mode;
1512     tmp_icr.dst_mode = ipi->logical;
1513     tmp_icr.trig_mode = ipi->trigger_mode;
1514     tmp_icr.dst_shorthand = ipi->dst_shorthand;
1515     tmp_icr.dst = ipi->dst;
1516
1517
1518     return route_ipi(apic_dev, NULL, &tmp_icr);
1519 }
1520
1521
1522 int v3_apic_raise_intr(struct v3_vm_info * vm, uint32_t irq, uint32_t dst, void * dev_data) {
1523     struct apic_dev_state * apic_dev = (struct apic_dev_state *)
1524         (((struct vm_device*)dev_data)->private_data);
1525     struct apic_state * apic = &(apic_dev->apics[dst]); 
1526
1527     PrintDebug("apic %u core ?: raising interrupt IRQ %u (dst = %u).\n", apic->lapic_id.val, irq, dst); 
1528
1529     add_apic_irq_entry(apic, irq);
1530
1531 #ifdef V3_CONFIG_MULTITHREAD_OS   
1532     if ((V3_Get_CPU() != dst)) {
1533         v3_interrupt_cpu(vm, dst, 0);
1534     }
1535 #endif
1536
1537     return 0;
1538 }
1539
1540
1541
1542 static int apic_begin_irq(struct guest_info * core, void * private_data, int irq) {
1543     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(private_data);
1544     struct apic_state * apic = &(apic_dev->apics[core->vcpu_id]); 
1545     int major_offset = (irq & ~0x00000007) >> 3;
1546     int minor_offset = irq & 0x00000007;
1547     uint8_t *req_location = apic->int_req_reg + major_offset;
1548     uint8_t *svc_location = apic->int_svc_reg + major_offset;
1549     uint8_t flag = 0x01 << minor_offset;
1550
1551     if (*req_location & flag) {
1552         // we will only pay attention to a begin irq if we
1553         // know that we initiated it!
1554         *svc_location |= flag;
1555         *req_location &= ~flag;
1556     } else {
1557         // do nothing... 
1558         //PrintDebug("apic %u: core %u: begin irq for %d ignored since I don't own it\n",
1559         //         apic->lapic_id.val, core->vcpu_id, irq);
1560     }
1561
1562     return 0;
1563 }
1564
1565
1566 /* Timer Functions */
1567
1568 static void apic_inject_timer_intr(struct guest_info *core,
1569                                    void * priv_data) {
1570     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(priv_data);
1571     struct apic_state * apic = &(apic_dev->apics[core->vcpu_id]); 
1572     // raise irq
1573     PrintDebug("apic %u: core %u: Raising APIC Timer interrupt (periodic=%d) (icnt=%d)\n",
1574                apic->lapic_id.val, core->vcpu_id,
1575                apic->tmr_vec_tbl.tmr_mode, apic->tmr_init_cnt);
1576
1577     if (apic_intr_pending(core, priv_data)) {
1578         PrintDebug("apic %u: core %u: Overriding pending IRQ %d\n", 
1579                    apic->lapic_id.val, core->vcpu_id, 
1580                    apic_get_intr_number(core, priv_data));
1581     }
1582
1583     if (activate_internal_irq(apic, APIC_TMR_INT) == -1) {
1584         PrintError("apic %u: core %u: Could not raise Timer interrupt\n",
1585                    apic->lapic_id.val, core->vcpu_id);
1586     }
1587
1588     return;
1589 }
1590         
1591
1592
1593
1594 static void apic_update_time(struct guest_info * core, 
1595                              uint64_t cpu_cycles, uint64_t cpu_freq, 
1596                              void * priv_data) {
1597     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(priv_data);
1598     struct apic_state * apic = &(apic_dev->apics[core->vcpu_id]); 
1599
1600     // The 32 bit GCC runtime is a pile of shit
1601 #ifdef __V3_64BIT__
1602     uint64_t tmr_ticks = 0;
1603 #else 
1604     uint32_t tmr_ticks = 0;
1605 #endif
1606
1607     uint8_t tmr_div = *(uint8_t *)&(apic->tmr_div_cfg.val);
1608     uint_t shift_num = 0;
1609
1610
1611     // Check whether this is true:
1612     //   -> If the Init count is zero then the timer is disabled
1613     //      and doesn't just blitz interrupts to the CPU
1614     if ((apic->tmr_init_cnt == 0) || 
1615         ( (apic->tmr_vec_tbl.tmr_mode == APIC_TMR_ONESHOT) &&
1616           (apic->tmr_cur_cnt == 0))) {
1617         //PrintDebug("apic %u: core %u: APIC timer not yet initialized\n",apic->lapic_id.val,info->vcpu_id);
1618         return;
1619     }
1620
1621
1622     switch (tmr_div) {
1623         case APIC_TMR_DIV1:
1624             shift_num = 0;
1625             break;
1626         case APIC_TMR_DIV2:
1627             shift_num = 1;
1628             break;
1629         case APIC_TMR_DIV4:
1630             shift_num = 2;
1631             break;
1632         case APIC_TMR_DIV8:
1633             shift_num = 3;
1634             break;
1635         case APIC_TMR_DIV16:
1636             shift_num = 4;
1637             break;
1638         case APIC_TMR_DIV32:
1639             shift_num = 5;
1640             break;
1641         case APIC_TMR_DIV64:
1642             shift_num = 6;
1643             break;
1644         case APIC_TMR_DIV128:
1645             shift_num = 7;
1646             break;
1647         default:
1648             PrintError("apic %u: core %u: Invalid Timer Divider configuration\n",
1649                        apic->lapic_id.val, core->vcpu_id);
1650             return;
1651     }
1652
1653     tmr_ticks = cpu_cycles >> shift_num;
1654     //    PrintDebug("Timer Ticks: %p\n", (void *)tmr_ticks);
1655
1656     if (tmr_ticks < apic->tmr_cur_cnt) {
1657         apic->tmr_cur_cnt -= tmr_ticks;
1658 #ifdef V3_CONFIG_APIC_ENQUEUE_MISSED_TMR_IRQS
1659         if (apic->missed_ints && !apic_intr_pending(core, priv_data)) {
1660             PrintDebug("apic %u: core %u: Injecting queued APIC timer interrupt.\n",
1661                        apic->lapic_id.val, core->vcpu_id);
1662             apic_inject_timer_intr(core, priv_data);
1663             apic->missed_ints--;
1664         }
1665 #endif /* CONFIG_APIC_ENQUEUE_MISSED_TMR_IRQS */ 
1666     } else {
1667         tmr_ticks -= apic->tmr_cur_cnt;
1668         apic->tmr_cur_cnt = 0;
1669
1670         apic_inject_timer_intr(core, priv_data);
1671
1672         if (apic->tmr_vec_tbl.tmr_mode == APIC_TMR_PERIODIC) {
1673             int queued_ints = tmr_ticks / apic->tmr_init_cnt;
1674             tmr_ticks = tmr_ticks % apic->tmr_init_cnt;
1675             apic->tmr_cur_cnt = apic->tmr_init_cnt - tmr_ticks;
1676             apic->missed_ints += queued_ints;
1677         }
1678     }
1679
1680     return;
1681 }
1682
1683 static struct intr_ctrl_ops intr_ops = {
1684     .intr_pending = apic_intr_pending,
1685     .get_intr_number = apic_get_intr_number,
1686     .begin_irq = apic_begin_irq,
1687 };
1688
1689
1690 static struct v3_timer_ops timer_ops = {
1691     .update_timer = apic_update_time,
1692 };
1693
1694
1695
1696
1697 static int apic_free(struct apic_dev_state * apic_dev) {
1698     int i = 0;
1699     struct v3_vm_info * vm = NULL;
1700
1701     for (i = 0; i < apic_dev->num_apics; i++) {
1702         struct apic_state * apic = &(apic_dev->apics[i]);
1703         struct guest_info * core = apic->core;
1704         
1705         vm = core->vm_info;
1706
1707         v3_remove_intr_controller(core, apic->controller_handle);
1708
1709         if (apic->timer) {
1710             v3_remove_timer(core, apic->timer);
1711         }
1712
1713         // unhook memory
1714
1715     }
1716
1717     v3_unhook_msr(vm, BASE_ADDR_MSR);
1718
1719     V3_Free(apic_dev);
1720     return 0;
1721 }
1722
1723 #ifdef V3_CONFIG_CHECKPOINT
1724 static int apic_save(struct v3_chkpt_ctx * ctx, void * private_data) {
1725     struct apic_dev_state * apic_state = (struct apic_dev_state *)private_data;
1726     int i = 0;
1727
1728     V3_CHKPT_STD_SAVE(ctx, apic_state->num_apics);
1729
1730     //V3_CHKPT_STD_SAVE(ctx,apic_state->state_lock);
1731     for (i = 0; i < apic_state->num_apics; i++) {
1732
1733         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].base_addr);
1734         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].base_addr_msr);
1735         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].lapic_id);
1736         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].apic_ver);
1737         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].ext_apic_ctrl);
1738         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].local_vec_tbl);
1739         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].tmr_vec_tbl);
1740         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].tmr_div_cfg);
1741         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].lint0_vec_tbl);
1742         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].lint1_vec_tbl);
1743         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].perf_ctr_loc_vec_tbl);
1744         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].therm_loc_vec_tbl);
1745         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].err_vec_tbl);
1746         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].err_status);
1747         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].spurious_int);
1748         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].int_cmd);
1749         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].log_dst);
1750         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].dst_fmt);
1751         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].arb_prio);
1752         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].task_prio);
1753         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].proc_prio);
1754         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].ext_apic_feature);
1755         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].spec_eoi);
1756         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].tmr_cur_cnt);
1757         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].tmr_init_cnt);
1758         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].ext_intr_vec_tbl);
1759         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].rem_rd_data);
1760         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].ipi_state);
1761         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].int_req_reg);
1762         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].int_svc_reg);
1763         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].int_en_reg);
1764         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].trig_mode_reg);
1765         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].eoi);
1766
1767     }
1768
1769     return 0;
1770 }
1771
1772 static int apic_load(struct v3_chkpt_ctx * ctx, void * private_data) {
1773     struct apic_dev_state *apic_state = (struct apic_dev_state *)private_data;
1774     int i = 0;
1775
1776     V3_CHKPT_STD_LOAD(ctx,apic_state->num_apics);
1777
1778     for (i = 0; i < apic_state->num_apics; i++) {
1779         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].base_addr);
1780         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].base_addr_msr);
1781         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].lapic_id);
1782         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].apic_ver);
1783         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].ext_apic_ctrl);
1784         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].local_vec_tbl);
1785         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].tmr_vec_tbl);
1786         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].tmr_div_cfg);
1787         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].lint0_vec_tbl);
1788         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].lint1_vec_tbl);
1789         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].perf_ctr_loc_vec_tbl);
1790         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].therm_loc_vec_tbl);
1791         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].err_vec_tbl);
1792         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].err_status);
1793         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].spurious_int);
1794         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].int_cmd);
1795         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].log_dst);
1796         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].dst_fmt);
1797         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].arb_prio);
1798         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].task_prio);
1799         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].proc_prio);
1800         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].ext_apic_feature);
1801         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].spec_eoi);
1802         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].tmr_cur_cnt);
1803         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].tmr_init_cnt);
1804         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].ext_intr_vec_tbl);
1805         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].rem_rd_data);
1806         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].ipi_state);
1807         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].int_req_reg);
1808         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].int_svc_reg);
1809         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].int_en_reg);
1810         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].trig_mode_reg);
1811         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].eoi);
1812     }
1813
1814
1815     return 0;
1816 }
1817
1818 #endif
1819
1820 static struct v3_device_ops dev_ops = {
1821     .free = (int (*)(void *))apic_free,
1822 #ifdef V3_CONFIG_CHECKPOINT
1823     .save = apic_save,
1824     .load = apic_load
1825 #endif
1826 };
1827
1828
1829
1830 static int apic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
1831     char * dev_id = v3_cfg_val(cfg, "ID");
1832     struct apic_dev_state * apic_dev = NULL;
1833     int i = 0;
1834
1835     PrintDebug("apic: creating an APIC for each core\n");
1836
1837     apic_dev = (struct apic_dev_state *)V3_Malloc(sizeof(struct apic_dev_state) + 
1838                                                   sizeof(struct apic_state) * vm->num_cores);
1839
1840     apic_dev->num_apics = vm->num_cores;
1841     v3_lock_init(&(apic_dev->state_lock));
1842
1843     struct vm_device * dev = v3_add_device(vm, dev_id, &dev_ops, apic_dev);
1844
1845     if (dev == NULL) {
1846         PrintError("apic: Could not attach device %s\n", dev_id);
1847         V3_Free(apic_dev);
1848         return -1;
1849     }
1850
1851     
1852     for (i = 0; i < vm->num_cores; i++) {
1853         struct apic_state * apic = &(apic_dev->apics[i]);
1854         struct guest_info * core = &(vm->cores[i]);
1855
1856         apic->core = core;
1857
1858         init_apic_state(apic, i);
1859
1860         apic->controller_handle = v3_register_intr_controller(core, &intr_ops, apic_dev);
1861
1862         apic->timer = v3_add_timer(core, &timer_ops, apic_dev);
1863
1864         if (apic->timer == NULL) {
1865             PrintError("APIC: Failed to attach timer to core %d\n", i);
1866             v3_remove_device(dev);
1867             return -1;
1868         }
1869
1870         v3_hook_full_mem(vm, core->vcpu_id, apic->base_addr, apic->base_addr + PAGE_SIZE_4KB, apic_read, apic_write, apic_dev);
1871
1872         PrintDebug("apic %u: (setup device): done, my id is %u\n", i, apic->lapic_id.val);
1873     }
1874
1875 #ifdef V3_CONFIG_DEBUG_APIC
1876     for (i = 0; i < vm->num_cores; i++) {
1877         struct apic_state * apic = &(apic_dev->apics[i]);
1878         PrintDebug("apic: sanity check: apic %u (at %p) has id %u and msr value %llx and core at %p\n",
1879                    i, apic, apic->lapic_id.val, apic->base_addr_msr.value,apic->core);
1880     }
1881 #endif
1882
1883
1884     PrintDebug("apic: priv_data is at %p\n", apic_dev);
1885
1886     v3_hook_msr(vm, BASE_ADDR_MSR, read_apic_msr, write_apic_msr, apic_dev);
1887
1888     return 0;
1889 }
1890
1891
1892
1893 device_register("LAPIC", apic_init)