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.


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