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.


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