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.


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