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.


reworked PCI bus implmentation -- moved to mask based implementation -- added capabil...
[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     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             if (dst_apic != src_apic) { 
768                 PrintDebug(" non-local core with new interrupt, forcing it to exit now\n"); 
769                 v3_interrupt_cpu(dst_core->vm_info, dst_core->pcpu_id, 0);
770             }
771
772             break;
773         }
774         case IPI_INIT: { 
775
776             PrintDebug(" INIT delivery to core %u\n", dst_core->vcpu_id);
777
778             // TODO: any APIC reset on dest core (shouldn't be needed, but not sure...)
779
780             // Sanity check
781             if (dst_apic->ipi_state != INIT_ST) { 
782                 PrintError(" Warning: core %u is not in INIT state (mode = %d), ignored (assuming this is the deassert)\n",
783                            dst_core->vcpu_id, dst_apic->ipi_state);
784                 // Only a warning, since INIT INIT SIPI is common
785                 break;
786             }
787
788             // We transition the target core to SIPI state
789             dst_apic->ipi_state = SIPI;  // note: locking should not be needed here
790
791             // That should be it since the target core should be
792             // waiting in host on this transition
793             // either it's on another core or on a different preemptive thread
794             // in both cases, it will quickly notice this transition 
795             // in particular, we should not need to force an exit here
796
797             PrintDebug(" INIT delivery done\n");
798
799             break;                                                      
800         }
801         case IPI_SIPI: { 
802
803             // Sanity check
804             if (dst_apic->ipi_state != SIPI) { 
805                 PrintError(" core %u is not in SIPI state (mode = %d), ignored!\n",
806                            dst_core->vcpu_id, dst_apic->ipi_state);
807                 break;
808             }
809
810             v3_reset_vm_core(dst_core, ipi->vector);
811
812             PrintDebug(" SIPI delivery (0x%x -> 0x%x:0x0) to core %u\n",
813                        ipi->vector, dst_core->segments.cs.selector, dst_core->vcpu_id);
814             // Maybe need to adjust the APIC?
815             
816             // We transition the target core to SIPI state
817             dst_core->core_run_state = CORE_RUNNING;  // note: locking should not be needed here
818             dst_apic->ipi_state = STARTED;
819             
820             // As with INIT, we should not need to do anything else
821             
822             PrintDebug(" SIPI delivery done\n");
823             
824             break;                                                      
825         }
826
827         case IPI_EXTINT: // EXTINT
828             /* Two possible things to do here: 
829              * 1. Ignore the IPI and assume the 8259a (PIC) will handle it
830              * 2. Add 32 to the vector and inject it...
831              * We probably just want to do 1 here, and assume the raise_irq() will hit the 8259a.
832              */
833             return 0;
834
835         case IPI_SMI: 
836         case IPI_RES1: // reserved                                              
837         case IPI_NMI:
838         default:
839             PrintError("IPI %d delivery is unsupported\n", ipi->mode); 
840             return -1;
841     }
842     
843     return 0;
844     
845 }
846
847 static struct apic_state * find_physical_apic(struct apic_dev_state * apic_dev, uint32_t dst_idx) {
848     struct apic_state * dst_apic = NULL;
849     addr_t flags;
850     int i;
851
852     flags = v3_lock_irqsave(apic_dev->state_lock);
853
854     if ( (dst_idx > 0) && (dst_idx < apic_dev->num_apics) ) { 
855         // see if it simply is the core id
856         if (apic_dev->apics[dst_idx].lapic_id.apic_id == dst_idx) { 
857              dst_apic = &(apic_dev->apics[dst_idx]);
858         }
859     }
860
861     for (i = 0; i < apic_dev->num_apics; i++) { 
862         if (apic_dev->apics[i].lapic_id.apic_id == dst_idx) { 
863             dst_apic =  &(apic_dev->apics[i]);
864         }
865     }
866
867     v3_unlock_irqrestore(apic_dev->state_lock, flags);
868
869     return dst_apic;
870
871 }
872
873
874 static int route_ipi(struct apic_dev_state * apic_dev,
875                      struct apic_state * src_apic, 
876                      struct v3_gen_ipi * ipi) {
877     struct apic_state * dest_apic = NULL;
878
879
880     PrintDebug("apic: IPI %s %u from apic %p to %s %s %u\n",
881                deliverymode_str[ipi->mode], 
882                ipi->vector, 
883                src_apic,               
884                (ipi->logical == 0) ? "(physical)" : "(logical)", 
885                shorthand_str[ipi->dst_shorthand], 
886                ipi->dst);
887
888
889     switch (ipi->dst_shorthand) {
890
891         case APIC_SHORTHAND_NONE:  // no shorthand
892             if (ipi->logical == APIC_DEST_PHYSICAL) { 
893
894                 dest_apic = find_physical_apic(apic_dev, ipi->dst);
895                 
896                 if (dest_apic == NULL) { 
897                     PrintError("apic: Attempted send to unregistered apic id=%u\n", ipi->dst);
898                     return -1;
899                 }
900
901                 if (deliver_ipi(src_apic, dest_apic, ipi) == -1) {
902                     PrintError("apic: Could not deliver IPI\n");
903                     return -1;
904                 }
905
906
907                 PrintDebug("apic: done\n");
908
909             } else if (ipi->logical == APIC_DEST_LOGICAL) {
910                 
911                 if (ipi->mode != IPI_LOWEST_PRIO) { 
912                     int i;
913                     uint8_t mda = ipi->dst;
914
915                     // logical, but not lowest priority
916                     // we immediately trigger
917                     // fixed, smi, reserved, nmi, init, sipi, etc
918
919                     
920                     for (i = 0; i < apic_dev->num_apics; i++) { 
921                         int del_flag = 0;
922                         
923                         dest_apic = &(apic_dev->apics[i]);
924                         
925                         del_flag = should_deliver_ipi(apic_dev, dest_apic->core, dest_apic, mda);
926                         
927                         if (del_flag == -1) {
928
929                             PrintError("apic: Error checking delivery mode\n");
930                             return -1;
931                         } else if (del_flag == 1) {
932
933                             if (deliver_ipi(src_apic, dest_apic, ipi) == -1) {
934                                 PrintError("apic: Error: Could not deliver IPI\n");
935                                 return -1;
936                             }
937                         }
938                     }
939                 } else {  // APIC_LOWEST_DELIVERY
940                     struct apic_state * cur_best_apic = NULL;
941                     uint8_t mda = ipi->dst;
942                     int i;
943
944                     // logical, lowest priority
945
946                     for (i = 0; i < apic_dev->num_apics; i++) { 
947                         int del_flag = 0;
948
949                         dest_apic = &(apic_dev->apics[i]);
950                         
951                         del_flag = should_deliver_ipi(apic_dev, dest_apic->core, dest_apic, mda);
952                         
953                         if (del_flag == -1) {
954                             PrintError("apic: Error checking delivery mode\n");
955
956                             return -1;
957                         } else if (del_flag == 1) {
958                             // update priority for lowest priority scan
959                             addr_t flags = 0;
960
961                             flags = v3_lock_irqsave(apic_dev->state_lock);
962
963                             if (cur_best_apic == 0) {
964                                 cur_best_apic = dest_apic;  
965                             } else if (dest_apic->task_prio.val < cur_best_apic->task_prio.val) {
966                                 cur_best_apic = dest_apic;
967                             } 
968
969                             v3_unlock_irqrestore(apic_dev->state_lock, flags);
970
971                         }
972                     }
973
974                     // now we will deliver to the best one if it exists
975                     if (!cur_best_apic) { 
976                         PrintDebug("apic: lowest priority deliver, but no destinations!\n");
977                     } else {
978                         if (deliver_ipi(src_apic, cur_best_apic, ipi) == -1) {
979                             PrintError("apic: Error: Could not deliver IPI\n");
980                             return -1;
981                         }
982                         //V3_Print("apic: logical, lowest priority delivery to apic %u\n",cur_best_apic->lapic_id.val);
983                     }
984                 }
985             }
986
987             break;
988             
989         case APIC_SHORTHAND_SELF:  // self
990
991             if (src_apic == NULL) {    /* this is not an apic, but it's trying to send to itself??? */
992                 PrintError("apic: Sending IPI to self from generic IPI sender\n");
993                 break;
994             }
995
996
997
998             if (ipi->logical == APIC_DEST_PHYSICAL)  {  /* physical delivery */
999                 if (deliver_ipi(src_apic, src_apic, ipi) == -1) {
1000                     PrintError("apic: Could not deliver IPI to self (physical)\n");
1001                     return -1;
1002                 }
1003             } else if (ipi->logical == APIC_DEST_LOGICAL) {  /* logical delivery */
1004                 PrintError("apic: use of logical delivery in self (untested)\n");
1005
1006                 if (deliver_ipi(src_apic, src_apic, ipi) == -1) {
1007                     PrintError("apic: Could not deliver IPI to self (logical)\n");
1008                     return -1;
1009                 }
1010             }
1011
1012             break;
1013             
1014         case APIC_SHORTHAND_ALL: 
1015         case APIC_SHORTHAND_ALL_BUT_ME: { /* all and all-but-me */
1016             /* assuming that logical verus physical doesn't matter
1017                although it is odd that both are used */
1018             int i;
1019
1020             for (i = 0; i < apic_dev->num_apics; i++) { 
1021                 dest_apic = &(apic_dev->apics[i]);
1022                 
1023                 if ((dest_apic != src_apic) || (ipi->dst_shorthand == APIC_SHORTHAND_ALL)) { 
1024                     if (deliver_ipi(src_apic, dest_apic, ipi) == -1) {
1025                         PrintError("apic: Error: Could not deliver IPI\n");
1026                         return -1;
1027                     }
1028                 }
1029             }
1030
1031             break;
1032         }
1033         default:
1034             PrintError("apic: Error routing IPI, invalid Mode (%d)\n", ipi->dst_shorthand);
1035             return -1;
1036     }
1037  
1038     return 0;
1039 }
1040
1041
1042 // External function, expected to acquire lock on apic
1043 static int apic_read(struct guest_info * core, addr_t guest_addr, void * dst, uint_t length, void * priv_data) {
1044     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(priv_data);
1045     struct apic_state * apic = &(apic_dev->apics[core->vcpu_id]);
1046     addr_t reg_addr  = guest_addr - apic->base_addr;
1047     struct apic_msr * msr = (struct apic_msr *)&(apic->base_addr_msr.value);
1048     uint32_t val = 0;
1049
1050
1051     PrintDebug("apic %u: core %u: at %p: Read apic address space (%p)\n",
1052                apic->lapic_id.val, core->vcpu_id, apic, (void *)guest_addr);
1053
1054     if (msr->apic_enable == 0) {
1055         PrintError("apic %u: core %u: Read from APIC address space with disabled APIC, apic msr=0x%llx\n",
1056                    apic->lapic_id.val, core->vcpu_id, apic->base_addr_msr.value);
1057         return -1;
1058     }
1059
1060
1061     /* Because "May not be supported" doesn't matter to Linux developers... */
1062     /*   if (length != 4) { */
1063     /*     PrintError("Invalid apic read length (%d)\n", length); */
1064     /*     return -1; */
1065     /*   } */
1066
1067     switch (reg_addr & ~0x3) {
1068         case EOI_OFFSET:
1069             // Well, only an idiot would read from a architectural write only register
1070             // Oh, Hello Linux.
1071             //    PrintError("Attempting to read from write only register\n");
1072             //    return -1;
1073             break;
1074
1075             // data registers
1076         case APIC_ID_OFFSET:
1077             val = apic->lapic_id.val;
1078             break;
1079         case APIC_VERSION_OFFSET:
1080             val = apic->apic_ver.val;
1081             break;
1082         case TPR_OFFSET:
1083             val = apic->task_prio.val;
1084             break;
1085         case APR_OFFSET:
1086             val = apic->arb_prio.val;
1087             break;
1088         case PPR_OFFSET:
1089             val = apic->proc_prio.val;
1090             break;
1091         case REMOTE_READ_OFFSET:
1092             val = apic->rem_rd_data;
1093             break;
1094         case LDR_OFFSET:
1095             val = apic->log_dst.val;
1096             break;
1097         case DFR_OFFSET:
1098             val = apic->dst_fmt.val;
1099             break;
1100         case SPURIOUS_INT_VEC_OFFSET:
1101             val = apic->spurious_int.val;
1102             break;
1103         case ESR_OFFSET:
1104             val = apic->err_status.val;
1105             break;
1106         case TMR_LOC_VEC_TBL_OFFSET:
1107             val = apic->tmr_vec_tbl.val;
1108             break;
1109         case LINT0_VEC_TBL_OFFSET:
1110             val = apic->lint0_vec_tbl.val;
1111             break;
1112         case LINT1_VEC_TBL_OFFSET:
1113             val = apic->lint1_vec_tbl.val;
1114             break;
1115         case ERR_VEC_TBL_OFFSET:
1116             val = apic->err_vec_tbl.val;
1117             break;
1118         case TMR_INIT_CNT_OFFSET:
1119             val = apic->tmr_init_cnt;
1120             break;
1121         case TMR_DIV_CFG_OFFSET:
1122             val = apic->tmr_div_cfg.val;
1123             break;
1124
1125         case IER_OFFSET0:
1126             val = *(uint32_t *)(apic->int_en_reg);
1127             break;
1128         case IER_OFFSET1:
1129             val = *(uint32_t *)(apic->int_en_reg + 4);
1130             break;
1131         case IER_OFFSET2:
1132             val = *(uint32_t *)(apic->int_en_reg + 8);
1133             break;
1134         case IER_OFFSET3:
1135             val = *(uint32_t *)(apic->int_en_reg + 12);
1136             break;
1137         case IER_OFFSET4:
1138             val = *(uint32_t *)(apic->int_en_reg + 16);
1139             break;
1140         case IER_OFFSET5:
1141             val = *(uint32_t *)(apic->int_en_reg + 20);
1142             break;
1143         case IER_OFFSET6:
1144             val = *(uint32_t *)(apic->int_en_reg + 24);
1145             break;
1146         case IER_OFFSET7:
1147             val = *(uint32_t *)(apic->int_en_reg + 28);
1148             break;
1149
1150         case ISR_OFFSET0:
1151             val = *(uint32_t *)(apic->int_svc_reg);
1152             break;
1153         case ISR_OFFSET1:
1154             val = *(uint32_t *)(apic->int_svc_reg + 4);
1155             break;
1156         case ISR_OFFSET2:
1157             val = *(uint32_t *)(apic->int_svc_reg + 8);
1158             break;
1159         case ISR_OFFSET3:
1160             val = *(uint32_t *)(apic->int_svc_reg + 12);
1161             break;
1162         case ISR_OFFSET4:
1163             val = *(uint32_t *)(apic->int_svc_reg + 16);
1164             break;
1165         case ISR_OFFSET5:
1166             val = *(uint32_t *)(apic->int_svc_reg + 20);
1167             break;
1168         case ISR_OFFSET6:
1169             val = *(uint32_t *)(apic->int_svc_reg + 24);
1170             break;
1171         case ISR_OFFSET7:
1172             val = *(uint32_t *)(apic->int_svc_reg + 28);
1173             break;
1174    
1175         case TRIG_OFFSET0:
1176             val = *(uint32_t *)(apic->trig_mode_reg);
1177             break;
1178         case TRIG_OFFSET1:
1179             val = *(uint32_t *)(apic->trig_mode_reg + 4);
1180             break;
1181         case TRIG_OFFSET2:
1182             val = *(uint32_t *)(apic->trig_mode_reg + 8);
1183             break;
1184         case TRIG_OFFSET3:
1185             val = *(uint32_t *)(apic->trig_mode_reg + 12);
1186             break;
1187         case TRIG_OFFSET4:
1188             val = *(uint32_t *)(apic->trig_mode_reg + 16);
1189             break;
1190         case TRIG_OFFSET5:
1191             val = *(uint32_t *)(apic->trig_mode_reg + 20);
1192             break;
1193         case TRIG_OFFSET6:
1194             val = *(uint32_t *)(apic->trig_mode_reg + 24);
1195             break;
1196         case TRIG_OFFSET7:
1197             val = *(uint32_t *)(apic->trig_mode_reg + 28);
1198             break;
1199
1200         case IRR_OFFSET0:
1201             val = *(uint32_t *)(apic->int_req_reg);
1202             break;
1203         case IRR_OFFSET1:
1204             val = *(uint32_t *)(apic->int_req_reg + 4);
1205             break;
1206         case IRR_OFFSET2:
1207             val = *(uint32_t *)(apic->int_req_reg + 8);
1208             break;
1209         case IRR_OFFSET3:
1210             val = *(uint32_t *)(apic->int_req_reg + 12);
1211             break;
1212         case IRR_OFFSET4:
1213             val = *(uint32_t *)(apic->int_req_reg + 16);
1214             break;
1215         case IRR_OFFSET5:
1216             val = *(uint32_t *)(apic->int_req_reg + 20);
1217             break;
1218         case IRR_OFFSET6:
1219             val = *(uint32_t *)(apic->int_req_reg + 24);
1220             break;
1221         case IRR_OFFSET7:
1222             val = *(uint32_t *)(apic->int_req_reg + 28);
1223             break;
1224         case TMR_CUR_CNT_OFFSET:
1225             val = apic->tmr_cur_cnt;
1226             break;
1227
1228             // We are not going to implement these....
1229         case THERM_LOC_VEC_TBL_OFFSET:
1230             val = apic->therm_loc_vec_tbl.val;
1231             break;
1232         case PERF_CTR_LOC_VEC_TBL_OFFSET:
1233             val = apic->perf_ctr_loc_vec_tbl.val;
1234             break;
1235
1236  
1237
1238             // handled registers
1239         case INT_CMD_LO_OFFSET:    
1240             val = apic->int_cmd.lo;
1241             break;
1242         case INT_CMD_HI_OFFSET:
1243             val = apic->int_cmd.hi;
1244             break;
1245
1246             // handle current timer count
1247
1248             // Unhandled Registers
1249         case EXT_INT_LOC_VEC_TBL_OFFSET0:
1250             val = apic->ext_intr_vec_tbl[0].val;
1251             break;
1252         case EXT_INT_LOC_VEC_TBL_OFFSET1:
1253             val = apic->ext_intr_vec_tbl[1].val;
1254             break;
1255         case EXT_INT_LOC_VEC_TBL_OFFSET2:
1256             val = apic->ext_intr_vec_tbl[2].val;
1257             break;
1258         case EXT_INT_LOC_VEC_TBL_OFFSET3:
1259             val = apic->ext_intr_vec_tbl[3].val;
1260             break;
1261     
1262
1263         case EXT_APIC_FEATURE_OFFSET:
1264         case EXT_APIC_CMD_OFFSET:
1265         case SEOI_OFFSET:
1266
1267         default:
1268             PrintError("apic %u: core %u: Read from Unhandled APIC Register: %x (getting zero)\n", 
1269                        apic->lapic_id.val, core->vcpu_id, (uint32_t)reg_addr);
1270             return -1;
1271     }
1272
1273
1274     if (length == 1) {
1275         uint_t byte_addr = reg_addr & 0x3;
1276         uint8_t * val_ptr = (uint8_t *)dst;
1277     
1278         *val_ptr = *(((uint8_t *)&val) + byte_addr);
1279
1280     } else if ((length == 2) && 
1281                ((reg_addr & 0x3) != 0x3)) {
1282         uint_t byte_addr = reg_addr & 0x3;
1283         uint16_t * val_ptr = (uint16_t *)dst;
1284         *val_ptr = *(((uint16_t *)&val) + byte_addr);
1285
1286     } else if (length == 4) {
1287         uint32_t * val_ptr = (uint32_t *)dst;
1288         *val_ptr = val;
1289
1290     } else {
1291         PrintError("apic %u: core %u: Invalid apic read length (%d)\n", 
1292                    apic->lapic_id.val, core->vcpu_id, length);
1293         return -1;
1294     }
1295
1296     PrintDebug("apic %u: core %u: Read finished (val=%x)\n", 
1297                apic->lapic_id.val, core->vcpu_id, *(uint32_t *)dst);
1298
1299     return length;
1300 }
1301
1302
1303 /**
1304  *
1305  */
1306 static int apic_write(struct guest_info * core, addr_t guest_addr, void * src, uint_t length, void * priv_data) {
1307     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(priv_data);
1308     struct apic_state * apic = &(apic_dev->apics[core->vcpu_id]); 
1309     addr_t reg_addr  = guest_addr - apic->base_addr;
1310     struct apic_msr * msr = (struct apic_msr *)&(apic->base_addr_msr.value);
1311     uint32_t op_val = *(uint32_t *)src;
1312     addr_t flags = 0;
1313
1314     PrintDebug("apic %u: core %u: at %p and priv_data is at %p\n",
1315                apic->lapic_id.val, core->vcpu_id, apic, priv_data);
1316
1317     PrintDebug("apic %u: core %u: write to address space (%p) (val=%x)\n", 
1318                apic->lapic_id.val, core->vcpu_id, (void *)guest_addr, *(uint32_t *)src);
1319
1320     if (msr->apic_enable == 0) {
1321         PrintError("apic %u: core %u: Write to APIC address space with disabled APIC, apic msr=0x%llx\n",
1322                    apic->lapic_id.val, core->vcpu_id, apic->base_addr_msr.value);
1323         return -1;
1324     }
1325
1326
1327     if (length != 4) {
1328         PrintError("apic %u: core %u: Invalid apic write length (%d)\n", 
1329                    apic->lapic_id.val, length, core->vcpu_id);
1330         return -1;
1331     }
1332
1333     switch (reg_addr) {
1334         case REMOTE_READ_OFFSET:
1335         case APIC_VERSION_OFFSET:
1336         case APR_OFFSET:
1337         case IRR_OFFSET0:
1338         case IRR_OFFSET1:
1339         case IRR_OFFSET2:
1340         case IRR_OFFSET3:
1341         case IRR_OFFSET4:
1342         case IRR_OFFSET5:
1343         case IRR_OFFSET6:
1344         case IRR_OFFSET7:
1345         case ISR_OFFSET0:
1346         case ISR_OFFSET1:
1347         case ISR_OFFSET2:
1348         case ISR_OFFSET3:
1349         case ISR_OFFSET4:
1350         case ISR_OFFSET5:
1351         case ISR_OFFSET6:
1352         case ISR_OFFSET7:
1353         case TRIG_OFFSET0:
1354         case TRIG_OFFSET1:
1355         case TRIG_OFFSET2:
1356         case TRIG_OFFSET3:
1357         case TRIG_OFFSET4:
1358         case TRIG_OFFSET5:
1359         case TRIG_OFFSET6:
1360         case TRIG_OFFSET7:
1361         case PPR_OFFSET:
1362         case EXT_APIC_FEATURE_OFFSET:
1363
1364             PrintError("apic %u: core %u: Attempting to write to read only register %p (error)\n", 
1365                        apic->lapic_id.val, core->vcpu_id, (void *)reg_addr);
1366
1367             break;
1368
1369             // Data registers
1370         case APIC_ID_OFFSET:
1371             //V3_Print("apic %u: core %u: my id is being changed to %u\n", 
1372             //       apic->lapic_id.val, core->vcpu_id, op_val);
1373
1374             apic->lapic_id.val = op_val;
1375             break;
1376         case TPR_OFFSET:
1377             apic->task_prio.val = op_val;
1378             break;
1379         case LDR_OFFSET:
1380             PrintDebug("apic %u: core %u: setting log_dst.val to 0x%x\n",
1381                        apic->lapic_id.val, core->vcpu_id, op_val);
1382             flags = v3_lock_irqsave(apic_dev->state_lock);
1383             apic->log_dst.val = op_val;
1384             v3_unlock_irqrestore(apic_dev->state_lock, flags);
1385             break;
1386         case DFR_OFFSET:
1387             flags = v3_lock_irqsave(apic_dev->state_lock);
1388             apic->dst_fmt.val = op_val;
1389             v3_unlock_irqrestore(apic_dev->state_lock, flags);
1390             break;
1391         case SPURIOUS_INT_VEC_OFFSET:
1392             apic->spurious_int.val = op_val;
1393             break;
1394         case ESR_OFFSET:
1395             apic->err_status.val = op_val;
1396             break;
1397         case TMR_LOC_VEC_TBL_OFFSET:
1398             apic->tmr_vec_tbl.val = op_val;
1399             break;
1400         case THERM_LOC_VEC_TBL_OFFSET:
1401             apic->therm_loc_vec_tbl.val = op_val;
1402             break;
1403         case PERF_CTR_LOC_VEC_TBL_OFFSET:
1404             apic->perf_ctr_loc_vec_tbl.val = op_val;
1405             break;
1406         case LINT0_VEC_TBL_OFFSET:
1407             apic->lint0_vec_tbl.val = op_val;
1408             break;
1409         case LINT1_VEC_TBL_OFFSET:
1410             apic->lint1_vec_tbl.val = op_val;
1411             break;
1412         case ERR_VEC_TBL_OFFSET:
1413             apic->err_vec_tbl.val = op_val;
1414             break;
1415         case TMR_INIT_CNT_OFFSET:
1416             apic->tmr_init_cnt = op_val;
1417             apic->tmr_cur_cnt = op_val;
1418             break;
1419         case TMR_CUR_CNT_OFFSET:
1420             apic->tmr_cur_cnt = op_val;
1421             break;
1422         case TMR_DIV_CFG_OFFSET:
1423             PrintDebug("apic %u: core %u: setting tmr_div_cfg to 0x%x\n",
1424                        apic->lapic_id.val, core->vcpu_id, op_val);
1425             apic->tmr_div_cfg.val = op_val;
1426             break;
1427
1428
1429             // Enable mask (256 bits)
1430         case IER_OFFSET0:
1431             *(uint32_t *)(apic->int_en_reg) = op_val;
1432             break;
1433         case IER_OFFSET1:
1434             *(uint32_t *)(apic->int_en_reg + 4) = op_val;
1435             break;
1436         case IER_OFFSET2:
1437             *(uint32_t *)(apic->int_en_reg + 8) = op_val;
1438             break;
1439         case IER_OFFSET3:
1440             *(uint32_t *)(apic->int_en_reg + 12) = op_val;
1441             break;
1442         case IER_OFFSET4:
1443             *(uint32_t *)(apic->int_en_reg + 16) = op_val;
1444             break;
1445         case IER_OFFSET5:
1446             *(uint32_t *)(apic->int_en_reg + 20) = op_val;
1447             break;
1448         case IER_OFFSET6:
1449             *(uint32_t *)(apic->int_en_reg + 24) = op_val;
1450             break;
1451         case IER_OFFSET7:
1452             *(uint32_t *)(apic->int_en_reg + 28) = op_val;
1453             break;
1454
1455         case EXT_INT_LOC_VEC_TBL_OFFSET0:
1456             apic->ext_intr_vec_tbl[0].val = op_val;
1457             break;
1458         case EXT_INT_LOC_VEC_TBL_OFFSET1:
1459             apic->ext_intr_vec_tbl[1].val = op_val;
1460             break;
1461         case EXT_INT_LOC_VEC_TBL_OFFSET2:
1462             apic->ext_intr_vec_tbl[2].val = op_val;
1463             break;
1464         case EXT_INT_LOC_VEC_TBL_OFFSET3:
1465             apic->ext_intr_vec_tbl[3].val = op_val;
1466             break;
1467
1468
1469             // Action Registers
1470         case EOI_OFFSET:
1471             // do eoi 
1472             apic_do_eoi(core, apic);
1473             break;
1474
1475         case INT_CMD_LO_OFFSET: {
1476             // execute command 
1477
1478             struct v3_gen_ipi tmp_ipi;
1479
1480             apic->int_cmd.lo = op_val;
1481
1482             tmp_ipi.vector = apic->int_cmd.vec;
1483             tmp_ipi.mode = apic->int_cmd.del_mode;
1484             tmp_ipi.logical = apic->int_cmd.dst_mode;
1485             tmp_ipi.trigger_mode = apic->int_cmd.trig_mode;
1486             tmp_ipi.dst_shorthand = apic->int_cmd.dst_shorthand;
1487             tmp_ipi.dst = apic->int_cmd.dst;
1488                 
1489             tmp_ipi.ack = NULL;
1490             tmp_ipi.private_data = NULL;
1491             
1492
1493             //      V3_Print("apic %u: core %u: sending cmd 0x%llx to apic %u\n", 
1494             //       apic->lapic_id.val, core->vcpu_id,
1495             //       apic->int_cmd.val, apic->int_cmd.dst);
1496
1497             if (route_ipi(apic_dev, apic, &tmp_ipi) == -1) { 
1498                 PrintError("IPI Routing failure\n");
1499                 return -1;
1500             }
1501
1502             break;
1503         }
1504         case INT_CMD_HI_OFFSET: {
1505             apic->int_cmd.hi = op_val;
1506             //V3_Print("apic %u: core %u: writing command high=0x%x\n", apic->lapic_id.val, core->vcpu_id,apic->int_cmd.hi);
1507             break;
1508         }
1509         // Unhandled Registers
1510         case EXT_APIC_CMD_OFFSET:
1511         case SEOI_OFFSET:
1512         default:
1513             PrintError("apic %u: core %u: Write to Unhandled APIC Register: %x (ignored)\n", 
1514                        apic->lapic_id.val, core->vcpu_id, (uint32_t)reg_addr);
1515
1516             return -1;
1517     }
1518
1519     PrintDebug("apic %u: core %u: Write finished\n", apic->lapic_id.val, core->vcpu_id);
1520
1521     return length;
1522
1523 }
1524
1525
1526
1527 /* Interrupt Controller Functions */
1528
1529
1530 static int apic_intr_pending(struct guest_info * core, void * private_data) {
1531     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(private_data);
1532     struct apic_state * apic = &(apic_dev->apics[core->vcpu_id]); 
1533     int req_irq = 0;    
1534     int svc_irq = 0;
1535
1536     // Activate all queued IRQ entries
1537     drain_irq_entries(apic);
1538
1539     // Check for newly activated entries
1540     req_irq = get_highest_irr(apic);
1541     svc_irq = get_highest_isr(apic);
1542
1543     //    PrintDebug("apic %u: core %u: req_irq=%d, svc_irq=%d\n",apic->lapic_id.val,info->vcpu_id,req_irq,svc_irq);
1544
1545     if ((req_irq >= 0) && 
1546         (req_irq > svc_irq)) {
1547         return 1;
1548     }
1549
1550     return 0;
1551 }
1552
1553
1554
1555 static int apic_get_intr_number(struct guest_info * core, void * private_data) {
1556     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(private_data);
1557     struct apic_state * apic = &(apic_dev->apics[core->vcpu_id]); 
1558     int req_irq = get_highest_irr(apic);
1559     int svc_irq = get_highest_isr(apic);
1560
1561     if (svc_irq == -1) {
1562         return req_irq;
1563     } else if (svc_irq < req_irq) {
1564         return req_irq;
1565     }
1566
1567     return -1;
1568 }
1569
1570
1571
1572 int v3_apic_send_ipi(struct v3_vm_info * vm, struct v3_gen_ipi * ipi, void * dev_data) {
1573     struct apic_dev_state * apic_dev = (struct apic_dev_state *)
1574         (((struct vm_device *)dev_data)->private_data);
1575
1576     return route_ipi(apic_dev, NULL, ipi);
1577 }
1578
1579
1580
1581
1582 static int apic_begin_irq(struct guest_info * core, void * private_data, int irq) {
1583     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(private_data);
1584     struct apic_state * apic = &(apic_dev->apics[core->vcpu_id]); 
1585     int major_offset = (irq & ~0x00000007) >> 3;
1586     int minor_offset = irq & 0x00000007;
1587     uint8_t *req_location = apic->int_req_reg + major_offset;
1588     uint8_t *svc_location = apic->int_svc_reg + major_offset;
1589     uint8_t flag = 0x01 << minor_offset;
1590
1591     if (*req_location & flag) {
1592         // we will only pay attention to a begin irq if we
1593         // know that we initiated it!
1594         *svc_location |= flag;
1595         *req_location &= ~flag;
1596     } else {
1597         // do nothing... 
1598         //PrintDebug("apic %u: core %u: begin irq for %d ignored since I don't own it\n",
1599         //         apic->lapic_id.val, core->vcpu_id, irq);
1600     }
1601
1602     return 0;
1603 }
1604
1605
1606 /* Timer Functions */
1607
1608 static void apic_inject_timer_intr(struct guest_info *core,
1609                                    void * priv_data) {
1610     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(priv_data);
1611     struct apic_state * apic = &(apic_dev->apics[core->vcpu_id]); 
1612     // raise irq
1613     PrintDebug("apic %u: core %u: Raising APIC Timer interrupt (periodic=%d) (icnt=%d)\n",
1614                apic->lapic_id.val, core->vcpu_id,
1615                apic->tmr_vec_tbl.tmr_mode, apic->tmr_init_cnt);
1616
1617     if (apic_intr_pending(core, priv_data)) {
1618         PrintDebug("apic %u: core %u: Overriding pending IRQ %d\n", 
1619                    apic->lapic_id.val, core->vcpu_id, 
1620                    apic_get_intr_number(core, priv_data));
1621     }
1622
1623     if (activate_internal_irq(apic, APIC_TMR_INT) == -1) {
1624         PrintError("apic %u: core %u: Could not raise Timer interrupt\n",
1625                    apic->lapic_id.val, core->vcpu_id);
1626     }
1627
1628     return;
1629 }
1630         
1631
1632
1633
1634 static void apic_update_time(struct guest_info * core, 
1635                              uint64_t cpu_cycles, uint64_t cpu_freq, 
1636                              void * priv_data) {
1637     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(priv_data);
1638     struct apic_state * apic = &(apic_dev->apics[core->vcpu_id]); 
1639
1640     // The 32 bit GCC runtime is a pile of shit
1641 #ifdef __V3_64BIT__
1642     uint64_t tmr_ticks = 0;
1643 #else 
1644     uint32_t tmr_ticks = 0;
1645 #endif
1646
1647     uint8_t tmr_div = *(uint8_t *)&(apic->tmr_div_cfg.val);
1648     uint_t shift_num = 0;
1649
1650
1651     // Check whether this is true:
1652     //   -> If the Init count is zero then the timer is disabled
1653     //      and doesn't just blitz interrupts to the CPU
1654     if ((apic->tmr_init_cnt == 0) || 
1655         ( (apic->tmr_vec_tbl.tmr_mode == APIC_TMR_ONESHOT) &&
1656           (apic->tmr_cur_cnt == 0))) {
1657         //PrintDebug("apic %u: core %u: APIC timer not yet initialized\n",apic->lapic_id.val,info->vcpu_id);
1658         return;
1659     }
1660
1661
1662     switch (tmr_div) {
1663         case APIC_TMR_DIV1:
1664             shift_num = 0;
1665             break;
1666         case APIC_TMR_DIV2:
1667             shift_num = 1;
1668             break;
1669         case APIC_TMR_DIV4:
1670             shift_num = 2;
1671             break;
1672         case APIC_TMR_DIV8:
1673             shift_num = 3;
1674             break;
1675         case APIC_TMR_DIV16:
1676             shift_num = 4;
1677             break;
1678         case APIC_TMR_DIV32:
1679             shift_num = 5;
1680             break;
1681         case APIC_TMR_DIV64:
1682             shift_num = 6;
1683             break;
1684         case APIC_TMR_DIV128:
1685             shift_num = 7;
1686             break;
1687         default:
1688             PrintError("apic %u: core %u: Invalid Timer Divider configuration\n",
1689                        apic->lapic_id.val, core->vcpu_id);
1690             return;
1691     }
1692
1693     tmr_ticks = cpu_cycles >> shift_num;
1694     //    PrintDebug("Timer Ticks: %p\n", (void *)tmr_ticks);
1695
1696     if (tmr_ticks < apic->tmr_cur_cnt) {
1697         apic->tmr_cur_cnt -= tmr_ticks;
1698 #ifdef V3_CONFIG_APIC_ENQUEUE_MISSED_TMR_IRQS
1699         if (apic->missed_ints && !apic_intr_pending(core, priv_data)) {
1700             PrintDebug("apic %u: core %u: Injecting queued APIC timer interrupt.\n",
1701                        apic->lapic_id.val, core->vcpu_id);
1702             apic_inject_timer_intr(core, priv_data);
1703             apic->missed_ints--;
1704         }
1705 #endif /* CONFIG_APIC_ENQUEUE_MISSED_TMR_IRQS */ 
1706     } else {
1707         tmr_ticks -= apic->tmr_cur_cnt;
1708         apic->tmr_cur_cnt = 0;
1709
1710         apic_inject_timer_intr(core, priv_data);
1711
1712         if (apic->tmr_vec_tbl.tmr_mode == APIC_TMR_PERIODIC) {
1713             int queued_ints = tmr_ticks / apic->tmr_init_cnt;
1714             tmr_ticks = tmr_ticks % apic->tmr_init_cnt;
1715             apic->tmr_cur_cnt = apic->tmr_init_cnt - tmr_ticks;
1716             apic->missed_ints += queued_ints;
1717         }
1718     }
1719
1720     return;
1721 }
1722
1723 static struct intr_ctrl_ops intr_ops = {
1724     .intr_pending = apic_intr_pending,
1725     .get_intr_number = apic_get_intr_number,
1726     .begin_irq = apic_begin_irq,
1727 };
1728
1729
1730 static struct v3_timer_ops timer_ops = {
1731     .update_timer = apic_update_time,
1732 };
1733
1734
1735
1736
1737 static int apic_free(struct apic_dev_state * apic_dev) {
1738     int i = 0;
1739     struct v3_vm_info * vm = NULL;
1740
1741     for (i = 0; i < apic_dev->num_apics; i++) {
1742         struct apic_state * apic = &(apic_dev->apics[i]);
1743         struct guest_info * core = apic->core;
1744         
1745         vm = core->vm_info;
1746
1747         v3_remove_intr_controller(core, apic->controller_handle);
1748
1749         if (apic->timer) {
1750             v3_remove_timer(core, apic->timer);
1751         }
1752
1753         // unhook memory
1754
1755     }
1756
1757     v3_unhook_msr(vm, BASE_ADDR_MSR);
1758
1759     V3_Free(apic_dev);
1760     return 0;
1761 }
1762
1763 #ifdef V3_CONFIG_CHECKPOINT
1764 static int apic_save(struct v3_chkpt_ctx * ctx, void * private_data) {
1765     struct apic_dev_state * apic_state = (struct apic_dev_state *)private_data;
1766     int i = 0;
1767
1768     V3_CHKPT_STD_SAVE(ctx, apic_state->num_apics);
1769
1770     //V3_CHKPT_STD_SAVE(ctx,apic_state->state_lock);
1771     for (i = 0; i < apic_state->num_apics; i++) {
1772
1773         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].base_addr);
1774         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].base_addr_msr);
1775         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].lapic_id);
1776         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].apic_ver);
1777         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].ext_apic_ctrl);
1778         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].local_vec_tbl);
1779         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].tmr_vec_tbl);
1780         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].tmr_div_cfg);
1781         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].lint0_vec_tbl);
1782         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].lint1_vec_tbl);
1783         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].perf_ctr_loc_vec_tbl);
1784         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].therm_loc_vec_tbl);
1785         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].err_vec_tbl);
1786         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].err_status);
1787         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].spurious_int);
1788         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].int_cmd);
1789         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].log_dst);
1790         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].dst_fmt);
1791         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].arb_prio);
1792         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].task_prio);
1793         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].proc_prio);
1794         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].ext_apic_feature);
1795         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].spec_eoi);
1796         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].tmr_cur_cnt);
1797         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].tmr_init_cnt);
1798         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].ext_intr_vec_tbl);
1799         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].rem_rd_data);
1800         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].ipi_state);
1801         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].int_req_reg);
1802         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].int_svc_reg);
1803         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].int_en_reg);
1804         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].trig_mode_reg);
1805         V3_CHKPT_STD_SAVE(ctx, apic_state->apics[i].eoi);
1806
1807     }
1808
1809     return 0;
1810 }
1811
1812 static int apic_load(struct v3_chkpt_ctx * ctx, void * private_data) {
1813     struct apic_dev_state *apic_state = (struct apic_dev_state *)private_data;
1814     int i = 0;
1815
1816     V3_CHKPT_STD_LOAD(ctx,apic_state->num_apics);
1817
1818     for (i = 0; i < apic_state->num_apics; i++) {
1819         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].base_addr);
1820         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].base_addr_msr);
1821         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].lapic_id);
1822         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].apic_ver);
1823         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].ext_apic_ctrl);
1824         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].local_vec_tbl);
1825         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].tmr_vec_tbl);
1826         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].tmr_div_cfg);
1827         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].lint0_vec_tbl);
1828         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].lint1_vec_tbl);
1829         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].perf_ctr_loc_vec_tbl);
1830         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].therm_loc_vec_tbl);
1831         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].err_vec_tbl);
1832         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].err_status);
1833         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].spurious_int);
1834         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].int_cmd);
1835         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].log_dst);
1836         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].dst_fmt);
1837         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].arb_prio);
1838         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].task_prio);
1839         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].proc_prio);
1840         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].ext_apic_feature);
1841         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].spec_eoi);
1842         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].tmr_cur_cnt);
1843         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].tmr_init_cnt);
1844         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].ext_intr_vec_tbl);
1845         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].rem_rd_data);
1846         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].ipi_state);
1847         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].int_req_reg);
1848         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].int_svc_reg);
1849         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].int_en_reg);
1850         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].trig_mode_reg);
1851         V3_CHKPT_STD_LOAD(ctx, apic_state->apics[i].eoi);
1852     }
1853
1854
1855     return 0;
1856 }
1857
1858 #endif
1859
1860 static struct v3_device_ops dev_ops = {
1861     .free = (int (*)(void *))apic_free,
1862 #ifdef V3_CONFIG_CHECKPOINT
1863     .save = apic_save,
1864     .load = apic_load
1865 #endif
1866 };
1867
1868
1869
1870 static int apic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
1871     char * dev_id = v3_cfg_val(cfg, "ID");
1872     struct apic_dev_state * apic_dev = NULL;
1873     int i = 0;
1874
1875     PrintDebug("apic: creating an APIC for each core\n");
1876
1877     apic_dev = (struct apic_dev_state *)V3_Malloc(sizeof(struct apic_dev_state) + 
1878                                                   sizeof(struct apic_state) * vm->num_cores);
1879
1880     apic_dev->num_apics = vm->num_cores;
1881     v3_lock_init(&(apic_dev->state_lock));
1882
1883     struct vm_device * dev = v3_add_device(vm, dev_id, &dev_ops, apic_dev);
1884
1885     if (dev == NULL) {
1886         PrintError("apic: Could not attach device %s\n", dev_id);
1887         V3_Free(apic_dev);
1888         return -1;
1889     }
1890
1891     
1892     for (i = 0; i < vm->num_cores; i++) {
1893         struct apic_state * apic = &(apic_dev->apics[i]);
1894         struct guest_info * core = &(vm->cores[i]);
1895
1896         apic->core = core;
1897
1898         init_apic_state(apic, i);
1899
1900         apic->controller_handle = v3_register_intr_controller(core, &intr_ops, apic_dev);
1901
1902         apic->timer = v3_add_timer(core, &timer_ops, apic_dev);
1903
1904         if (apic->timer == NULL) {
1905             PrintError("APIC: Failed to attach timer to core %d\n", i);
1906             v3_remove_device(dev);
1907             return -1;
1908         }
1909
1910         v3_hook_full_mem(vm, core->vcpu_id, apic->base_addr, apic->base_addr + PAGE_SIZE_4KB, apic_read, apic_write, apic_dev);
1911
1912         PrintDebug("apic %u: (setup device): done, my id is %u\n", i, apic->lapic_id.val);
1913     }
1914
1915 #ifdef V3_CONFIG_DEBUG_APIC
1916     for (i = 0; i < vm->num_cores; i++) {
1917         struct apic_state * apic = &(apic_dev->apics[i]);
1918         PrintDebug("apic: sanity check: apic %u (at %p) has id %u and msr value %llx and core at %p\n",
1919                    i, apic, apic->lapic_id.val, apic->base_addr_msr.value,apic->core);
1920     }
1921 #endif
1922
1923
1924     PrintDebug("apic: priv_data is at %p\n", apic_dev);
1925
1926     v3_hook_msr(vm, BASE_ADDR_MSR, read_apic_msr, write_apic_msr, apic_dev);
1927
1928     return 0;
1929 }
1930
1931
1932
1933 device_register("LAPIC", apic_init)