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.


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