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