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.


Fixed cluster/fixed dst_fmt usage in apic.c; revised default.xml for new APIC change
[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
709     switch (icr->dst_shorthand) {
710
711         case 0:  // no shorthand
712             if (icr->dst_mode == 0) { 
713                 // physical delivery
714
715                 if (deliver_ipi(src_apic, dest_apic, 
716                                 icr->vec, icr->del_mode) == -1) {
717                     PrintError("Error: Could not deliver IPI\n");
718                     return -1;
719                 }
720
721             } else {
722                 // logical delivery
723                 int i;
724                 uint8_t mda = icr->dst;
725
726                 for (i = 0; i < apic_dev->num_apics; i++) { 
727                      dest_apic = &(apic_dev->apics[i]);
728                      int del_flag = should_deliver_ipi(dest_apic->core, dest_apic, mda);
729                      
730                      if (del_flag == -1) {
731                          PrintError("Error checking delivery mode\n");
732                          return -1;
733                      } else if (del_flag == 1) {
734                         if (deliver_ipi(src_apic, dest_apic, 
735                                         icr->vec, icr->del_mode) == -1) {
736                             PrintError("Error: Could not deliver IPI\n");
737                             return -1;
738                         }
739                     }
740                 }
741             }
742             
743             break;
744             
745         case 1:  // self
746
747             if (src_apic == NULL) {
748                 PrintError("Sending IPI to self from generic IPI sender\n");
749                 break;
750             }
751
752             if (icr->dst_mode == 0) { 
753                 if (deliver_ipi(src_apic, src_apic, icr->vec, icr->del_mode) == -1) {
754                     PrintError("Could not deliver IPI\n");
755                     return -1;
756                 }
757             } else {
758                 // logical delivery
759                 PrintError("use of logical delivery in self is not yet supported.\n");
760                 return -1;
761             }
762             break;
763             
764         case 2: 
765         case 3: { // all and all-but-me
766             // assuming that logical verus physical doesn't matter
767             // although it is odd that both are used
768             int i;
769
770             for (i = 0; i < apic_dev->num_apics; i++) { 
771                 dest_apic = &(apic_dev->apics[i]);
772
773                 if ((dest_apic != src_apic) || (icr->dst_shorthand == 2)) { 
774                     if (deliver_ipi(src_apic, dest_apic, icr->vec, icr->del_mode) == -1) {
775                         PrintError("Error: Could not deliver IPI\n");
776                         return -1;
777                     }
778                 }
779             }   
780
781             break;
782         }
783         default:
784             PrintError("Error routing IPI, invalid Mode (%d)\n", icr->dst_shorthand);
785             return -1;
786     }
787     
788
789     return 0;
790 }
791
792
793
794 static int apic_read(struct guest_info * core, addr_t guest_addr, void * dst, uint_t length, void * priv_data) {
795     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(priv_data);
796     struct apic_state * apic = &(apic_dev->apics[core->cpu_id]);
797     addr_t reg_addr  = guest_addr - apic->base_addr;
798     struct apic_msr * msr = (struct apic_msr *)&(apic->base_addr_msr.value);
799     uint32_t val = 0;
800
801
802     PrintDebug("apic %u: core %u: at %p: Read apic address space (%p)\n",
803                apic->lapic_id.val, core->cpu_id, apic, (void *)guest_addr);
804
805     if (msr->apic_enable == 0) {
806         PrintError("apic %u: core %u: Read from APIC address space with disabled APIC, apic msr=0x%llx\n",
807                    apic->lapic_id.val, core->cpu_id, apic->base_addr_msr.value);
808
809         return -1;
810     }
811
812
813     /* Because "May not be supported" doesn't matter to Linux developers... */
814     /*   if (length != 4) { */
815     /*     PrintError("Invalid apic read length (%d)\n", length); */
816     /*     return -1; */
817     /*   } */
818
819     switch (reg_addr & ~0x3) {
820         case EOI_OFFSET:
821             // Well, only an idiot would read from a architectural write only register
822             // Oh, Hello Linux.
823             //    PrintError("Attempting to read from write only register\n");
824             //    return -1;
825             break;
826
827             // data registers
828         case APIC_ID_OFFSET:
829             val = apic->lapic_id.val;
830             break;
831         case APIC_VERSION_OFFSET:
832             val = apic->apic_ver.val;
833             break;
834         case TPR_OFFSET:
835             val = apic->task_prio.val;
836             break;
837         case APR_OFFSET:
838             val = apic->arb_prio.val;
839             break;
840         case PPR_OFFSET:
841             val = apic->proc_prio.val;
842             break;
843         case REMOTE_READ_OFFSET:
844             val = apic->rem_rd_data;
845             break;
846         case LDR_OFFSET:
847             val = apic->log_dst.val;
848             break;
849         case DFR_OFFSET:
850             val = apic->dst_fmt.val;
851             break;
852         case SPURIOUS_INT_VEC_OFFSET:
853             val = apic->spurious_int.val;
854             break;
855         case ESR_OFFSET:
856             val = apic->err_status.val;
857             break;
858         case TMR_LOC_VEC_TBL_OFFSET:
859             val = apic->tmr_vec_tbl.val;
860             break;
861         case LINT0_VEC_TBL_OFFSET:
862             val = apic->lint0_vec_tbl.val;
863             break;
864         case LINT1_VEC_TBL_OFFSET:
865             val = apic->lint1_vec_tbl.val;
866             break;
867         case ERR_VEC_TBL_OFFSET:
868             val = apic->err_vec_tbl.val;
869             break;
870         case TMR_INIT_CNT_OFFSET:
871             val = apic->tmr_init_cnt;
872             break;
873         case TMR_DIV_CFG_OFFSET:
874             val = apic->tmr_div_cfg.val;
875             break;
876
877         case IER_OFFSET0:
878             val = *(uint32_t *)(apic->int_en_reg);
879             break;
880         case IER_OFFSET1:
881             val = *(uint32_t *)(apic->int_en_reg + 4);
882             break;
883         case IER_OFFSET2:
884             val = *(uint32_t *)(apic->int_en_reg + 8);
885             break;
886         case IER_OFFSET3:
887             val = *(uint32_t *)(apic->int_en_reg + 12);
888             break;
889         case IER_OFFSET4:
890             val = *(uint32_t *)(apic->int_en_reg + 16);
891             break;
892         case IER_OFFSET5:
893             val = *(uint32_t *)(apic->int_en_reg + 20);
894             break;
895         case IER_OFFSET6:
896             val = *(uint32_t *)(apic->int_en_reg + 24);
897             break;
898         case IER_OFFSET7:
899             val = *(uint32_t *)(apic->int_en_reg + 28);
900             break;
901
902         case ISR_OFFSET0:
903             val = *(uint32_t *)(apic->int_svc_reg);
904             break;
905         case ISR_OFFSET1:
906             val = *(uint32_t *)(apic->int_svc_reg + 4);
907             break;
908         case ISR_OFFSET2:
909             val = *(uint32_t *)(apic->int_svc_reg + 8);
910             break;
911         case ISR_OFFSET3:
912             val = *(uint32_t *)(apic->int_svc_reg + 12);
913             break;
914         case ISR_OFFSET4:
915             val = *(uint32_t *)(apic->int_svc_reg + 16);
916             break;
917         case ISR_OFFSET5:
918             val = *(uint32_t *)(apic->int_svc_reg + 20);
919             break;
920         case ISR_OFFSET6:
921             val = *(uint32_t *)(apic->int_svc_reg + 24);
922             break;
923         case ISR_OFFSET7:
924             val = *(uint32_t *)(apic->int_svc_reg + 28);
925             break;
926    
927         case TRIG_OFFSET0:
928             val = *(uint32_t *)(apic->trig_mode_reg);
929             break;
930         case TRIG_OFFSET1:
931             val = *(uint32_t *)(apic->trig_mode_reg + 4);
932             break;
933         case TRIG_OFFSET2:
934             val = *(uint32_t *)(apic->trig_mode_reg + 8);
935             break;
936         case TRIG_OFFSET3:
937             val = *(uint32_t *)(apic->trig_mode_reg + 12);
938             break;
939         case TRIG_OFFSET4:
940             val = *(uint32_t *)(apic->trig_mode_reg + 16);
941             break;
942         case TRIG_OFFSET5:
943             val = *(uint32_t *)(apic->trig_mode_reg + 20);
944             break;
945         case TRIG_OFFSET6:
946             val = *(uint32_t *)(apic->trig_mode_reg + 24);
947             break;
948         case TRIG_OFFSET7:
949             val = *(uint32_t *)(apic->trig_mode_reg + 28);
950             break;
951
952         case IRR_OFFSET0:
953             val = *(uint32_t *)(apic->int_req_reg);
954             break;
955         case IRR_OFFSET1:
956             val = *(uint32_t *)(apic->int_req_reg + 4);
957             break;
958         case IRR_OFFSET2:
959             val = *(uint32_t *)(apic->int_req_reg + 8);
960             break;
961         case IRR_OFFSET3:
962             val = *(uint32_t *)(apic->int_req_reg + 12);
963             break;
964         case IRR_OFFSET4:
965             val = *(uint32_t *)(apic->int_req_reg + 16);
966             break;
967         case IRR_OFFSET5:
968             val = *(uint32_t *)(apic->int_req_reg + 20);
969             break;
970         case IRR_OFFSET6:
971             val = *(uint32_t *)(apic->int_req_reg + 24);
972             break;
973         case IRR_OFFSET7:
974             val = *(uint32_t *)(apic->int_req_reg + 28);
975             break;
976         case TMR_CUR_CNT_OFFSET:
977             val = apic->tmr_cur_cnt;
978             break;
979
980             // We are not going to implement these....
981         case THERM_LOC_VEC_TBL_OFFSET:
982             val = apic->therm_loc_vec_tbl.val;
983             break;
984         case PERF_CTR_LOC_VEC_TBL_OFFSET:
985             val = apic->perf_ctr_loc_vec_tbl.val;
986             break;
987
988  
989
990             // handled registers
991         case INT_CMD_LO_OFFSET:    
992             val = apic->int_cmd.lo;
993             break;
994         case INT_CMD_HI_OFFSET:
995             val = apic->int_cmd.hi;
996             break;
997
998             // handle current timer count
999
1000             // Unhandled Registers
1001         case EXT_INT_LOC_VEC_TBL_OFFSET0:
1002             val = apic->ext_intr_vec_tbl[0].val;
1003             break;
1004         case EXT_INT_LOC_VEC_TBL_OFFSET1:
1005             val = apic->ext_intr_vec_tbl[1].val;
1006             break;
1007         case EXT_INT_LOC_VEC_TBL_OFFSET2:
1008             val = apic->ext_intr_vec_tbl[2].val;
1009             break;
1010         case EXT_INT_LOC_VEC_TBL_OFFSET3:
1011             val = apic->ext_intr_vec_tbl[3].val;
1012             break;
1013     
1014
1015         case EXT_APIC_FEATURE_OFFSET:
1016         case EXT_APIC_CMD_OFFSET:
1017         case SEOI_OFFSET:
1018
1019         default:
1020             PrintError("apic %u: core %u: Read from Unhandled APIC Register: %x (getting zero)\n", 
1021                        apic->lapic_id.val, core->cpu_id, (uint32_t)reg_addr);
1022             return -1;
1023     }
1024
1025
1026     if (length == 1) {
1027         uint_t byte_addr = reg_addr & 0x3;
1028         uint8_t * val_ptr = (uint8_t *)dst;
1029     
1030         *val_ptr = *(((uint8_t *)&val) + byte_addr);
1031
1032     } else if ((length == 2) && 
1033                ((reg_addr & 0x3) == 0x3)) {
1034         uint_t byte_addr = reg_addr & 0x3;
1035         uint16_t * val_ptr = (uint16_t *)dst;
1036         *val_ptr = *(((uint16_t *)&val) + byte_addr);
1037
1038     } else if (length == 4) {
1039         uint32_t * val_ptr = (uint32_t *)dst;
1040         *val_ptr = val;
1041
1042     } else {
1043         PrintError("apic %u: core %u: Invalid apic read length (%d)\n", 
1044                    apic->lapic_id.val, core->cpu_id, length);
1045         return -1;
1046     }
1047
1048     PrintDebug("apic %u: core %u: Read finished (val=%x)\n", 
1049                apic->lapic_id.val, core->cpu_id, *(uint32_t *)dst);
1050
1051     return length;
1052 }
1053
1054
1055 /**
1056  *
1057  */
1058 static int apic_write(struct guest_info * core, addr_t guest_addr, void * src, uint_t length, void * priv_data) {
1059     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(priv_data);
1060     struct apic_state * apic = &(apic_dev->apics[core->cpu_id]); 
1061     addr_t reg_addr  = guest_addr - apic->base_addr;
1062     struct apic_msr * msr = (struct apic_msr *)&(apic->base_addr_msr.value);
1063     uint32_t op_val = *(uint32_t *)src;
1064
1065     PrintDebug("apic %u: core %u: at %p and priv_data is at %p\n",
1066                apic->lapic_id.val, core->cpu_id, apic, priv_data);
1067
1068     PrintDebug("Write to address space (%p) (val=%x)\n", 
1069                (void *)guest_addr, *(uint32_t *)src);
1070
1071     if (msr->apic_enable == 0) {
1072         PrintError("apic %u: core %u: Write to APIC address space with disabled APIC, apic msr=0x%llx\n",
1073                    apic->lapic_id.val, core->cpu_id, apic->base_addr_msr.value);
1074         return -1;
1075     }
1076
1077
1078     if (length != 4) {
1079         PrintError("apic %u: core %u: Invalid apic write length (%d)\n", 
1080                    apic->lapic_id.val, length, core->cpu_id);
1081         return -1;
1082     }
1083
1084     switch (reg_addr) {
1085         case REMOTE_READ_OFFSET:
1086         case APIC_VERSION_OFFSET:
1087         case APR_OFFSET:
1088         case IRR_OFFSET0:
1089         case IRR_OFFSET1:
1090         case IRR_OFFSET2:
1091         case IRR_OFFSET3:
1092         case IRR_OFFSET4:
1093         case IRR_OFFSET5:
1094         case IRR_OFFSET6:
1095         case IRR_OFFSET7:
1096         case ISR_OFFSET0:
1097         case ISR_OFFSET1:
1098         case ISR_OFFSET2:
1099         case ISR_OFFSET3:
1100         case ISR_OFFSET4:
1101         case ISR_OFFSET5:
1102         case ISR_OFFSET6:
1103         case ISR_OFFSET7:
1104         case TRIG_OFFSET0:
1105         case TRIG_OFFSET1:
1106         case TRIG_OFFSET2:
1107         case TRIG_OFFSET3:
1108         case TRIG_OFFSET4:
1109         case TRIG_OFFSET5:
1110         case TRIG_OFFSET6:
1111         case TRIG_OFFSET7:
1112         case PPR_OFFSET:
1113         case EXT_APIC_FEATURE_OFFSET:
1114
1115             PrintError("apic %u: core %u: Attempting to write to read only register %p (error)\n", 
1116                        apic->lapic_id.val, core->cpu_id, (void *)reg_addr);
1117             //  return -1;
1118
1119             break;
1120
1121             // Data registers
1122         case APIC_ID_OFFSET:
1123             PrintDebug("apic %u: core %u: my id is being changed to %u\n", 
1124                        apic->lapic_id.val, core->cpu_id, op_val);
1125
1126             apic->lapic_id.val = op_val;
1127             break;
1128         case TPR_OFFSET:
1129             apic->task_prio.val = op_val;
1130             break;
1131         case LDR_OFFSET:
1132             PrintDebug("apic %u: core %u: setting log_dst.val to 0x%x\n",
1133                        apic->lapic_id.val, core->cpu_id, op_val);
1134             apic->log_dst.val = op_val;
1135             break;
1136         case DFR_OFFSET:
1137             apic->dst_fmt.val = op_val;
1138             break;
1139         case SPURIOUS_INT_VEC_OFFSET:
1140             apic->spurious_int.val = op_val;
1141             break;
1142         case ESR_OFFSET:
1143             apic->err_status.val = op_val;
1144             break;
1145         case TMR_LOC_VEC_TBL_OFFSET:
1146             apic->tmr_vec_tbl.val = op_val;
1147             break;
1148         case THERM_LOC_VEC_TBL_OFFSET:
1149             apic->therm_loc_vec_tbl.val = op_val;
1150             break;
1151         case PERF_CTR_LOC_VEC_TBL_OFFSET:
1152             apic->perf_ctr_loc_vec_tbl.val = op_val;
1153             break;
1154         case LINT0_VEC_TBL_OFFSET:
1155             apic->lint0_vec_tbl.val = op_val;
1156             break;
1157         case LINT1_VEC_TBL_OFFSET:
1158             apic->lint1_vec_tbl.val = op_val;
1159             break;
1160         case ERR_VEC_TBL_OFFSET:
1161             apic->err_vec_tbl.val = op_val;
1162             break;
1163         case TMR_INIT_CNT_OFFSET:
1164             apic->tmr_init_cnt = op_val;
1165             apic->tmr_cur_cnt = op_val;
1166             break;
1167         case TMR_CUR_CNT_OFFSET:
1168             apic->tmr_cur_cnt = op_val;
1169             break;
1170         case TMR_DIV_CFG_OFFSET:
1171             apic->tmr_div_cfg.val = op_val;
1172             break;
1173
1174
1175             // Enable mask (256 bits)
1176         case IER_OFFSET0:
1177             *(uint32_t *)(apic->int_en_reg) = op_val;
1178             break;
1179         case IER_OFFSET1:
1180             *(uint32_t *)(apic->int_en_reg + 4) = op_val;
1181             break;
1182         case IER_OFFSET2:
1183             *(uint32_t *)(apic->int_en_reg + 8) = op_val;
1184             break;
1185         case IER_OFFSET3:
1186             *(uint32_t *)(apic->int_en_reg + 12) = op_val;
1187             break;
1188         case IER_OFFSET4:
1189             *(uint32_t *)(apic->int_en_reg + 16) = op_val;
1190             break;
1191         case IER_OFFSET5:
1192             *(uint32_t *)(apic->int_en_reg + 20) = op_val;
1193             break;
1194         case IER_OFFSET6:
1195             *(uint32_t *)(apic->int_en_reg + 24) = op_val;
1196             break;
1197         case IER_OFFSET7:
1198             *(uint32_t *)(apic->int_en_reg + 28) = op_val;
1199             break;
1200
1201         case EXT_INT_LOC_VEC_TBL_OFFSET0:
1202             apic->ext_intr_vec_tbl[0].val = op_val;
1203             break;
1204         case EXT_INT_LOC_VEC_TBL_OFFSET1:
1205             apic->ext_intr_vec_tbl[1].val = op_val;
1206             break;
1207         case EXT_INT_LOC_VEC_TBL_OFFSET2:
1208             apic->ext_intr_vec_tbl[2].val = op_val;
1209             break;
1210         case EXT_INT_LOC_VEC_TBL_OFFSET3:
1211             apic->ext_intr_vec_tbl[3].val = op_val;
1212             break;
1213
1214
1215             // Action Registers
1216         case EOI_OFFSET:
1217             // do eoi
1218             apic_do_eoi(apic);
1219             break;
1220
1221         case INT_CMD_LO_OFFSET:
1222             apic->int_cmd.lo = op_val;
1223
1224             PrintDebug("apic %u: core %u: sending cmd 0x%llx to apic %u\n", 
1225                        apic->lapic_id.val, core->cpu_id,
1226                        apic->int_cmd.val, apic->int_cmd.dst);
1227
1228             if (route_ipi(apic_dev, apic, &(apic->int_cmd)) == -1) { 
1229                 PrintError("IPI Routing failure\n");
1230                 return -1;
1231             }
1232
1233             break;
1234
1235         case INT_CMD_HI_OFFSET:
1236             apic->int_cmd.hi = op_val;
1237             break;
1238
1239
1240         // Unhandled Registers
1241         case EXT_APIC_CMD_OFFSET:
1242         case SEOI_OFFSET:
1243         default:
1244             PrintError("apic %u: core %u: Write to Unhandled APIC Register: %x (ignored)\n", 
1245                        apic->lapic_id.val, core->cpu_id, (uint32_t)reg_addr);
1246
1247             return -1;
1248     }
1249
1250     PrintDebug("apic %u: core %u: Write finished\n", apic->lapic_id.val, core->cpu_id);
1251
1252     return length;
1253 }
1254
1255
1256
1257 /* Interrupt Controller Functions */
1258
1259 // returns 1 if an interrupt is pending, 0 otherwise
1260 static int apic_intr_pending(struct guest_info * core, void * private_data) {
1261     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(private_data);
1262     struct apic_state * apic = &(apic_dev->apics[core->cpu_id]); 
1263     int req_irq = get_highest_irr(apic);
1264     int svc_irq = get_highest_isr(apic);
1265
1266     //    PrintDebug("apic %u: core %u: req_irq=%d, svc_irq=%d\n",apic->lapic_id.val,info->cpu_id,req_irq,svc_irq);
1267
1268     if ((req_irq >= 0) && 
1269         (req_irq > svc_irq)) {
1270         return 1;
1271     }
1272
1273     return 0;
1274 }
1275
1276 static int apic_get_intr_number(struct guest_info * core, void * private_data) {
1277     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(private_data);
1278     struct apic_state * apic = &(apic_dev->apics[core->cpu_id]); 
1279     int req_irq = get_highest_irr(apic);
1280     int svc_irq = get_highest_isr(apic);
1281
1282     if (svc_irq == -1) {
1283         return req_irq;
1284     } else if (svc_irq < req_irq) {
1285         return req_irq;
1286     }
1287
1288     return -1;
1289 }
1290
1291
1292 int v3_apic_send_ipi(struct v3_vm_info * vm, struct vm_device * dev, 
1293                      struct v3_gen_ipi * ipi) {
1294     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(dev->private_data);
1295     struct int_cmd_reg tmp_icr;
1296
1297     // zero out all the fields
1298     tmp_icr.val = 0;
1299
1300
1301     tmp_icr.vec = ipi->vector;
1302     tmp_icr.del_mode = ipi->mode;
1303     tmp_icr.dst_mode = ipi->logical;
1304     tmp_icr.trig_mode = ipi->trigger_mode;
1305     tmp_icr.dst_shorthand = ipi->dst_shorthand;
1306     tmp_icr.dst = ipi->dst;
1307     
1308
1309     return route_ipi(apic_dev, NULL, &tmp_icr);
1310 }
1311
1312
1313 int v3_apic_raise_intr(struct v3_vm_info * vm, struct vm_device * dev, 
1314                        uint32_t irq, uint32_t dst) {
1315     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(dev->private_data);
1316     struct apic_state * apic = &(apic_dev->apics[dst]); 
1317
1318     PrintDebug("apic %u core ?: raising interrupt IRQ %u (dst = %u).\n", apic->lapic_id.val, irq, dst); 
1319
1320     activate_apic_irq(apic, irq);
1321
1322     if (V3_Get_CPU() != dst) {
1323         v3_interrupt_cpu(vm, dst, 0);
1324     }
1325
1326     return 0;
1327 }
1328
1329
1330
1331 static int apic_begin_irq(struct guest_info * core, void * private_data, int irq) {
1332     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(private_data);
1333     struct apic_state * apic = &(apic_dev->apics[core->cpu_id]); 
1334     int major_offset = (irq & ~0x00000007) >> 3;
1335     int minor_offset = irq & 0x00000007;
1336     uint8_t * req_location = apic->int_req_reg + major_offset;
1337     uint8_t * svc_location = apic->int_svc_reg + major_offset;
1338     uint8_t flag = 0x01 << minor_offset;
1339
1340     if (*req_location & flag) {
1341         // we will only pay attention to a begin irq if we
1342         // know that we initiated it!
1343         *svc_location |= flag;
1344         *req_location &= ~flag;
1345     } else {
1346         // do nothing... 
1347         //PrintDebug("apic %u: core %u: begin irq for %d ignored since I don't own it\n",
1348         //         apic->lapic_id.val, core->cpu_id, irq);
1349     }
1350
1351     return 0;
1352 }
1353
1354
1355
1356
1357 /* Timer Functions */
1358 static void apic_update_time(struct guest_info * core, 
1359                              uint64_t cpu_cycles, uint64_t cpu_freq, 
1360                              void * priv_data) {
1361     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(priv_data);
1362     struct apic_state * apic = &(apic_dev->apics[core->cpu_id]); 
1363
1364     // The 32 bit GCC runtime is a pile of shit
1365 #ifdef __V3_64BIT__
1366     uint64_t tmr_ticks = 0;
1367 #else 
1368     uint32_t tmr_ticks = 0;
1369 #endif
1370
1371     uint8_t tmr_div = *(uint8_t *)&(apic->tmr_div_cfg.val);
1372     uint_t shift_num = 0;
1373
1374
1375     // Check whether this is true:
1376     //   -> If the Init count is zero then the timer is disabled
1377     //      and doesn't just blitz interrupts to the CPU
1378     if ((apic->tmr_init_cnt == 0) || 
1379         ( (apic->tmr_vec_tbl.tmr_mode == APIC_TMR_ONESHOT) &&
1380           (apic->tmr_cur_cnt == 0))) {
1381         //PrintDebug("apic %u: core %u: APIC timer not yet initialized\n",apic->lapic_id.val,info->cpu_id);
1382         return;
1383     }
1384
1385
1386     switch (tmr_div) {
1387         case APIC_TMR_DIV1:
1388             shift_num = 0;
1389             break;
1390         case APIC_TMR_DIV2:
1391             shift_num = 1;
1392             break;
1393         case APIC_TMR_DIV4:
1394             shift_num = 2;
1395             break;
1396         case APIC_TMR_DIV8:
1397             shift_num = 3;
1398             break;
1399         case APIC_TMR_DIV16:
1400             shift_num = 4;
1401             break;
1402         case APIC_TMR_DIV32:
1403             shift_num = 5;
1404             break;
1405         case APIC_TMR_DIV64:
1406             shift_num = 6;
1407             break;
1408         case APIC_TMR_DIV128:
1409             shift_num = 7;
1410             break;
1411         default:
1412             PrintError("apic %u: core %u: Invalid Timer Divider configuration\n",
1413                        apic->lapic_id.val, core->cpu_id);
1414             return;
1415     }
1416
1417     tmr_ticks = cpu_cycles >> shift_num;
1418     //    PrintDebug("Timer Ticks: %p\n", (void *)tmr_ticks);
1419
1420     if (tmr_ticks < apic->tmr_cur_cnt) {
1421         apic->tmr_cur_cnt -= tmr_ticks;
1422     } else {
1423         tmr_ticks -= apic->tmr_cur_cnt;
1424         apic->tmr_cur_cnt = 0;
1425
1426         // raise irq
1427         PrintDebug("apic %u: core %u: Raising APIC Timer interrupt (periodic=%d) (icnt=%d) (div=%d)\n",
1428                    apic->lapic_id.val, core->cpu_id,
1429                    apic->tmr_vec_tbl.tmr_mode, apic->tmr_init_cnt, shift_num);
1430
1431         if (apic_intr_pending(core, priv_data)) {
1432             PrintDebug("apic %u: core %u: Overriding pending IRQ %d\n", 
1433                        apic->lapic_id.val, core->cpu_id, 
1434                        apic_get_intr_number(core, priv_data));
1435         }
1436
1437         if (activate_internal_irq(apic, APIC_TMR_INT) == -1) {
1438             PrintError("apic %u: core %u: Could not raise Timer interrupt\n",
1439                        apic->lapic_id.val, core->cpu_id);
1440         }
1441     
1442         if (apic->tmr_vec_tbl.tmr_mode == APIC_TMR_PERIODIC) {
1443             tmr_ticks = tmr_ticks % apic->tmr_init_cnt;
1444             apic->tmr_cur_cnt = apic->tmr_init_cnt - tmr_ticks;
1445         }
1446     }
1447
1448
1449 }
1450
1451
1452 static struct intr_ctrl_ops intr_ops = {
1453     .intr_pending = apic_intr_pending,
1454     .get_intr_number = apic_get_intr_number,
1455     .begin_irq = apic_begin_irq,
1456 };
1457
1458
1459 static struct vm_timer_ops timer_ops = {
1460     .update_timer = apic_update_time,
1461 };
1462
1463
1464
1465
1466 static int apic_free(struct vm_device * dev) {
1467
1468     /* TODO: This should crosscall to force an unhook on each CPU */
1469
1470     //   struct apic_state * apic = (struct apic_state *)dev->private_data;
1471
1472     v3_unhook_msr(dev->vm, BASE_ADDR_MSR);
1473
1474     return 0;
1475 }
1476
1477
1478 static struct v3_device_ops dev_ops = {
1479     .free = apic_free,
1480     .reset = NULL,
1481     .start = NULL,
1482     .stop = NULL,
1483 };
1484
1485
1486
1487
1488
1489 static int apic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
1490     char * dev_id = v3_cfg_val(cfg, "ID");
1491     struct apic_dev_state * apic_dev = NULL;
1492     int i = 0;
1493
1494     PrintDebug("apic: creating an APIC for each core\n");
1495
1496     apic_dev = (struct apic_dev_state *)V3_Malloc(sizeof(struct apic_dev_state) + 
1497                                                   sizeof(struct apic_state) * vm->num_cores);
1498
1499     apic_dev->num_apics = vm->num_cores;
1500
1501     struct vm_device * dev = v3_allocate_device(dev_id, &dev_ops, apic_dev);
1502
1503     if (v3_attach_device(vm, dev) == -1) {
1504         PrintError("apic: Could not attach device %s\n", dev_id);
1505         return -1;
1506     }
1507
1508     
1509     for (i = 0; i < vm->num_cores; i++) {
1510         struct apic_state * apic = &(apic_dev->apics[i]);
1511         struct guest_info * core = &(vm->cores[i]);
1512
1513         apic->core = core;
1514
1515         init_apic_state(apic, i);
1516
1517         v3_register_intr_controller(core, &intr_ops, apic_dev);
1518
1519         v3_add_timer(core, &timer_ops, apic_dev);
1520
1521         v3_hook_full_mem(vm, core->cpu_id, apic->base_addr, apic->base_addr + PAGE_SIZE_4KB, apic_read, apic_write, apic_dev);
1522
1523         PrintDebug("apic %u: (setup device): done, my id is %u\n", i, apic->lapic_id.val);
1524     }
1525
1526 #ifdef CONFIG_DEBUG_APIC
1527     for (i = 0; i < vm->num_cores; i++) {
1528         struct apic_state * apic = &(apic_dev->apics[i]);
1529         PrintDebug("apic: sanity check: apic %u (at %p) has id %u and msr value %llx\n",
1530                    i, apic, apic->lapic_id.val, apic->base_addr_msr.value);
1531     }
1532 #endif
1533
1534
1535     PrintDebug("apic: priv_data is at %p\n", apic_dev);
1536
1537     v3_hook_msr(vm, BASE_ADDR_MSR, read_apic_msr, write_apic_msr, apic_dev);
1538
1539     return 0;
1540 }
1541
1542
1543
1544 device_register("LAPIC", apic_init)