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.


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