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.


Minor debugging print changes/fixups
[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  * Author: Jack Lange <jarusl@cs.northwestern.edu>
15  *
16  * This is free software.  You are permitted to use,
17  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
18  */
19
20
21 #include <devices/apic.h>
22 #include <devices/apic_regs.h>
23 #include <palacios/vmm.h>
24 #include <palacios/vmm_msr.h>
25 #include <palacios/vmm_sprintf.h>
26 #include <palacios/vm_guest.h>
27 #include <palacios/vmm_types.h>
28
29
30 #ifndef CONFIG_DEBUG_APIC
31 #undef PrintDebug
32 #define PrintDebug(fmt, args...)
33 #endif
34
35 #ifdef CONFIG_DEBUG_APIC
36 static char *shorthand_str[] = { 
37     "(no shorthand)",
38     "(self)",
39     "(all)",
40     "(all-but-me)",
41 };
42
43 static char *deliverymode_str[] = { 
44     "(fixed)",
45     "(lowest priority)",
46     "(SMI)",
47     "(reserved)",
48     "(NMI)",
49     "(INIT)",
50     "(Start Up)",
51     "(ExtInt)",
52 };
53 #endif
54
55 typedef enum { APIC_TMR_INT, APIC_THERM_INT, APIC_PERF_INT, 
56                APIC_LINT0_INT, APIC_LINT1_INT, APIC_ERR_INT } apic_irq_type_t;
57
58 #define APIC_FIXED_DELIVERY  0x0
59 #define APIC_SMI_DELIVERY    0x2
60 #define APIC_NMI_DELIVERY    0x4
61 #define APIC_INIT_DELIVERY   0x5
62 #define APIC_EXTINT_DELIVERY 0x7
63
64
65 #define BASE_ADDR_MSR     0x0000001B
66 #define DEFAULT_BASE_ADDR 0xfee00000
67
68 #define APIC_ID_OFFSET                    0x020
69 #define APIC_VERSION_OFFSET               0x030
70 #define TPR_OFFSET                        0x080
71 #define APR_OFFSET                        0x090
72 #define PPR_OFFSET                        0x0a0
73 #define EOI_OFFSET                        0x0b0
74 #define REMOTE_READ_OFFSET                0x0c0
75 #define LDR_OFFSET                        0x0d0
76 #define DFR_OFFSET                        0x0e0
77 #define SPURIOUS_INT_VEC_OFFSET           0x0f0
78
79 #define ISR_OFFSET0                       0x100   // 0x100 - 0x170
80 #define ISR_OFFSET1                       0x110   // 0x100 - 0x170
81 #define ISR_OFFSET2                       0x120   // 0x100 - 0x170
82 #define ISR_OFFSET3                       0x130   // 0x100 - 0x170
83 #define ISR_OFFSET4                       0x140   // 0x100 - 0x170
84 #define ISR_OFFSET5                       0x150   // 0x100 - 0x170
85 #define ISR_OFFSET6                       0x160   // 0x100 - 0x170
86 #define ISR_OFFSET7                       0x170   // 0x100 - 0x170
87
88 #define TRIG_OFFSET0                      0x180   // 0x180 - 0x1f0
89 #define TRIG_OFFSET1                      0x190   // 0x180 - 0x1f0
90 #define TRIG_OFFSET2                      0x1a0   // 0x180 - 0x1f0
91 #define TRIG_OFFSET3                      0x1b0   // 0x180 - 0x1f0
92 #define TRIG_OFFSET4                      0x1c0   // 0x180 - 0x1f0
93 #define TRIG_OFFSET5                      0x1d0   // 0x180 - 0x1f0
94 #define TRIG_OFFSET6                      0x1e0   // 0x180 - 0x1f0
95 #define TRIG_OFFSET7                      0x1f0   // 0x180 - 0x1f0
96
97
98 #define IRR_OFFSET0                       0x200   // 0x200 - 0x270
99 #define IRR_OFFSET1                       0x210   // 0x200 - 0x270
100 #define IRR_OFFSET2                       0x220   // 0x200 - 0x270
101 #define IRR_OFFSET3                       0x230   // 0x200 - 0x270
102 #define IRR_OFFSET4                       0x240   // 0x200 - 0x270
103 #define IRR_OFFSET5                       0x250   // 0x200 - 0x270
104 #define IRR_OFFSET6                       0x260   // 0x200 - 0x270
105 #define IRR_OFFSET7                       0x270   // 0x200 - 0x270
106
107
108 #define ESR_OFFSET                        0x280
109 #define INT_CMD_LO_OFFSET                 0x300
110 #define INT_CMD_HI_OFFSET                 0x310
111 #define TMR_LOC_VEC_TBL_OFFSET            0x320
112 #define THERM_LOC_VEC_TBL_OFFSET          0x330
113 #define PERF_CTR_LOC_VEC_TBL_OFFSET       0x340
114 #define LINT0_VEC_TBL_OFFSET              0x350
115 #define LINT1_VEC_TBL_OFFSET              0x360
116 #define ERR_VEC_TBL_OFFSET                0x370
117 #define TMR_INIT_CNT_OFFSET               0x380
118 #define TMR_CUR_CNT_OFFSET                0x390
119 #define TMR_DIV_CFG_OFFSET                0x3e0
120 #define EXT_APIC_FEATURE_OFFSET           0x400
121 #define EXT_APIC_CMD_OFFSET               0x410
122 #define SEOI_OFFSET                       0x420
123
124 #define IER_OFFSET0                       0x480   // 0x480 - 0x4f0
125 #define IER_OFFSET1                       0x490   // 0x480 - 0x4f0
126 #define IER_OFFSET2                       0x4a0   // 0x480 - 0x4f0
127 #define IER_OFFSET3                       0x4b0   // 0x480 - 0x4f0
128 #define IER_OFFSET4                       0x4c0   // 0x480 - 0x4f0
129 #define IER_OFFSET5                       0x4d0   // 0x480 - 0x4f0
130 #define IER_OFFSET6                       0x4e0   // 0x480 - 0x4f0
131 #define IER_OFFSET7                       0x4f0   // 0x480 - 0x4f0
132
133 #define EXT_INT_LOC_VEC_TBL_OFFSET0       0x500   // 0x500 - 0x530
134 #define EXT_INT_LOC_VEC_TBL_OFFSET1       0x510   // 0x500 - 0x530
135 #define EXT_INT_LOC_VEC_TBL_OFFSET2       0x520   // 0x500 - 0x530
136 #define EXT_INT_LOC_VEC_TBL_OFFSET3       0x530   // 0x500 - 0x530
137
138 struct apic_msr {
139     union {
140         uint64_t value;
141         struct {
142             uint8_t rsvd;
143             uint8_t bootstrap_cpu : 1;
144             uint8_t rsvd2         : 2;
145             uint8_t apic_enable   : 1;
146             uint64_t base_addr    : 40;
147             uint32_t rsvd3        : 12;
148         } __attribute__((packed));
149     } __attribute__((packed));
150 } __attribute__((packed));
151
152
153
154 typedef enum {INIT_ST, 
155               SIPI, 
156               STARTED} ipi_state_t; 
157
158 struct apic_dev_state;
159
160 struct apic_state {
161     addr_t base_addr;
162
163     /* MSRs */
164     struct apic_msr base_addr_msr;
165
166
167     /* memory map registers */
168
169     struct lapic_id_reg lapic_id;
170     struct apic_ver_reg apic_ver;
171     struct ext_apic_ctrl_reg ext_apic_ctrl;
172     struct local_vec_tbl_reg local_vec_tbl;
173     struct tmr_vec_tbl_reg tmr_vec_tbl;
174     struct tmr_div_cfg_reg tmr_div_cfg;
175     struct lint_vec_tbl_reg lint0_vec_tbl;
176     struct lint_vec_tbl_reg lint1_vec_tbl;
177     struct perf_ctr_loc_vec_tbl_reg perf_ctr_loc_vec_tbl;
178     struct therm_loc_vec_tbl_reg therm_loc_vec_tbl;
179     struct err_vec_tbl_reg err_vec_tbl;
180     struct err_status_reg err_status;
181     struct spurious_int_reg spurious_int;
182     struct int_cmd_reg int_cmd;
183     struct log_dst_reg log_dst;
184     struct dst_fmt_reg dst_fmt;
185     struct arb_prio_reg arb_prio;
186     struct task_prio_reg task_prio;
187     struct proc_prio_reg proc_prio;
188     struct ext_apic_feature_reg ext_apic_feature;
189     struct spec_eoi_reg spec_eoi;
190   
191
192     uint32_t tmr_cur_cnt;
193     uint32_t tmr_init_cnt;
194
195
196     struct local_vec_tbl_reg ext_intr_vec_tbl[4];
197
198     uint32_t rem_rd_data;
199
200
201     ipi_state_t ipi_state;
202
203     uint8_t int_req_reg[32];
204     uint8_t int_svc_reg[32];
205     uint8_t int_en_reg[32];
206     uint8_t trig_mode_reg[32];
207
208     struct guest_info * core;
209
210     uint32_t eoi;
211
212     v3_lock_t  lock;
213 };
214
215
216
217
218 struct apic_dev_state {
219     int num_apics;
220
221     struct apic_state apics[0];
222 } __attribute__((packed));
223
224
225
226 static int apic_read(struct guest_info * core, addr_t guest_addr, void * dst, uint_t length, void * priv_data);
227 static int apic_write(struct guest_info * core, addr_t guest_addr, void * src, uint_t length, void * priv_data);
228
229 static void init_apic_state(struct apic_state * apic, uint32_t id) {
230     apic->base_addr = DEFAULT_BASE_ADDR;
231
232     if (id == 0) { 
233         // boot processor, enabled
234         apic->base_addr_msr.value = 0x0000000000000900LL;
235     } else {
236         // ap processor, enabled
237         apic->base_addr_msr.value = 0x0000000000000800LL;
238     }
239
240     // same base address regardless of ap or main
241     apic->base_addr_msr.value |= ((uint64_t)DEFAULT_BASE_ADDR); 
242
243     PrintDebug("apic %u: (init_apic_state): msr=0x%llx\n",id, apic->base_addr_msr.value);
244
245     PrintDebug("apic %u: (init_apic_state): Sizeof Interrupt Request Register %d, should be 32\n",
246                id, (uint_t)sizeof(apic->int_req_reg));
247
248     memset(apic->int_req_reg, 0, sizeof(apic->int_req_reg));
249     memset(apic->int_svc_reg, 0, sizeof(apic->int_svc_reg));
250     memset(apic->int_en_reg, 0xff, sizeof(apic->int_en_reg));
251     memset(apic->trig_mode_reg, 0, sizeof(apic->trig_mode_reg));
252
253     apic->eoi = 0x00000000;
254     apic->rem_rd_data = 0x00000000;
255     apic->tmr_init_cnt = 0x00000000;
256     apic->tmr_cur_cnt = 0x00000000;
257
258     apic->lapic_id.val = id;
259     
260     apic->ipi_state = INIT_ST;
261
262     // The P6 has 6 LVT entries, so we set the value to (6-1)...
263     apic->apic_ver.val = 0x80050010;
264
265     apic->task_prio.val = 0x00000000;
266     apic->arb_prio.val = 0x00000000;
267     apic->proc_prio.val = 0x00000000;
268     apic->log_dst.val = 0x00000000;
269     apic->dst_fmt.val = 0xffffffff;
270     apic->spurious_int.val = 0x000000ff;
271     apic->err_status.val = 0x00000000;
272     apic->int_cmd.val = 0x0000000000000000LL;
273     apic->tmr_vec_tbl.val = 0x00010000;
274     apic->therm_loc_vec_tbl.val = 0x00010000;
275     apic->perf_ctr_loc_vec_tbl.val = 0x00010000;
276     apic->lint0_vec_tbl.val = 0x00010000;
277     apic->lint1_vec_tbl.val = 0x00010000;
278     apic->err_vec_tbl.val = 0x00010000;
279     apic->tmr_div_cfg.val = 0x00000000;
280     //apic->ext_apic_feature.val = 0x00000007;
281     apic->ext_apic_feature.val = 0x00040007;
282     apic->ext_apic_ctrl.val = 0x00000000;
283     apic->spec_eoi.val = 0x00000000;
284
285     v3_lock_init(&(apic->lock));
286 }
287
288
289
290
291 static int read_apic_msr(struct guest_info * core, uint_t msr, v3_msr_t * dst, void * priv_data) {
292     struct apic_dev_state * apic_dev = (struct apic_dev_state *)priv_data;
293     struct apic_state * apic = &(apic_dev->apics[core->cpu_id]);
294
295     PrintDebug("apic %u: core %u: MSR read\n", apic->lapic_id.val, core->cpu_id);
296     v3_lock(apic->lock);
297     dst->value = apic->base_addr;
298     v3_unlock(apic->lock);
299     return 0;
300 }
301
302
303 static int write_apic_msr(struct guest_info * core, uint_t msr, v3_msr_t src, void * priv_data) {
304     struct apic_dev_state * apic_dev = (struct apic_dev_state *)priv_data;
305     struct apic_state * apic = &(apic_dev->apics[core->cpu_id]);
306     struct v3_mem_region * old_reg = v3_get_mem_region(core->vm_info, core->cpu_id, apic->base_addr);
307
308
309     PrintDebug("apic %u: core %u: MSR write\n", apic->lapic_id.val, core->cpu_id);
310
311     if (old_reg == NULL) {
312         // uh oh...
313         PrintError("apic %u: core %u: APIC Base address region does not exit...\n",
314                    apic->lapic_id.val, core->cpu_id);
315         return -1;
316     }
317     
318     v3_lock(apic->lock);
319
320     v3_delete_mem_region(core->vm_info, old_reg);
321
322     apic->base_addr = src.value;
323
324     if (v3_hook_full_mem(core->vm_info, core->cpu_id, apic->base_addr, 
325                          apic->base_addr + PAGE_SIZE_4KB, 
326                          apic_read, apic_write, apic_dev) == -1) {
327         PrintError("apic %u: core %u: Could not hook new APIC Base address\n",
328                    apic->lapic_id.val, core->cpu_id);
329         v3_unlock(apic->lock);
330         return -1;
331     }
332
333     v3_unlock(apic->lock);
334     return 0;
335 }
336
337
338 // irq_num is the bit offset into a 256 bit buffer...
339 static int activate_apic_irq(struct apic_state * apic, uint32_t irq_num) {
340     int major_offset = (irq_num & ~0x00000007) >> 3;
341     int minor_offset = irq_num & 0x00000007;
342     uint8_t * req_location = apic->int_req_reg + major_offset;
343     uint8_t * en_location = apic->int_en_reg + major_offset;
344     uint8_t flag = 0x1 << minor_offset;
345
346
347
348     if (irq_num <= 15) {
349         PrintError("apic %u: core %d: Attempting to raise an invalid interrupt: %d\n", 
350                    apic->lapic_id.val, apic->core->cpu_id, irq_num);
351         return -1;
352     }
353
354
355     PrintDebug("apic %u: core %d: Raising APIC IRQ %d\n", apic->lapic_id.val, apic->core->cpu_id, irq_num);
356
357     if (*req_location & flag) {
358         PrintDebug("Interrupt %d  coallescing\n", irq_num);
359     }
360
361     if (*en_location & flag) {
362         *req_location |= flag;
363     } else {
364         PrintDebug("apic %u: core %d: Interrupt  not enabled... %.2x\n", 
365                    apic->lapic_id.val, apic->core->cpu_id,*en_location);
366         return 0;
367     }
368
369     return 0;
370 }
371
372
373
374 static int get_highest_isr(struct apic_state * apic) {
375     int i = 0, j = 0;
376
377     // We iterate backwards to find the highest priority
378     for (i = 31; i >= 0; i--) {
379         uint8_t  * svc_major = apic->int_svc_reg + i;
380     
381         if ((*svc_major) & 0xff) {
382             for (j = 7; j >= 0; j--) {
383                 uint8_t flag = 0x1 << j;
384                 if ((*svc_major) & flag) {
385                     return ((i * 8) + j);
386                 }
387             }
388         }
389     }
390
391     return -1;
392 }
393  
394
395
396 static int get_highest_irr(struct apic_state * apic) {
397     int i = 0, j = 0;
398
399     // We iterate backwards to find the highest priority
400     for (i = 31; i >= 0; i--) {
401         uint8_t  * req_major = apic->int_req_reg + i;
402     
403         if ((*req_major) & 0xff) {
404             for (j = 7; j >= 0; j--) {
405                 uint8_t flag = 0x1 << j;
406                 if ((*req_major) & flag) {
407                     return ((i * 8) + j);
408                 }
409             }
410         }
411     }
412
413     return -1;
414 }
415  
416
417
418
419 static int apic_do_eoi(struct apic_state * apic) {
420     int isr_irq = get_highest_isr(apic);
421
422     if (isr_irq != -1) {
423         int major_offset = (isr_irq & ~0x00000007) >> 3;
424         int minor_offset = isr_irq & 0x00000007;
425         uint8_t flag = 0x1 << minor_offset;
426         uint8_t * svc_location = apic->int_svc_reg + major_offset;
427         
428         PrintDebug("apic %u: core ?: Received APIC EOI for IRQ %d\n", apic->lapic_id.val,isr_irq);
429         
430         *svc_location &= ~flag;
431
432 #ifdef CONFIG_CRAY_XT
433         
434         if ((isr_irq == 238) || 
435             (isr_irq == 239)) {
436             PrintDebug("apic %u: core ?: Acking IRQ %d\n", apic->lapic_id.val,isr_irq);
437         }
438         
439         if (isr_irq == 238) {
440             V3_ACK_IRQ(238);
441         }
442 #endif
443     } else {
444         //PrintError("apic %u: core ?: Spurious EOI...\n",apic->lapic_id.val);
445     }
446         
447     return 0;
448 }
449  
450
451 static int activate_internal_irq(struct apic_state * apic, apic_irq_type_t int_type) {
452     uint32_t vec_num = 0;
453     uint32_t del_mode = 0;
454     int masked = 0;
455
456
457     switch (int_type) {
458         case APIC_TMR_INT:
459             vec_num = apic->tmr_vec_tbl.vec;
460             del_mode = APIC_FIXED_DELIVERY;
461             masked = apic->tmr_vec_tbl.mask;
462             break;
463         case APIC_THERM_INT:
464             vec_num = apic->therm_loc_vec_tbl.vec;
465             del_mode = apic->therm_loc_vec_tbl.msg_type;
466             masked = apic->therm_loc_vec_tbl.mask;
467             break;
468         case APIC_PERF_INT:
469             vec_num = apic->perf_ctr_loc_vec_tbl.vec;
470             del_mode = apic->perf_ctr_loc_vec_tbl.msg_type;
471             masked = apic->perf_ctr_loc_vec_tbl.mask;
472             break;
473         case APIC_LINT0_INT:
474             vec_num = apic->lint0_vec_tbl.vec;
475             del_mode = apic->lint0_vec_tbl.msg_type;
476             masked = apic->lint0_vec_tbl.mask;
477             break;
478         case APIC_LINT1_INT:
479             vec_num = apic->lint1_vec_tbl.vec;
480             del_mode = apic->lint1_vec_tbl.msg_type;
481             masked = apic->lint1_vec_tbl.mask;
482             break;
483         case APIC_ERR_INT:
484             vec_num = apic->err_vec_tbl.vec;
485             del_mode = APIC_FIXED_DELIVERY;
486             masked = apic->err_vec_tbl.mask;
487             break;
488         default:
489             PrintError("apic %u: core ?: Invalid APIC interrupt type\n", apic->lapic_id.val);
490             return -1;
491     }
492
493     // interrupt is masked, don't send
494     if (masked == 1) {
495         PrintDebug("apic %u: core ?: Inerrupt is masked\n", apic->lapic_id.val);
496         return 0;
497     }
498
499     if (del_mode == APIC_FIXED_DELIVERY) {
500         //PrintDebug("Activating internal APIC IRQ %d\n", vec_num);
501         return activate_apic_irq(apic, vec_num);
502     } else {
503         PrintError("apic %u: core ?: Unhandled Delivery Mode\n", apic->lapic_id.val);
504         return -1;
505     }
506 }
507
508
509
510 static inline int should_deliver_cluster_ipi(struct guest_info * dst_core, 
511                                              struct apic_state * dst_apic, uint8_t mda) {
512
513     if  ( ((mda & 0xf0) == (dst_apic->log_dst.dst_log_id & 0xf0)) &&     // (I am in the cluster and
514           ((mda & 0x0f) & (dst_apic->log_dst.dst_log_id & 0x0f)) ) {  //  I am in the set)
515
516         PrintDebug("apic %u core %u: accepting clustered IRQ (mda 0x%x == log_dst 0x%x)\n",
517                    dst_apic->lapic_id.val, dst_core->cpu_id, mda, 
518                    dst_apic->log_dst.dst_log_id);
519         
520         return 1;
521     } else {
522         PrintDebug("apic %u core %u: rejecting clustered IRQ (mda 0x%x != log_dst 0x%x)\n",
523                    dst_apic->lapic_id.val, dst_core->cpu_id, mda, 
524                    dst_apic->log_dst.dst_log_id);
525         return 0;
526     }
527 }
528
529 static inline int should_deliver_flat_ipi(struct guest_info * dst_core,
530                                           struct apic_state * dst_apic, uint8_t mda) {
531
532     if (dst_apic->log_dst.dst_log_id & mda) {  // I am in the set 
533
534         PrintDebug("apic %u core %u: accepting flat IRQ (mda 0x%x == log_dst 0x%x)\n",
535                    dst_apic->lapic_id.val, dst_core->cpu_id, mda, 
536                    dst_apic->log_dst.dst_log_id);
537       return 1;
538   } else {
539         PrintDebug("apic %u core %u: rejecting flat IRQ (mda 0x%x != log_dst 0x%x)\n",
540                    dst_apic->lapic_id.val, dst_core->cpu_id, mda, 
541                    dst_apic->log_dst.dst_log_id);
542       return 0;
543   }
544 }
545
546
547
548 static int should_deliver_ipi(struct guest_info * dst_core, 
549                               struct apic_state * dst_apic, uint8_t mda) {
550
551
552     if (dst_apic->dst_fmt.model == 0xf) {
553
554         if (mda == 0xff) {
555             // always deliver broadcast
556             return 1;
557         }
558
559         return should_deliver_flat_ipi(dst_core, dst_apic, mda);
560     } else if (dst_apic->dst_fmt.model == 0x0) {
561
562         if (mda == 0xff) {
563             // always deliver broadcast
564             return 1;
565         }
566
567         return should_deliver_cluster_ipi(dst_core, dst_apic, mda);
568     } else {
569         PrintError("apic %u core %u: invalid destination format register value 0x%x for logical mode delivery.\n", 
570                    dst_apic->lapic_id.val, dst_core->cpu_id, dst_apic->dst_fmt.model);
571         return -1;
572     }
573 }
574
575
576 static int deliver_ipi(struct apic_state * src_apic, 
577                        struct apic_state * dst_apic, 
578                        uint32_t vector, uint8_t del_mode) {
579
580     struct guest_info * dst_core = dst_apic->core;
581
582     switch (del_mode) {
583
584         case 0:  //fixed
585         case 1: // lowest priority
586             PrintDebug("delivering IRQ %d to core %u\n", vector, dst_core->cpu_id); 
587
588             activate_apic_irq(dst_apic, vector);
589
590             if (dst_apic != src_apic) { 
591                 // Assume core # is same as logical processor for now
592                 // TODO FIX THIS FIX THIS
593                 // THERE SHOULD BE:  guestapicid->virtualapicid map,
594                 //                   cpu_id->logical processor map
595                 //     host maitains logical proc->phsysical proc
596                 PrintDebug(" non-local core, forcing it to exit\n"); 
597
598                 v3_interrupt_cpu(dst_core->vm_info, dst_core->cpu_id, 0);
599             }
600
601             break;
602         case 5: { //INIT
603
604             PrintDebug(" INIT delivery to core %u\n", dst_core->cpu_id);
605
606             // TODO: any APIC reset on dest core (shouldn't be needed, but not sure...)
607
608             // Sanity check
609             if (dst_apic->ipi_state != INIT_ST) { 
610                 PrintError(" Warning: core %u is not in INIT state (mode = %d), ignored\n",
611                            dst_core->cpu_id, dst_apic->ipi_state);
612                 // Only a warning, since INIT INIT SIPI is common
613                 break;
614             }
615
616             // We transition the target core to SIPI state
617             dst_apic->ipi_state = SIPI;  // note: locking should not be needed here
618
619             // That should be it since the target core should be
620             // waiting in host on this transition
621             // either it's on another core or on a different preemptive thread
622             // in both cases, it will quickly notice this transition 
623             // in particular, we should not need to force an exit here
624
625             PrintDebug(" INIT delivery done\n");
626
627             break;                                                      
628         }
629         case 6: { //SIPI
630
631             // Sanity check
632             if (dst_apic->ipi_state != SIPI) { 
633                 PrintError(" core %u is not in SIPI state (mode = %d), ignored!\n",
634                            dst_core->cpu_id, dst_apic->ipi_state);
635                 break;
636             }
637
638             // Write the RIP, CS, and descriptor
639             // assume the rest is already good to go
640             //
641             // vector VV -> rip at 0
642             //              CS = VV00
643             //  This means we start executing at linear address VV000
644             //
645             // So the selector needs to be VV00
646             // and the base needs to be VV000
647             //
648             dst_core->rip = 0;
649             dst_core->segments.cs.selector = vector << 8;
650             dst_core->segments.cs.limit = 0xffff;
651             dst_core->segments.cs.base = vector << 12;
652
653             PrintDebug(" SIPI delivery (0x%x -> 0x%x:0x0) to core %u\n",
654                        vector, dst_core->segments.cs.selector, dst_core->cpu_id);
655             // Maybe need to adjust the APIC?
656             
657             // We transition the target core to SIPI state
658             dst_core->core_run_state = CORE_RUNNING;  // note: locking should not be needed here
659             dst_apic->ipi_state = STARTED;
660
661             // As with INIT, we should not need to do anything else
662
663             PrintDebug(" SIPI delivery done\n");
664
665             break;                                                      
666         }
667         case 2: // SMI                  
668         case 3: // reserved                                             
669         case 4: // NMI                                  
670         case 7: // ExtInt
671         default:
672             PrintError("IPI %d delivery is unsupported\n", del_mode); 
673             return -1;
674     }
675
676     return 0;
677
678 }
679
680
681 static int route_ipi(struct apic_dev_state * apic_dev,
682                      struct apic_state * src_apic, 
683                      struct int_cmd_reg * icr) {
684     struct apic_state * dest_apic = NULL;
685
686     PrintDebug("route_ipi: src_apic=%p, icr_data=%p\n", 
687                src_apic, (void *)(addr_t)icr->val);
688
689
690     if ((icr->dst_mode == 0) && (icr->dst >= apic_dev->num_apics)) { 
691         PrintError("route_ipi: Attempted send to unregistered apic id=%u\n", 
692                    icr->dst);
693         return -1;
694     }
695
696     dest_apic =  &(apic_dev->apics[icr->dst]);
697
698
699     PrintDebug("route_ipi: IPI %s %u from apic %p to %s %s %u (icr=0x%llx)\n",
700                deliverymode_str[icr->del_mode], 
701                icr->vec, 
702                src_apic,               
703                (icr->dst_mode == 0) ? "(physical)" : "(logical)", 
704                shorthand_str[icr->dst_shorthand], 
705                icr->dst,
706                icr->val);
707
708     switch (icr->dst_shorthand) {
709
710         case 0:  // no shorthand
711             if (icr->dst_mode == 0) { 
712                 // physical delivery
713
714                 if (deliver_ipi(src_apic, dest_apic, 
715                                 icr->vec, icr->del_mode) == -1) {
716                     PrintError("Error: Could not deliver IPI\n");
717                     return -1;
718                 }
719
720             } else {
721                 // logical delivery
722                 int i;
723                 uint8_t mda = icr->dst;
724
725                 for (i = 0; i < apic_dev->num_apics; i++) { 
726                      dest_apic = &(apic_dev->apics[i]);
727                      int del_flag = should_deliver_ipi(dest_apic->core, dest_apic, mda);
728                      
729                      if (del_flag == -1) {
730                          PrintError("Error checking delivery mode\n");
731                          return -1;
732                      } else if (del_flag == 1) {
733                         if (deliver_ipi(src_apic, dest_apic, 
734                                         icr->vec, icr->del_mode) == -1) {
735                             PrintError("Error: Could not deliver IPI\n");
736                             return -1;
737                         }
738                     }
739                 }
740             }
741             
742             break;
743             
744         case 1:  // self
745
746             if (src_apic == NULL) {
747                 PrintError("Sending IPI to self from generic IPI sender\n");
748                 break;
749             }
750
751             if (icr->dst_mode == 0) { 
752                 if (deliver_ipi(src_apic, src_apic, icr->vec, icr->del_mode) == -1) {
753                     PrintError("Could not deliver IPI\n");
754                     return -1;
755                 }
756             } else {
757                 // logical delivery
758                 PrintError("use of logical delivery in self is not yet supported.\n");
759                 return -1;
760             }
761             break;
762             
763         case 2: 
764         case 3: { // all and all-but-me
765             // assuming that logical verus physical doesn't matter
766             // although it is odd that both are used
767             int i;
768
769             for (i = 0; i < apic_dev->num_apics; i++) { 
770                 dest_apic = &(apic_dev->apics[i]);
771
772                 if ((dest_apic != src_apic) || (icr->dst_shorthand == 2)) { 
773                     if (deliver_ipi(src_apic, dest_apic, icr->vec, icr->del_mode) == -1) {
774                         PrintError("Error: Could not deliver IPI\n");
775                         return -1;
776                     }
777                 }
778             }   
779
780             break;
781         }
782         default:
783             PrintError("Error routing IPI, invalid Mode (%d)\n", icr->dst_shorthand);
784             return -1;
785     }
786     
787
788     return 0;
789 }
790
791
792
793 static int apic_read(struct guest_info * core, addr_t guest_addr, void * dst, uint_t length, void * priv_data) {
794     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(priv_data);
795     struct apic_state * apic = &(apic_dev->apics[core->cpu_id]);
796     addr_t reg_addr  = guest_addr - apic->base_addr;
797     struct apic_msr * msr = (struct apic_msr *)&(apic->base_addr_msr.value);
798     uint32_t val = 0;
799
800
801     PrintDebug("apic %u: core %u: at %p: Read apic address space (%p)\n",
802                apic->lapic_id.val, core->cpu_id, apic, (void *)guest_addr);
803
804     if (msr->apic_enable == 0) {
805         PrintError("apic %u: core %u: Read from APIC address space with disabled APIC, apic msr=0x%llx\n",
806                    apic->lapic_id.val, core->cpu_id, apic->base_addr_msr.value);
807
808         return -1;
809     }
810
811
812     /* Because "May not be supported" doesn't matter to Linux developers... */
813     /*   if (length != 4) { */
814     /*     PrintError("Invalid apic read length (%d)\n", length); */
815     /*     return -1; */
816     /*   } */
817
818     switch (reg_addr & ~0x3) {
819         case EOI_OFFSET:
820             // Well, only an idiot would read from a architectural write only register
821             // Oh, Hello Linux.
822             //    PrintError("Attempting to read from write only register\n");
823             //    return -1;
824             break;
825
826             // data registers
827         case APIC_ID_OFFSET:
828             val = apic->lapic_id.val;
829             break;
830         case APIC_VERSION_OFFSET:
831             val = apic->apic_ver.val;
832             break;
833         case TPR_OFFSET:
834             val = apic->task_prio.val;
835             break;
836         case APR_OFFSET:
837             val = apic->arb_prio.val;
838             break;
839         case PPR_OFFSET:
840             val = apic->proc_prio.val;
841             break;
842         case REMOTE_READ_OFFSET:
843             val = apic->rem_rd_data;
844             break;
845         case LDR_OFFSET:
846             val = apic->log_dst.val;
847             break;
848         case DFR_OFFSET:
849             val = apic->dst_fmt.val;
850             break;
851         case SPURIOUS_INT_VEC_OFFSET:
852             val = apic->spurious_int.val;
853             break;
854         case ESR_OFFSET:
855             val = apic->err_status.val;
856             break;
857         case TMR_LOC_VEC_TBL_OFFSET:
858             val = apic->tmr_vec_tbl.val;
859             break;
860         case LINT0_VEC_TBL_OFFSET:
861             val = apic->lint0_vec_tbl.val;
862             break;
863         case LINT1_VEC_TBL_OFFSET:
864             val = apic->lint1_vec_tbl.val;
865             break;
866         case ERR_VEC_TBL_OFFSET:
867             val = apic->err_vec_tbl.val;
868             break;
869         case TMR_INIT_CNT_OFFSET:
870             val = apic->tmr_init_cnt;
871             break;
872         case TMR_DIV_CFG_OFFSET:
873             val = apic->tmr_div_cfg.val;
874             break;
875
876         case IER_OFFSET0:
877             val = *(uint32_t *)(apic->int_en_reg);
878             break;
879         case IER_OFFSET1:
880             val = *(uint32_t *)(apic->int_en_reg + 4);
881             break;
882         case IER_OFFSET2:
883             val = *(uint32_t *)(apic->int_en_reg + 8);
884             break;
885         case IER_OFFSET3:
886             val = *(uint32_t *)(apic->int_en_reg + 12);
887             break;
888         case IER_OFFSET4:
889             val = *(uint32_t *)(apic->int_en_reg + 16);
890             break;
891         case IER_OFFSET5:
892             val = *(uint32_t *)(apic->int_en_reg + 20);
893             break;
894         case IER_OFFSET6:
895             val = *(uint32_t *)(apic->int_en_reg + 24);
896             break;
897         case IER_OFFSET7:
898             val = *(uint32_t *)(apic->int_en_reg + 28);
899             break;
900
901         case ISR_OFFSET0:
902             val = *(uint32_t *)(apic->int_svc_reg);
903             break;
904         case ISR_OFFSET1:
905             val = *(uint32_t *)(apic->int_svc_reg + 4);
906             break;
907         case ISR_OFFSET2:
908             val = *(uint32_t *)(apic->int_svc_reg + 8);
909             break;
910         case ISR_OFFSET3:
911             val = *(uint32_t *)(apic->int_svc_reg + 12);
912             break;
913         case ISR_OFFSET4:
914             val = *(uint32_t *)(apic->int_svc_reg + 16);
915             break;
916         case ISR_OFFSET5:
917             val = *(uint32_t *)(apic->int_svc_reg + 20);
918             break;
919         case ISR_OFFSET6:
920             val = *(uint32_t *)(apic->int_svc_reg + 24);
921             break;
922         case ISR_OFFSET7:
923             val = *(uint32_t *)(apic->int_svc_reg + 28);
924             break;
925    
926         case TRIG_OFFSET0:
927             val = *(uint32_t *)(apic->trig_mode_reg);
928             break;
929         case TRIG_OFFSET1:
930             val = *(uint32_t *)(apic->trig_mode_reg + 4);
931             break;
932         case TRIG_OFFSET2:
933             val = *(uint32_t *)(apic->trig_mode_reg + 8);
934             break;
935         case TRIG_OFFSET3:
936             val = *(uint32_t *)(apic->trig_mode_reg + 12);
937             break;
938         case TRIG_OFFSET4:
939             val = *(uint32_t *)(apic->trig_mode_reg + 16);
940             break;
941         case TRIG_OFFSET5:
942             val = *(uint32_t *)(apic->trig_mode_reg + 20);
943             break;
944         case TRIG_OFFSET6:
945             val = *(uint32_t *)(apic->trig_mode_reg + 24);
946             break;
947         case TRIG_OFFSET7:
948             val = *(uint32_t *)(apic->trig_mode_reg + 28);
949             break;
950
951         case IRR_OFFSET0:
952             val = *(uint32_t *)(apic->int_req_reg);
953             break;
954         case IRR_OFFSET1:
955             val = *(uint32_t *)(apic->int_req_reg + 4);
956             break;
957         case IRR_OFFSET2:
958             val = *(uint32_t *)(apic->int_req_reg + 8);
959             break;
960         case IRR_OFFSET3:
961             val = *(uint32_t *)(apic->int_req_reg + 12);
962             break;
963         case IRR_OFFSET4:
964             val = *(uint32_t *)(apic->int_req_reg + 16);
965             break;
966         case IRR_OFFSET5:
967             val = *(uint32_t *)(apic->int_req_reg + 20);
968             break;
969         case IRR_OFFSET6:
970             val = *(uint32_t *)(apic->int_req_reg + 24);
971             break;
972         case IRR_OFFSET7:
973             val = *(uint32_t *)(apic->int_req_reg + 28);
974             break;
975         case TMR_CUR_CNT_OFFSET:
976             val = apic->tmr_cur_cnt;
977             break;
978
979             // We are not going to implement these....
980         case THERM_LOC_VEC_TBL_OFFSET:
981             val = apic->therm_loc_vec_tbl.val;
982             break;
983         case PERF_CTR_LOC_VEC_TBL_OFFSET:
984             val = apic->perf_ctr_loc_vec_tbl.val;
985             break;
986
987  
988
989             // handled registers
990         case INT_CMD_LO_OFFSET:    
991             val = apic->int_cmd.lo;
992             break;
993         case INT_CMD_HI_OFFSET:
994             val = apic->int_cmd.hi;
995             break;
996
997             // handle current timer count
998
999             // Unhandled Registers
1000         case EXT_INT_LOC_VEC_TBL_OFFSET0:
1001             val = apic->ext_intr_vec_tbl[0].val;
1002             break;
1003         case EXT_INT_LOC_VEC_TBL_OFFSET1:
1004             val = apic->ext_intr_vec_tbl[1].val;
1005             break;
1006         case EXT_INT_LOC_VEC_TBL_OFFSET2:
1007             val = apic->ext_intr_vec_tbl[2].val;
1008             break;
1009         case EXT_INT_LOC_VEC_TBL_OFFSET3:
1010             val = apic->ext_intr_vec_tbl[3].val;
1011             break;
1012     
1013
1014         case EXT_APIC_FEATURE_OFFSET:
1015         case EXT_APIC_CMD_OFFSET:
1016         case SEOI_OFFSET:
1017
1018         default:
1019             PrintError("apic %u: core %u: Read from Unhandled APIC Register: %x (getting zero)\n", 
1020                        apic->lapic_id.val, core->cpu_id, (uint32_t)reg_addr);
1021             return -1;
1022     }
1023
1024
1025     if (length == 1) {
1026         uint_t byte_addr = reg_addr & 0x3;
1027         uint8_t * val_ptr = (uint8_t *)dst;
1028     
1029         *val_ptr = *(((uint8_t *)&val) + byte_addr);
1030
1031     } else if ((length == 2) && 
1032                ((reg_addr & 0x3) == 0x3)) {
1033         uint_t byte_addr = reg_addr & 0x3;
1034         uint16_t * val_ptr = (uint16_t *)dst;
1035         *val_ptr = *(((uint16_t *)&val) + byte_addr);
1036
1037     } else if (length == 4) {
1038         uint32_t * val_ptr = (uint32_t *)dst;
1039         *val_ptr = val;
1040
1041     } else {
1042         PrintError("apic %u: core %u: Invalid apic read length (%d)\n", 
1043                    apic->lapic_id.val, core->cpu_id, length);
1044         return -1;
1045     }
1046
1047     PrintDebug("apic %u: core %u: Read finished (val=%x)\n", 
1048                apic->lapic_id.val, core->cpu_id, *(uint32_t *)dst);
1049
1050     return length;
1051 }
1052
1053
1054 /**
1055  *
1056  */
1057 static int apic_write(struct guest_info * core, addr_t guest_addr, void * src, uint_t length, void * priv_data) {
1058     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(priv_data);
1059     struct apic_state * apic = &(apic_dev->apics[core->cpu_id]); 
1060     addr_t reg_addr  = guest_addr - apic->base_addr;
1061     struct apic_msr * msr = (struct apic_msr *)&(apic->base_addr_msr.value);
1062     uint32_t op_val = *(uint32_t *)src;
1063
1064     PrintDebug("apic %u: core %u: at %p and priv_data is at %p\n",
1065                apic->lapic_id.val, core->cpu_id, apic, priv_data);
1066
1067     PrintDebug("apic %u: core %u: write to address space (%p) (val=%x)\n", 
1068                apic->lapic_id.val, core->cpu_id, (void *)guest_addr, *(uint32_t *)src);
1069
1070     if (msr->apic_enable == 0) {
1071         PrintError("apic %u: core %u: Write to APIC address space with disabled APIC, apic msr=0x%llx\n",
1072                    apic->lapic_id.val, core->cpu_id, apic->base_addr_msr.value);
1073         return -1;
1074     }
1075
1076
1077     if (length != 4) {
1078         PrintError("apic %u: core %u: Invalid apic write length (%d)\n", 
1079                    apic->lapic_id.val, length, core->cpu_id);
1080         return -1;
1081     }
1082
1083     switch (reg_addr) {
1084         case REMOTE_READ_OFFSET:
1085         case APIC_VERSION_OFFSET:
1086         case APR_OFFSET:
1087         case IRR_OFFSET0:
1088         case IRR_OFFSET1:
1089         case IRR_OFFSET2:
1090         case IRR_OFFSET3:
1091         case IRR_OFFSET4:
1092         case IRR_OFFSET5:
1093         case IRR_OFFSET6:
1094         case IRR_OFFSET7:
1095         case ISR_OFFSET0:
1096         case ISR_OFFSET1:
1097         case ISR_OFFSET2:
1098         case ISR_OFFSET3:
1099         case ISR_OFFSET4:
1100         case ISR_OFFSET5:
1101         case ISR_OFFSET6:
1102         case ISR_OFFSET7:
1103         case TRIG_OFFSET0:
1104         case TRIG_OFFSET1:
1105         case TRIG_OFFSET2:
1106         case TRIG_OFFSET3:
1107         case TRIG_OFFSET4:
1108         case TRIG_OFFSET5:
1109         case TRIG_OFFSET6:
1110         case TRIG_OFFSET7:
1111         case PPR_OFFSET:
1112         case EXT_APIC_FEATURE_OFFSET:
1113
1114             PrintError("apic %u: core %u: Attempting to write to read only register %p (error)\n", 
1115                        apic->lapic_id.val, core->cpu_id, (void *)reg_addr);
1116             //  return -1;
1117
1118             break;
1119
1120             // Data registers
1121         case APIC_ID_OFFSET:
1122             PrintDebug("apic %u: core %u: my id is being changed to %u\n", 
1123                        apic->lapic_id.val, core->cpu_id, op_val);
1124
1125             apic->lapic_id.val = op_val;
1126             break;
1127         case TPR_OFFSET:
1128             apic->task_prio.val = op_val;
1129             break;
1130         case LDR_OFFSET:
1131             PrintDebug("apic %u: core %u: setting log_dst.val to 0x%x\n",
1132                        apic->lapic_id.val, core->cpu_id, op_val);
1133             apic->log_dst.val = op_val;
1134             break;
1135         case DFR_OFFSET:
1136             apic->dst_fmt.val = op_val;
1137             break;
1138         case SPURIOUS_INT_VEC_OFFSET:
1139             apic->spurious_int.val = op_val;
1140             break;
1141         case ESR_OFFSET:
1142             apic->err_status.val = op_val;
1143             break;
1144         case TMR_LOC_VEC_TBL_OFFSET:
1145             apic->tmr_vec_tbl.val = op_val;
1146             break;
1147         case THERM_LOC_VEC_TBL_OFFSET:
1148             apic->therm_loc_vec_tbl.val = op_val;
1149             break;
1150         case PERF_CTR_LOC_VEC_TBL_OFFSET:
1151             apic->perf_ctr_loc_vec_tbl.val = op_val;
1152             break;
1153         case LINT0_VEC_TBL_OFFSET:
1154             apic->lint0_vec_tbl.val = op_val;
1155             break;
1156         case LINT1_VEC_TBL_OFFSET:
1157             apic->lint1_vec_tbl.val = op_val;
1158             break;
1159         case ERR_VEC_TBL_OFFSET:
1160             apic->err_vec_tbl.val = op_val;
1161             break;
1162         case TMR_INIT_CNT_OFFSET:
1163             apic->tmr_init_cnt = op_val;
1164             apic->tmr_cur_cnt = op_val;
1165             break;
1166         case TMR_CUR_CNT_OFFSET:
1167             apic->tmr_cur_cnt = op_val;
1168             break;
1169         case TMR_DIV_CFG_OFFSET:
1170             apic->tmr_div_cfg.val = op_val;
1171             break;
1172
1173
1174             // Enable mask (256 bits)
1175         case IER_OFFSET0:
1176             *(uint32_t *)(apic->int_en_reg) = op_val;
1177             break;
1178         case IER_OFFSET1:
1179             *(uint32_t *)(apic->int_en_reg + 4) = op_val;
1180             break;
1181         case IER_OFFSET2:
1182             *(uint32_t *)(apic->int_en_reg + 8) = op_val;
1183             break;
1184         case IER_OFFSET3:
1185             *(uint32_t *)(apic->int_en_reg + 12) = op_val;
1186             break;
1187         case IER_OFFSET4:
1188             *(uint32_t *)(apic->int_en_reg + 16) = op_val;
1189             break;
1190         case IER_OFFSET5:
1191             *(uint32_t *)(apic->int_en_reg + 20) = op_val;
1192             break;
1193         case IER_OFFSET6:
1194             *(uint32_t *)(apic->int_en_reg + 24) = op_val;
1195             break;
1196         case IER_OFFSET7:
1197             *(uint32_t *)(apic->int_en_reg + 28) = op_val;
1198             break;
1199
1200         case EXT_INT_LOC_VEC_TBL_OFFSET0:
1201             apic->ext_intr_vec_tbl[0].val = op_val;
1202             break;
1203         case EXT_INT_LOC_VEC_TBL_OFFSET1:
1204             apic->ext_intr_vec_tbl[1].val = op_val;
1205             break;
1206         case EXT_INT_LOC_VEC_TBL_OFFSET2:
1207             apic->ext_intr_vec_tbl[2].val = op_val;
1208             break;
1209         case EXT_INT_LOC_VEC_TBL_OFFSET3:
1210             apic->ext_intr_vec_tbl[3].val = op_val;
1211             break;
1212
1213
1214             // Action Registers
1215         case EOI_OFFSET:
1216             // do eoi
1217             apic_do_eoi(apic);
1218             break;
1219
1220         case INT_CMD_LO_OFFSET:
1221             apic->int_cmd.lo = op_val;
1222
1223             PrintDebug("apic %u: core %u: sending cmd 0x%llx to apic %u\n", 
1224                        apic->lapic_id.val, core->cpu_id,
1225                        apic->int_cmd.val, apic->int_cmd.dst);
1226
1227             if (route_ipi(apic_dev, apic, &(apic->int_cmd)) == -1) { 
1228                 PrintError("IPI Routing failure\n");
1229                 return -1;
1230             }
1231
1232             break;
1233
1234         case INT_CMD_HI_OFFSET:
1235             apic->int_cmd.hi = op_val;
1236             break;
1237
1238
1239         // Unhandled Registers
1240         case EXT_APIC_CMD_OFFSET:
1241         case SEOI_OFFSET:
1242         default:
1243             PrintError("apic %u: core %u: Write to Unhandled APIC Register: %x (ignored)\n", 
1244                        apic->lapic_id.val, core->cpu_id, (uint32_t)reg_addr);
1245
1246             return -1;
1247     }
1248
1249     PrintDebug("apic %u: core %u: Write finished\n", apic->lapic_id.val, core->cpu_id);
1250
1251     return length;
1252 }
1253
1254
1255
1256 /* Interrupt Controller Functions */
1257
1258 // returns 1 if an interrupt is pending, 0 otherwise
1259 static int apic_intr_pending(struct guest_info * core, void * private_data) {
1260     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(private_data);
1261     struct apic_state * apic = &(apic_dev->apics[core->cpu_id]); 
1262     int req_irq = get_highest_irr(apic);
1263     int svc_irq = get_highest_isr(apic);
1264
1265     //    PrintDebug("apic %u: core %u: req_irq=%d, svc_irq=%d\n",apic->lapic_id.val,info->cpu_id,req_irq,svc_irq);
1266
1267     if ((req_irq >= 0) && 
1268         (req_irq > svc_irq)) {
1269         return 1;
1270     }
1271
1272     return 0;
1273 }
1274
1275 static int apic_get_intr_number(struct guest_info * core, void * private_data) {
1276     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(private_data);
1277     struct apic_state * apic = &(apic_dev->apics[core->cpu_id]); 
1278     int req_irq = get_highest_irr(apic);
1279     int svc_irq = get_highest_isr(apic);
1280
1281     if (svc_irq == -1) {
1282         return req_irq;
1283     } else if (svc_irq < req_irq) {
1284         return req_irq;
1285     }
1286
1287     return -1;
1288 }
1289
1290
1291 int v3_apic_send_ipi(struct v3_vm_info * vm, struct vm_device * dev, 
1292                      struct v3_gen_ipi * ipi) {
1293     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(dev->private_data);
1294     struct int_cmd_reg tmp_icr;
1295
1296     // zero out all the fields
1297     tmp_icr.val = 0;
1298
1299
1300     tmp_icr.vec = ipi->vector;
1301     tmp_icr.del_mode = ipi->mode;
1302     tmp_icr.dst_mode = ipi->logical;
1303     tmp_icr.trig_mode = ipi->trigger_mode;
1304     tmp_icr.dst_shorthand = ipi->dst_shorthand;
1305     tmp_icr.dst = ipi->dst;
1306     
1307
1308     return route_ipi(apic_dev, NULL, &tmp_icr);
1309 }
1310
1311
1312 int v3_apic_raise_intr(struct v3_vm_info * vm, struct vm_device * dev, 
1313                        uint32_t irq, uint32_t dst) {
1314     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(dev->private_data);
1315     struct apic_state * apic = &(apic_dev->apics[dst]); 
1316
1317     PrintDebug("apic %u core ?: raising interrupt IRQ %u (dst = %u).\n", apic->lapic_id.val, irq, dst); 
1318
1319     activate_apic_irq(apic, irq);
1320
1321     if (V3_Get_CPU() != dst) {
1322         v3_interrupt_cpu(vm, dst, 0);
1323     }
1324
1325     return 0;
1326 }
1327
1328
1329
1330 static int apic_begin_irq(struct guest_info * core, void * private_data, int irq) {
1331     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(private_data);
1332     struct apic_state * apic = &(apic_dev->apics[core->cpu_id]); 
1333     int major_offset = (irq & ~0x00000007) >> 3;
1334     int minor_offset = irq & 0x00000007;
1335     uint8_t * req_location = apic->int_req_reg + major_offset;
1336     uint8_t * svc_location = apic->int_svc_reg + major_offset;
1337     uint8_t flag = 0x01 << minor_offset;
1338
1339     if (*req_location & flag) {
1340         // we will only pay attention to a begin irq if we
1341         // know that we initiated it!
1342         *svc_location |= flag;
1343         *req_location &= ~flag;
1344     } else {
1345         // do nothing... 
1346         //PrintDebug("apic %u: core %u: begin irq for %d ignored since I don't own it\n",
1347         //         apic->lapic_id.val, core->cpu_id, irq);
1348     }
1349
1350     return 0;
1351 }
1352
1353
1354
1355
1356 /* Timer Functions */
1357 static void apic_update_time(struct guest_info * core, 
1358                              uint64_t cpu_cycles, uint64_t cpu_freq, 
1359                              void * priv_data) {
1360     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(priv_data);
1361     struct apic_state * apic = &(apic_dev->apics[core->cpu_id]); 
1362
1363     // The 32 bit GCC runtime is a pile of shit
1364 #ifdef __V3_64BIT__
1365     uint64_t tmr_ticks = 0;
1366 #else 
1367     uint32_t tmr_ticks = 0;
1368 #endif
1369
1370     uint8_t tmr_div = *(uint8_t *)&(apic->tmr_div_cfg.val);
1371     uint_t shift_num = 0;
1372
1373
1374     // Check whether this is true:
1375     //   -> If the Init count is zero then the timer is disabled
1376     //      and doesn't just blitz interrupts to the CPU
1377     if ((apic->tmr_init_cnt == 0) || 
1378         ( (apic->tmr_vec_tbl.tmr_mode == APIC_TMR_ONESHOT) &&
1379           (apic->tmr_cur_cnt == 0))) {
1380         //PrintDebug("apic %u: core %u: APIC timer not yet initialized\n",apic->lapic_id.val,info->cpu_id);
1381         return;
1382     }
1383
1384
1385     switch (tmr_div) {
1386         case APIC_TMR_DIV1:
1387             shift_num = 0;
1388             break;
1389         case APIC_TMR_DIV2:
1390             shift_num = 1;
1391             break;
1392         case APIC_TMR_DIV4:
1393             shift_num = 2;
1394             break;
1395         case APIC_TMR_DIV8:
1396             shift_num = 3;
1397             break;
1398         case APIC_TMR_DIV16:
1399             shift_num = 4;
1400             break;
1401         case APIC_TMR_DIV32:
1402             shift_num = 5;
1403             break;
1404         case APIC_TMR_DIV64:
1405             shift_num = 6;
1406             break;
1407         case APIC_TMR_DIV128:
1408             shift_num = 7;
1409             break;
1410         default:
1411             PrintError("apic %u: core %u: Invalid Timer Divider configuration\n",
1412                        apic->lapic_id.val, core->cpu_id);
1413             return;
1414     }
1415
1416     tmr_ticks = cpu_cycles >> shift_num;
1417     //    PrintDebug("Timer Ticks: %p\n", (void *)tmr_ticks);
1418
1419     if (tmr_ticks < apic->tmr_cur_cnt) {
1420         apic->tmr_cur_cnt -= tmr_ticks;
1421     } else {
1422         tmr_ticks -= apic->tmr_cur_cnt;
1423         apic->tmr_cur_cnt = 0;
1424
1425         // raise irq
1426         PrintDebug("apic %u: core %u: Raising APIC Timer interrupt (periodic=%d) (icnt=%d) (div=%d)\n",
1427                    apic->lapic_id.val, core->cpu_id,
1428                    apic->tmr_vec_tbl.tmr_mode, apic->tmr_init_cnt, shift_num);
1429
1430         if (apic_intr_pending(core, priv_data)) {
1431             PrintDebug("apic %u: core %u: Overriding pending IRQ %d\n", 
1432                        apic->lapic_id.val, core->cpu_id, 
1433                        apic_get_intr_number(core, priv_data));
1434         }
1435
1436         if (activate_internal_irq(apic, APIC_TMR_INT) == -1) {
1437             PrintError("apic %u: core %u: Could not raise Timer interrupt\n",
1438                        apic->lapic_id.val, core->cpu_id);
1439         }
1440     
1441         if (apic->tmr_vec_tbl.tmr_mode == APIC_TMR_PERIODIC) {
1442             tmr_ticks = tmr_ticks % apic->tmr_init_cnt;
1443             apic->tmr_cur_cnt = apic->tmr_init_cnt - tmr_ticks;
1444         }
1445     }
1446
1447
1448 }
1449
1450
1451 static struct intr_ctrl_ops intr_ops = {
1452     .intr_pending = apic_intr_pending,
1453     .get_intr_number = apic_get_intr_number,
1454     .begin_irq = apic_begin_irq,
1455 };
1456
1457
1458 static struct vm_timer_ops timer_ops = {
1459     .update_timer = apic_update_time,
1460 };
1461
1462
1463
1464
1465 static int apic_free(struct vm_device * dev) {
1466
1467     /* TODO: This should crosscall to force an unhook on each CPU */
1468
1469     //   struct apic_state * apic = (struct apic_state *)dev->private_data;
1470
1471     v3_unhook_msr(dev->vm, BASE_ADDR_MSR);
1472
1473     return 0;
1474 }
1475
1476
1477 static struct v3_device_ops dev_ops = {
1478     .free = apic_free,
1479     .reset = NULL,
1480     .start = NULL,
1481     .stop = NULL,
1482 };
1483
1484
1485
1486
1487
1488 static int apic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
1489     char * dev_id = v3_cfg_val(cfg, "ID");
1490     struct apic_dev_state * apic_dev = NULL;
1491     int i = 0;
1492
1493     PrintDebug("apic: creating an APIC for each core\n");
1494
1495     apic_dev = (struct apic_dev_state *)V3_Malloc(sizeof(struct apic_dev_state) + 
1496                                                   sizeof(struct apic_state) * vm->num_cores);
1497
1498     apic_dev->num_apics = vm->num_cores;
1499
1500     struct vm_device * dev = v3_allocate_device(dev_id, &dev_ops, apic_dev);
1501
1502     if (v3_attach_device(vm, dev) == -1) {
1503         PrintError("apic: Could not attach device %s\n", dev_id);
1504         return -1;
1505     }
1506
1507     
1508     for (i = 0; i < vm->num_cores; i++) {
1509         struct apic_state * apic = &(apic_dev->apics[i]);
1510         struct guest_info * core = &(vm->cores[i]);
1511
1512         apic->core = core;
1513
1514         init_apic_state(apic, i);
1515
1516         v3_register_intr_controller(core, &intr_ops, apic_dev);
1517
1518         v3_add_timer(core, &timer_ops, apic_dev);
1519
1520         v3_hook_full_mem(vm, core->cpu_id, apic->base_addr, apic->base_addr + PAGE_SIZE_4KB, apic_read, apic_write, apic_dev);
1521
1522         PrintDebug("apic %u: (setup device): done, my id is %u\n", i, apic->lapic_id.val);
1523     }
1524
1525 #ifdef CONFIG_DEBUG_APIC
1526     for (i = 0; i < vm->num_cores; i++) {
1527         struct apic_state * apic = &(apic_dev->apics[i]);
1528         PrintDebug("apic: sanity check: apic %u (at %p) has id %u and msr value %llx\n",
1529                    i, apic, apic->lapic_id.val, apic->base_addr_msr.value);
1530     }
1531 #endif
1532
1533
1534     PrintDebug("apic: priv_data is at %p\n", apic_dev);
1535
1536     v3_hook_msr(vm, BASE_ADDR_MSR, read_apic_msr, write_apic_msr, apic_dev);
1537
1538     return 0;
1539 }
1540
1541
1542
1543 device_register("LAPIC", apic_init)