Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


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