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.


This patch adds a few compiler conditionals so that multi-thread-specific code is...
[palacios.git] / palacios / src / devices / apic.c
1 /* 
2  * This file is part of the Palacios Virtual Machine Monitor developed
3  * by the V3VEE Project with funding from the United States National 
4  * Science Foundation and the Department of Energy.  
5  *
6  * The V3VEE Project is a joint project between Northwestern University
7  * and the University of New Mexico.  You can find out more at 
8  * http://www.v3vee.org
9  *
10  * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu> 
11  * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
12  * All rights reserved.
13  *
14  * Author: Jack Lange <jarusl@cs.northwestern.edu>
15  *
16  * This is free software.  You are permitted to use,
17  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
18  */
19
20
21 #include <devices/apic.h>
22 #include <devices/apic_regs.h>
23 #include <palacios/vmm.h>
24 #include <palacios/vmm_msr.h>
25 #include <palacios/vmm_sprintf.h>
26 #include <palacios/vm_guest.h>
27 #include <palacios/vmm_types.h>
28
29
30 #ifndef CONFIG_DEBUG_APIC
31 #undef PrintDebug
32 #define PrintDebug(fmt, args...)
33 #endif
34
35 #ifdef CONFIG_DEBUG_APIC
36 static char * shorthand_str[] = { 
37     "(no shorthand)",
38     "(self)",
39     "(all)",
40     "(all-but-me)",
41 };
42
43 static char * deliverymode_str[] = { 
44     "(fixed)",
45     "(lowest priority)",
46     "(SMI)",
47     "(reserved)",
48     "(NMI)",
49     "(INIT)",
50     "(Start Up)",
51     "(ExtInt)",
52 };
53 #endif
54
55 typedef enum { APIC_TMR_INT, APIC_THERM_INT, APIC_PERF_INT, 
56                APIC_LINT0_INT, APIC_LINT1_INT, APIC_ERR_INT } apic_irq_type_t;
57
58 #define APIC_FIXED_DELIVERY  0x0
59 #define APIC_SMI_DELIVERY    0x2
60 #define APIC_NMI_DELIVERY    0x4
61 #define APIC_INIT_DELIVERY   0x5
62 #define APIC_EXTINT_DELIVERY 0x7
63
64
65 #define BASE_ADDR_MSR     0x0000001B
66 #define DEFAULT_BASE_ADDR 0xfee00000
67
68 #define APIC_ID_OFFSET                    0x020
69 #define APIC_VERSION_OFFSET               0x030
70 #define TPR_OFFSET                        0x080
71 #define APR_OFFSET                        0x090
72 #define PPR_OFFSET                        0x0a0
73 #define EOI_OFFSET                        0x0b0
74 #define REMOTE_READ_OFFSET                0x0c0
75 #define LDR_OFFSET                        0x0d0
76 #define DFR_OFFSET                        0x0e0
77 #define SPURIOUS_INT_VEC_OFFSET           0x0f0
78
79 #define ISR_OFFSET0                       0x100   // 0x100 - 0x170
80 #define ISR_OFFSET1                       0x110   // 0x100 - 0x170
81 #define ISR_OFFSET2                       0x120   // 0x100 - 0x170
82 #define ISR_OFFSET3                       0x130   // 0x100 - 0x170
83 #define ISR_OFFSET4                       0x140   // 0x100 - 0x170
84 #define ISR_OFFSET5                       0x150   // 0x100 - 0x170
85 #define ISR_OFFSET6                       0x160   // 0x100 - 0x170
86 #define ISR_OFFSET7                       0x170   // 0x100 - 0x170
87
88 #define TRIG_OFFSET0                      0x180   // 0x180 - 0x1f0
89 #define TRIG_OFFSET1                      0x190   // 0x180 - 0x1f0
90 #define TRIG_OFFSET2                      0x1a0   // 0x180 - 0x1f0
91 #define TRIG_OFFSET3                      0x1b0   // 0x180 - 0x1f0
92 #define TRIG_OFFSET4                      0x1c0   // 0x180 - 0x1f0
93 #define TRIG_OFFSET5                      0x1d0   // 0x180 - 0x1f0
94 #define TRIG_OFFSET6                      0x1e0   // 0x180 - 0x1f0
95 #define TRIG_OFFSET7                      0x1f0   // 0x180 - 0x1f0
96
97
98 #define IRR_OFFSET0                       0x200   // 0x200 - 0x270
99 #define IRR_OFFSET1                       0x210   // 0x200 - 0x270
100 #define IRR_OFFSET2                       0x220   // 0x200 - 0x270
101 #define IRR_OFFSET3                       0x230   // 0x200 - 0x270
102 #define IRR_OFFSET4                       0x240   // 0x200 - 0x270
103 #define IRR_OFFSET5                       0x250   // 0x200 - 0x270
104 #define IRR_OFFSET6                       0x260   // 0x200 - 0x270
105 #define IRR_OFFSET7                       0x270   // 0x200 - 0x270
106
107
108 #define ESR_OFFSET                        0x280
109 #define INT_CMD_LO_OFFSET                 0x300
110 #define INT_CMD_HI_OFFSET                 0x310
111 #define TMR_LOC_VEC_TBL_OFFSET            0x320
112 #define THERM_LOC_VEC_TBL_OFFSET          0x330
113 #define PERF_CTR_LOC_VEC_TBL_OFFSET       0x340
114 #define LINT0_VEC_TBL_OFFSET              0x350
115 #define LINT1_VEC_TBL_OFFSET              0x360
116 #define ERR_VEC_TBL_OFFSET                0x370
117 #define TMR_INIT_CNT_OFFSET               0x380
118 #define TMR_CUR_CNT_OFFSET                0x390
119 #define TMR_DIV_CFG_OFFSET                0x3e0
120 #define EXT_APIC_FEATURE_OFFSET           0x400
121 #define EXT_APIC_CMD_OFFSET               0x410
122 #define SEOI_OFFSET                       0x420
123
124 #define IER_OFFSET0                       0x480   // 0x480 - 0x4f0
125 #define IER_OFFSET1                       0x490   // 0x480 - 0x4f0
126 #define IER_OFFSET2                       0x4a0   // 0x480 - 0x4f0
127 #define IER_OFFSET3                       0x4b0   // 0x480 - 0x4f0
128 #define IER_OFFSET4                       0x4c0   // 0x480 - 0x4f0
129 #define IER_OFFSET5                       0x4d0   // 0x480 - 0x4f0
130 #define IER_OFFSET6                       0x4e0   // 0x480 - 0x4f0
131 #define IER_OFFSET7                       0x4f0   // 0x480 - 0x4f0
132
133 #define EXT_INT_LOC_VEC_TBL_OFFSET0       0x500   // 0x500 - 0x530
134 #define EXT_INT_LOC_VEC_TBL_OFFSET1       0x510   // 0x500 - 0x530
135 #define EXT_INT_LOC_VEC_TBL_OFFSET2       0x520   // 0x500 - 0x530
136 #define EXT_INT_LOC_VEC_TBL_OFFSET3       0x530   // 0x500 - 0x530
137
138 struct apic_msr {
139     union {
140         uint64_t value;
141         struct {
142             uint8_t rsvd;
143             uint8_t bootstrap_cpu : 1;
144             uint8_t rsvd2         : 2;
145             uint8_t apic_enable   : 1;
146             uint64_t base_addr    : 40;
147             uint32_t rsvd3        : 12;
148         } __attribute__((packed));
149     } __attribute__((packed));
150 } __attribute__((packed));
151
152
153
154 typedef enum {INIT_ST, 
155               SIPI, 
156               STARTED} ipi_state_t; 
157
158 struct apic_dev_state;
159
160 struct apic_state {
161     addr_t base_addr;
162
163     /* MSRs */
164     struct apic_msr base_addr_msr;
165
166
167     /* memory map registers */
168
169     struct lapic_id_reg lapic_id;
170     struct apic_ver_reg apic_ver;
171     struct ext_apic_ctrl_reg ext_apic_ctrl;
172     struct local_vec_tbl_reg local_vec_tbl;
173     struct tmr_vec_tbl_reg tmr_vec_tbl;
174     struct tmr_div_cfg_reg tmr_div_cfg;
175     struct lint_vec_tbl_reg lint0_vec_tbl;
176     struct lint_vec_tbl_reg lint1_vec_tbl;
177     struct perf_ctr_loc_vec_tbl_reg perf_ctr_loc_vec_tbl;
178     struct therm_loc_vec_tbl_reg therm_loc_vec_tbl;
179     struct err_vec_tbl_reg err_vec_tbl;
180     struct err_status_reg err_status;
181     struct spurious_int_reg spurious_int;
182     struct int_cmd_reg int_cmd;
183     struct log_dst_reg log_dst;
184     struct dst_fmt_reg dst_fmt;
185     struct arb_prio_reg arb_prio;
186     struct task_prio_reg task_prio;
187     struct proc_prio_reg proc_prio;
188     struct ext_apic_feature_reg ext_apic_feature;
189     struct spec_eoi_reg spec_eoi;
190   
191
192     uint32_t tmr_cur_cnt;
193     uint32_t tmr_init_cnt;
194
195
196     struct local_vec_tbl_reg ext_intr_vec_tbl[4];
197
198     uint32_t rem_rd_data;
199
200
201     ipi_state_t ipi_state;
202
203     uint8_t int_req_reg[32];
204     uint8_t int_svc_reg[32];
205     uint8_t int_en_reg[32];
206     uint8_t trig_mode_reg[32];
207
208     struct guest_info * core;
209
210     void * controller_handle;
211
212     struct v3_timer * timer;
213
214     uint32_t eoi;
215
216     v3_lock_t  lock;
217 };
218
219
220
221
222 struct apic_dev_state {
223     int num_apics;
224
225     struct apic_state apics[0];
226 } __attribute__((packed));
227
228
229
230 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_flat_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_cluster_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 #ifdef CONFIG_MULTITHREAD_OS
603                 v3_interrupt_cpu(dst_core->vm_info, dst_core->cpu_id, 0);
604 #else
605                 V3_ASSERT(0);
606 #endif
607             }
608
609             break;
610         case 5: { //INIT
611
612             PrintDebug(" INIT delivery to core %u\n", dst_core->cpu_id);
613
614             // TODO: any APIC reset on dest core (shouldn't be needed, but not sure...)
615
616             // Sanity check
617             if (dst_apic->ipi_state != INIT_ST) { 
618                 PrintError(" Warning: core %u is not in INIT state (mode = %d), ignored\n",
619                            dst_core->cpu_id, dst_apic->ipi_state);
620                 // Only a warning, since INIT INIT SIPI is common
621                 break;
622             }
623
624             // We transition the target core to SIPI state
625             dst_apic->ipi_state = SIPI;  // note: locking should not be needed here
626
627             // That should be it since the target core should be
628             // waiting in host on this transition
629             // either it's on another core or on a different preemptive thread
630             // in both cases, it will quickly notice this transition 
631             // in particular, we should not need to force an exit here
632
633             PrintDebug(" INIT delivery done\n");
634
635             break;                                                      
636         }
637         case 6: { //SIPI
638
639             // Sanity check
640             if (dst_apic->ipi_state != SIPI) { 
641                 PrintError(" core %u is not in SIPI state (mode = %d), ignored!\n",
642                            dst_core->cpu_id, dst_apic->ipi_state);
643                 break;
644             }
645
646             // Write the RIP, CS, and descriptor
647             // assume the rest is already good to go
648             //
649             // vector VV -> rip at 0
650             //              CS = VV00
651             //  This means we start executing at linear address VV000
652             //
653             // So the selector needs to be VV00
654             // and the base needs to be VV000
655             //
656             dst_core->rip = 0;
657             dst_core->segments.cs.selector = vector << 8;
658             dst_core->segments.cs.limit = 0xffff;
659             dst_core->segments.cs.base = vector << 12;
660
661             PrintDebug(" SIPI delivery (0x%x -> 0x%x:0x0) to core %u\n",
662                        vector, dst_core->segments.cs.selector, dst_core->cpu_id);
663             // Maybe need to adjust the APIC?
664             
665             // We transition the target core to SIPI state
666             dst_core->core_run_state = CORE_RUNNING;  // note: locking should not be needed here
667             dst_apic->ipi_state = STARTED;
668
669             // As with INIT, we should not need to do anything else
670
671             PrintDebug(" SIPI delivery done\n");
672
673             break;                                                      
674         }
675         case 2: // SMI                  
676         case 3: // reserved                                             
677         case 4: // NMI                                  
678         case 7: // ExtInt
679         default:
680             PrintError("IPI %d delivery is unsupported\n", del_mode); 
681             return -1;
682     }
683
684     return 0;
685
686 }
687
688
689 static int route_ipi(struct apic_dev_state * apic_dev,
690                      struct apic_state * src_apic, 
691                      struct int_cmd_reg * icr) {
692     struct apic_state * dest_apic = NULL;
693
694     PrintDebug("route_ipi: src_apic=%p, icr_data=%p\n", 
695                src_apic, (void *)(addr_t)icr->val);
696
697
698     if ((icr->dst_mode == 0) && (icr->dst >= apic_dev->num_apics)) { 
699         PrintError("route_ipi: Attempted send to unregistered apic id=%u\n", 
700                    icr->dst);
701         return -1;
702     }
703
704     dest_apic =  &(apic_dev->apics[icr->dst]);
705
706
707     PrintDebug("route_ipi: IPI %s %u from apic %p to %s %s %u (icr=0x%llx)\n",
708                deliverymode_str[icr->del_mode], 
709                icr->vec, 
710                src_apic,               
711                (icr->dst_mode == 0) ? "(physical)" : "(logical)", 
712                shorthand_str[icr->dst_shorthand], 
713                icr->dst,
714                icr->val);
715
716     switch (icr->dst_shorthand) {
717
718         case 0:  // no shorthand
719             if (icr->dst_mode == 0) { 
720                 // physical delivery
721
722                 if (deliver_ipi(src_apic, dest_apic, 
723                                 icr->vec, icr->del_mode) == -1) {
724                     PrintError("Error: Could not deliver IPI\n");
725                     return -1;
726                 }
727
728             } else {
729                 // logical delivery
730                 int i;
731                 uint8_t mda = icr->dst;
732
733                 for (i = 0; i < apic_dev->num_apics; i++) { 
734                      dest_apic = &(apic_dev->apics[i]);
735                      int del_flag = should_deliver_ipi(dest_apic->core, dest_apic, mda);
736                      
737                      if (del_flag == -1) {
738                          PrintError("Error checking delivery mode\n");
739                          return -1;
740                      } else if (del_flag == 1) {
741                         if (deliver_ipi(src_apic, dest_apic, 
742                                         icr->vec, icr->del_mode) == -1) {
743                             PrintError("Error: Could not deliver IPI\n");
744                             return -1;
745                         }
746                     }
747                 }
748             }
749             
750             break;
751             
752         case 1:  // self
753
754             if (src_apic == NULL) {
755                 PrintError("Sending IPI to self from generic IPI sender\n");
756                 break;
757             }
758
759             if (icr->dst_mode == 0) { 
760                 if (deliver_ipi(src_apic, src_apic, icr->vec, icr->del_mode) == -1) {
761                     PrintError("Could not deliver IPI\n");
762                     return -1;
763                 }
764             } else {
765                 // logical delivery
766                 PrintError("use of logical delivery in self is not yet supported.\n");
767                 return -1;
768             }
769             break;
770             
771         case 2: 
772         case 3: { // all and all-but-me
773             // assuming that logical verus physical doesn't matter
774             // although it is odd that both are used
775             int i;
776
777             for (i = 0; i < apic_dev->num_apics; i++) { 
778                 dest_apic = &(apic_dev->apics[i]);
779
780                 if ((dest_apic != src_apic) || (icr->dst_shorthand == 2)) { 
781                     if (deliver_ipi(src_apic, dest_apic, icr->vec, icr->del_mode) == -1) {
782                         PrintError("Error: Could not deliver IPI\n");
783                         return -1;
784                     }
785                 }
786             }   
787
788             break;
789         }
790         default:
791             PrintError("Error routing IPI, invalid Mode (%d)\n", icr->dst_shorthand);
792             return -1;
793     }
794     
795
796     return 0;
797 }
798
799
800
801 static int apic_read(struct guest_info * core, addr_t guest_addr, void * dst, uint_t length, void * priv_data) {
802     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(priv_data);
803     struct apic_state * apic = &(apic_dev->apics[core->cpu_id]);
804     addr_t reg_addr  = guest_addr - apic->base_addr;
805     struct apic_msr * msr = (struct apic_msr *)&(apic->base_addr_msr.value);
806     uint32_t val = 0;
807
808
809     PrintDebug("apic %u: core %u: at %p: Read apic address space (%p)\n",
810                apic->lapic_id.val, core->cpu_id, apic, (void *)guest_addr);
811
812     if (msr->apic_enable == 0) {
813         PrintError("apic %u: core %u: Read from APIC address space with disabled APIC, apic msr=0x%llx\n",
814                    apic->lapic_id.val, core->cpu_id, apic->base_addr_msr.value);
815
816         return -1;
817     }
818
819
820     /* Because "May not be supported" doesn't matter to Linux developers... */
821     /*   if (length != 4) { */
822     /*     PrintError("Invalid apic read length (%d)\n", length); */
823     /*     return -1; */
824     /*   } */
825
826     switch (reg_addr & ~0x3) {
827         case EOI_OFFSET:
828             // Well, only an idiot would read from a architectural write only register
829             // Oh, Hello Linux.
830             //    PrintError("Attempting to read from write only register\n");
831             //    return -1;
832             break;
833
834             // data registers
835         case APIC_ID_OFFSET:
836             val = apic->lapic_id.val;
837             break;
838         case APIC_VERSION_OFFSET:
839             val = apic->apic_ver.val;
840             break;
841         case TPR_OFFSET:
842             val = apic->task_prio.val;
843             break;
844         case APR_OFFSET:
845             val = apic->arb_prio.val;
846             break;
847         case PPR_OFFSET:
848             val = apic->proc_prio.val;
849             break;
850         case REMOTE_READ_OFFSET:
851             val = apic->rem_rd_data;
852             break;
853         case LDR_OFFSET:
854             val = apic->log_dst.val;
855             break;
856         case DFR_OFFSET:
857             val = apic->dst_fmt.val;
858             break;
859         case SPURIOUS_INT_VEC_OFFSET:
860             val = apic->spurious_int.val;
861             break;
862         case ESR_OFFSET:
863             val = apic->err_status.val;
864             break;
865         case TMR_LOC_VEC_TBL_OFFSET:
866             val = apic->tmr_vec_tbl.val;
867             break;
868         case LINT0_VEC_TBL_OFFSET:
869             val = apic->lint0_vec_tbl.val;
870             break;
871         case LINT1_VEC_TBL_OFFSET:
872             val = apic->lint1_vec_tbl.val;
873             break;
874         case ERR_VEC_TBL_OFFSET:
875             val = apic->err_vec_tbl.val;
876             break;
877         case TMR_INIT_CNT_OFFSET:
878             val = apic->tmr_init_cnt;
879             break;
880         case TMR_DIV_CFG_OFFSET:
881             val = apic->tmr_div_cfg.val;
882             break;
883
884         case IER_OFFSET0:
885             val = *(uint32_t *)(apic->int_en_reg);
886             break;
887         case IER_OFFSET1:
888             val = *(uint32_t *)(apic->int_en_reg + 4);
889             break;
890         case IER_OFFSET2:
891             val = *(uint32_t *)(apic->int_en_reg + 8);
892             break;
893         case IER_OFFSET3:
894             val = *(uint32_t *)(apic->int_en_reg + 12);
895             break;
896         case IER_OFFSET4:
897             val = *(uint32_t *)(apic->int_en_reg + 16);
898             break;
899         case IER_OFFSET5:
900             val = *(uint32_t *)(apic->int_en_reg + 20);
901             break;
902         case IER_OFFSET6:
903             val = *(uint32_t *)(apic->int_en_reg + 24);
904             break;
905         case IER_OFFSET7:
906             val = *(uint32_t *)(apic->int_en_reg + 28);
907             break;
908
909         case ISR_OFFSET0:
910             val = *(uint32_t *)(apic->int_svc_reg);
911             break;
912         case ISR_OFFSET1:
913             val = *(uint32_t *)(apic->int_svc_reg + 4);
914             break;
915         case ISR_OFFSET2:
916             val = *(uint32_t *)(apic->int_svc_reg + 8);
917             break;
918         case ISR_OFFSET3:
919             val = *(uint32_t *)(apic->int_svc_reg + 12);
920             break;
921         case ISR_OFFSET4:
922             val = *(uint32_t *)(apic->int_svc_reg + 16);
923             break;
924         case ISR_OFFSET5:
925             val = *(uint32_t *)(apic->int_svc_reg + 20);
926             break;
927         case ISR_OFFSET6:
928             val = *(uint32_t *)(apic->int_svc_reg + 24);
929             break;
930         case ISR_OFFSET7:
931             val = *(uint32_t *)(apic->int_svc_reg + 28);
932             break;
933    
934         case TRIG_OFFSET0:
935             val = *(uint32_t *)(apic->trig_mode_reg);
936             break;
937         case TRIG_OFFSET1:
938             val = *(uint32_t *)(apic->trig_mode_reg + 4);
939             break;
940         case TRIG_OFFSET2:
941             val = *(uint32_t *)(apic->trig_mode_reg + 8);
942             break;
943         case TRIG_OFFSET3:
944             val = *(uint32_t *)(apic->trig_mode_reg + 12);
945             break;
946         case TRIG_OFFSET4:
947             val = *(uint32_t *)(apic->trig_mode_reg + 16);
948             break;
949         case TRIG_OFFSET5:
950             val = *(uint32_t *)(apic->trig_mode_reg + 20);
951             break;
952         case TRIG_OFFSET6:
953             val = *(uint32_t *)(apic->trig_mode_reg + 24);
954             break;
955         case TRIG_OFFSET7:
956             val = *(uint32_t *)(apic->trig_mode_reg + 28);
957             break;
958
959         case IRR_OFFSET0:
960             val = *(uint32_t *)(apic->int_req_reg);
961             break;
962         case IRR_OFFSET1:
963             val = *(uint32_t *)(apic->int_req_reg + 4);
964             break;
965         case IRR_OFFSET2:
966             val = *(uint32_t *)(apic->int_req_reg + 8);
967             break;
968         case IRR_OFFSET3:
969             val = *(uint32_t *)(apic->int_req_reg + 12);
970             break;
971         case IRR_OFFSET4:
972             val = *(uint32_t *)(apic->int_req_reg + 16);
973             break;
974         case IRR_OFFSET5:
975             val = *(uint32_t *)(apic->int_req_reg + 20);
976             break;
977         case IRR_OFFSET6:
978             val = *(uint32_t *)(apic->int_req_reg + 24);
979             break;
980         case IRR_OFFSET7:
981             val = *(uint32_t *)(apic->int_req_reg + 28);
982             break;
983         case TMR_CUR_CNT_OFFSET:
984             val = apic->tmr_cur_cnt;
985             break;
986
987             // We are not going to implement these....
988         case THERM_LOC_VEC_TBL_OFFSET:
989             val = apic->therm_loc_vec_tbl.val;
990             break;
991         case PERF_CTR_LOC_VEC_TBL_OFFSET:
992             val = apic->perf_ctr_loc_vec_tbl.val;
993             break;
994
995  
996
997             // handled registers
998         case INT_CMD_LO_OFFSET:    
999             val = apic->int_cmd.lo;
1000             break;
1001         case INT_CMD_HI_OFFSET:
1002             val = apic->int_cmd.hi;
1003             break;
1004
1005             // handle current timer count
1006
1007             // Unhandled Registers
1008         case EXT_INT_LOC_VEC_TBL_OFFSET0:
1009             val = apic->ext_intr_vec_tbl[0].val;
1010             break;
1011         case EXT_INT_LOC_VEC_TBL_OFFSET1:
1012             val = apic->ext_intr_vec_tbl[1].val;
1013             break;
1014         case EXT_INT_LOC_VEC_TBL_OFFSET2:
1015             val = apic->ext_intr_vec_tbl[2].val;
1016             break;
1017         case EXT_INT_LOC_VEC_TBL_OFFSET3:
1018             val = apic->ext_intr_vec_tbl[3].val;
1019             break;
1020     
1021
1022         case EXT_APIC_FEATURE_OFFSET:
1023         case EXT_APIC_CMD_OFFSET:
1024         case SEOI_OFFSET:
1025
1026         default:
1027             PrintError("apic %u: core %u: Read from Unhandled APIC Register: %x (getting zero)\n", 
1028                        apic->lapic_id.val, core->cpu_id, (uint32_t)reg_addr);
1029             return -1;
1030     }
1031
1032
1033     if (length == 1) {
1034         uint_t byte_addr = reg_addr & 0x3;
1035         uint8_t * val_ptr = (uint8_t *)dst;
1036     
1037         *val_ptr = *(((uint8_t *)&val) + byte_addr);
1038
1039     } else if ((length == 2) && 
1040                ((reg_addr & 0x3) == 0x3)) {
1041         uint_t byte_addr = reg_addr & 0x3;
1042         uint16_t * val_ptr = (uint16_t *)dst;
1043         *val_ptr = *(((uint16_t *)&val) + byte_addr);
1044
1045     } else if (length == 4) {
1046         uint32_t * val_ptr = (uint32_t *)dst;
1047         *val_ptr = val;
1048
1049     } else {
1050         PrintError("apic %u: core %u: Invalid apic read length (%d)\n", 
1051                    apic->lapic_id.val, core->cpu_id, length);
1052         return -1;
1053     }
1054
1055     PrintDebug("apic %u: core %u: Read finished (val=%x)\n", 
1056                apic->lapic_id.val, core->cpu_id, *(uint32_t *)dst);
1057
1058     return length;
1059 }
1060
1061
1062 /**
1063  *
1064  */
1065 static int apic_write(struct guest_info * core, addr_t guest_addr, void * src, uint_t length, void * priv_data) {
1066     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(priv_data);
1067     struct apic_state * apic = &(apic_dev->apics[core->cpu_id]); 
1068     addr_t reg_addr  = guest_addr - apic->base_addr;
1069     struct apic_msr * msr = (struct apic_msr *)&(apic->base_addr_msr.value);
1070     uint32_t op_val = *(uint32_t *)src;
1071
1072     PrintDebug("apic %u: core %u: at %p and priv_data is at %p\n",
1073                apic->lapic_id.val, core->cpu_id, apic, priv_data);
1074
1075     PrintDebug("apic %u: core %u: write to address space (%p) (val=%x)\n", 
1076                apic->lapic_id.val, core->cpu_id, (void *)guest_addr, *(uint32_t *)src);
1077
1078     if (msr->apic_enable == 0) {
1079         PrintError("apic %u: core %u: Write to APIC address space with disabled APIC, apic msr=0x%llx\n",
1080                    apic->lapic_id.val, core->cpu_id, apic->base_addr_msr.value);
1081         return -1;
1082     }
1083
1084
1085     if (length != 4) {
1086         PrintError("apic %u: core %u: Invalid apic write length (%d)\n", 
1087                    apic->lapic_id.val, length, core->cpu_id);
1088         return -1;
1089     }
1090
1091     switch (reg_addr) {
1092         case REMOTE_READ_OFFSET:
1093         case APIC_VERSION_OFFSET:
1094         case APR_OFFSET:
1095         case IRR_OFFSET0:
1096         case IRR_OFFSET1:
1097         case IRR_OFFSET2:
1098         case IRR_OFFSET3:
1099         case IRR_OFFSET4:
1100         case IRR_OFFSET5:
1101         case IRR_OFFSET6:
1102         case IRR_OFFSET7:
1103         case ISR_OFFSET0:
1104         case ISR_OFFSET1:
1105         case ISR_OFFSET2:
1106         case ISR_OFFSET3:
1107         case ISR_OFFSET4:
1108         case ISR_OFFSET5:
1109         case ISR_OFFSET6:
1110         case ISR_OFFSET7:
1111         case TRIG_OFFSET0:
1112         case TRIG_OFFSET1:
1113         case TRIG_OFFSET2:
1114         case TRIG_OFFSET3:
1115         case TRIG_OFFSET4:
1116         case TRIG_OFFSET5:
1117         case TRIG_OFFSET6:
1118         case TRIG_OFFSET7:
1119         case PPR_OFFSET:
1120         case EXT_APIC_FEATURE_OFFSET:
1121
1122             PrintError("apic %u: core %u: Attempting to write to read only register %p (error)\n", 
1123                        apic->lapic_id.val, core->cpu_id, (void *)reg_addr);
1124             //  return -1;
1125
1126             break;
1127
1128             // Data registers
1129         case APIC_ID_OFFSET:
1130             PrintDebug("apic %u: core %u: my id is being changed to %u\n", 
1131                        apic->lapic_id.val, core->cpu_id, op_val);
1132
1133             apic->lapic_id.val = op_val;
1134             break;
1135         case TPR_OFFSET:
1136             apic->task_prio.val = op_val;
1137             break;
1138         case LDR_OFFSET:
1139             PrintDebug("apic %u: core %u: setting log_dst.val to 0x%x\n",
1140                        apic->lapic_id.val, core->cpu_id, op_val);
1141             apic->log_dst.val = op_val;
1142             break;
1143         case DFR_OFFSET:
1144             apic->dst_fmt.val = op_val;
1145             break;
1146         case SPURIOUS_INT_VEC_OFFSET:
1147             apic->spurious_int.val = op_val;
1148             break;
1149         case ESR_OFFSET:
1150             apic->err_status.val = op_val;
1151             break;
1152         case TMR_LOC_VEC_TBL_OFFSET:
1153             apic->tmr_vec_tbl.val = op_val;
1154             break;
1155         case THERM_LOC_VEC_TBL_OFFSET:
1156             apic->therm_loc_vec_tbl.val = op_val;
1157             break;
1158         case PERF_CTR_LOC_VEC_TBL_OFFSET:
1159             apic->perf_ctr_loc_vec_tbl.val = op_val;
1160             break;
1161         case LINT0_VEC_TBL_OFFSET:
1162             apic->lint0_vec_tbl.val = op_val;
1163             break;
1164         case LINT1_VEC_TBL_OFFSET:
1165             apic->lint1_vec_tbl.val = op_val;
1166             break;
1167         case ERR_VEC_TBL_OFFSET:
1168             apic->err_vec_tbl.val = op_val;
1169             break;
1170         case TMR_INIT_CNT_OFFSET:
1171             apic->tmr_init_cnt = op_val;
1172             apic->tmr_cur_cnt = op_val;
1173             break;
1174         case TMR_CUR_CNT_OFFSET:
1175             apic->tmr_cur_cnt = op_val;
1176             break;
1177         case TMR_DIV_CFG_OFFSET:
1178             apic->tmr_div_cfg.val = op_val;
1179             break;
1180
1181
1182             // Enable mask (256 bits)
1183         case IER_OFFSET0:
1184             *(uint32_t *)(apic->int_en_reg) = op_val;
1185             break;
1186         case IER_OFFSET1:
1187             *(uint32_t *)(apic->int_en_reg + 4) = op_val;
1188             break;
1189         case IER_OFFSET2:
1190             *(uint32_t *)(apic->int_en_reg + 8) = op_val;
1191             break;
1192         case IER_OFFSET3:
1193             *(uint32_t *)(apic->int_en_reg + 12) = op_val;
1194             break;
1195         case IER_OFFSET4:
1196             *(uint32_t *)(apic->int_en_reg + 16) = op_val;
1197             break;
1198         case IER_OFFSET5:
1199             *(uint32_t *)(apic->int_en_reg + 20) = op_val;
1200             break;
1201         case IER_OFFSET6:
1202             *(uint32_t *)(apic->int_en_reg + 24) = op_val;
1203             break;
1204         case IER_OFFSET7:
1205             *(uint32_t *)(apic->int_en_reg + 28) = op_val;
1206             break;
1207
1208         case EXT_INT_LOC_VEC_TBL_OFFSET0:
1209             apic->ext_intr_vec_tbl[0].val = op_val;
1210             break;
1211         case EXT_INT_LOC_VEC_TBL_OFFSET1:
1212             apic->ext_intr_vec_tbl[1].val = op_val;
1213             break;
1214         case EXT_INT_LOC_VEC_TBL_OFFSET2:
1215             apic->ext_intr_vec_tbl[2].val = op_val;
1216             break;
1217         case EXT_INT_LOC_VEC_TBL_OFFSET3:
1218             apic->ext_intr_vec_tbl[3].val = op_val;
1219             break;
1220
1221
1222             // Action Registers
1223         case EOI_OFFSET:
1224             // do eoi
1225             apic_do_eoi(apic);
1226             break;
1227
1228         case INT_CMD_LO_OFFSET:
1229             apic->int_cmd.lo = op_val;
1230
1231             PrintDebug("apic %u: core %u: sending cmd 0x%llx to apic %u\n", 
1232                        apic->lapic_id.val, core->cpu_id,
1233                        apic->int_cmd.val, apic->int_cmd.dst);
1234
1235             if (route_ipi(apic_dev, apic, &(apic->int_cmd)) == -1) { 
1236                 PrintError("IPI Routing failure\n");
1237                 return -1;
1238             }
1239
1240             break;
1241
1242         case INT_CMD_HI_OFFSET:
1243             apic->int_cmd.hi = op_val;
1244             break;
1245
1246
1247         // Unhandled Registers
1248         case EXT_APIC_CMD_OFFSET:
1249         case SEOI_OFFSET:
1250         default:
1251             PrintError("apic %u: core %u: Write to Unhandled APIC Register: %x (ignored)\n", 
1252                        apic->lapic_id.val, core->cpu_id, (uint32_t)reg_addr);
1253
1254             return -1;
1255     }
1256
1257     PrintDebug("apic %u: core %u: Write finished\n", apic->lapic_id.val, core->cpu_id);
1258
1259     return length;
1260 }
1261
1262
1263
1264 /* Interrupt Controller Functions */
1265
1266 // returns 1 if an interrupt is pending, 0 otherwise
1267 static int apic_intr_pending(struct guest_info * core, void * private_data) {
1268     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(private_data);
1269     struct apic_state * apic = &(apic_dev->apics[core->cpu_id]); 
1270     int req_irq = get_highest_irr(apic);
1271     int svc_irq = get_highest_isr(apic);
1272
1273     //    PrintDebug("apic %u: core %u: req_irq=%d, svc_irq=%d\n",apic->lapic_id.val,info->cpu_id,req_irq,svc_irq);
1274
1275     if ((req_irq >= 0) && 
1276         (req_irq > svc_irq)) {
1277         return 1;
1278     }
1279
1280     return 0;
1281 }
1282
1283 static int apic_get_intr_number(struct guest_info * core, void * private_data) {
1284     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(private_data);
1285     struct apic_state * apic = &(apic_dev->apics[core->cpu_id]); 
1286     int req_irq = get_highest_irr(apic);
1287     int svc_irq = get_highest_isr(apic);
1288
1289     if (svc_irq == -1) {
1290         return req_irq;
1291     } else if (svc_irq < req_irq) {
1292         return req_irq;
1293     }
1294
1295     return -1;
1296 }
1297
1298
1299 int v3_apic_send_ipi(struct v3_vm_info * vm, struct v3_gen_ipi * ipi, void * dev_data) {
1300     struct apic_dev_state * apic_dev = (struct apic_dev_state *)dev_data;
1301     struct int_cmd_reg tmp_icr;
1302
1303     // zero out all the fields
1304     tmp_icr.val = 0;
1305
1306
1307     tmp_icr.vec = ipi->vector;
1308     tmp_icr.del_mode = ipi->mode;
1309     tmp_icr.dst_mode = ipi->logical;
1310     tmp_icr.trig_mode = ipi->trigger_mode;
1311     tmp_icr.dst_shorthand = ipi->dst_shorthand;
1312     tmp_icr.dst = ipi->dst;
1313     
1314
1315     return route_ipi(apic_dev, NULL, &tmp_icr);
1316 }
1317
1318
1319 int v3_apic_raise_intr(struct v3_vm_info * vm, uint32_t irq, uint32_t dst, void * dev_data) {
1320     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(dev_data);
1321     struct apic_state * apic = &(apic_dev->apics[dst]); 
1322
1323     PrintDebug("apic %u core ?: raising interrupt IRQ %u (dst = %u).\n", apic->lapic_id.val, irq, dst); 
1324
1325     activate_apic_irq(apic, irq);
1326
1327     if (V3_Get_CPU() != dst) {
1328 #ifdef CONFIG_MULTITHREAD_OS
1329         v3_interrupt_cpu(vm, dst, 0);
1330 #else
1331         V3_ASSERT(0);
1332 #endif
1333     }
1334
1335     return 0;
1336 }
1337
1338
1339
1340 static int apic_begin_irq(struct guest_info * core, void * private_data, int irq) {
1341     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(private_data);
1342     struct apic_state * apic = &(apic_dev->apics[core->cpu_id]); 
1343     int major_offset = (irq & ~0x00000007) >> 3;
1344     int minor_offset = irq & 0x00000007;
1345     uint8_t * req_location = apic->int_req_reg + major_offset;
1346     uint8_t * svc_location = apic->int_svc_reg + major_offset;
1347     uint8_t flag = 0x01 << minor_offset;
1348
1349     if (*req_location & flag) {
1350         // we will only pay attention to a begin irq if we
1351         // know that we initiated it!
1352         *svc_location |= flag;
1353         *req_location &= ~flag;
1354     } else {
1355         // do nothing... 
1356         //PrintDebug("apic %u: core %u: begin irq for %d ignored since I don't own it\n",
1357         //         apic->lapic_id.val, core->cpu_id, irq);
1358     }
1359
1360     return 0;
1361 }
1362
1363
1364
1365
1366 /* Timer Functions */
1367 static void apic_update_time(struct guest_info * core, 
1368                              uint64_t cpu_cycles, uint64_t cpu_freq, 
1369                              void * priv_data) {
1370     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(priv_data);
1371     struct apic_state * apic = &(apic_dev->apics[core->cpu_id]); 
1372
1373     // The 32 bit GCC runtime is a pile of shit
1374 #ifdef __V3_64BIT__
1375     uint64_t tmr_ticks = 0;
1376 #else 
1377     uint32_t tmr_ticks = 0;
1378 #endif
1379
1380     uint8_t tmr_div = *(uint8_t *)&(apic->tmr_div_cfg.val);
1381     uint_t shift_num = 0;
1382
1383
1384     // Check whether this is true:
1385     //   -> If the Init count is zero then the timer is disabled
1386     //      and doesn't just blitz interrupts to the CPU
1387     if ((apic->tmr_init_cnt == 0) || 
1388         ( (apic->tmr_vec_tbl.tmr_mode == APIC_TMR_ONESHOT) &&
1389           (apic->tmr_cur_cnt == 0))) {
1390         //PrintDebug("apic %u: core %u: APIC timer not yet initialized\n",apic->lapic_id.val,info->cpu_id);
1391         return;
1392     }
1393
1394
1395     switch (tmr_div) {
1396         case APIC_TMR_DIV1:
1397             shift_num = 0;
1398             break;
1399         case APIC_TMR_DIV2:
1400             shift_num = 1;
1401             break;
1402         case APIC_TMR_DIV4:
1403             shift_num = 2;
1404             break;
1405         case APIC_TMR_DIV8:
1406             shift_num = 3;
1407             break;
1408         case APIC_TMR_DIV16:
1409             shift_num = 4;
1410             break;
1411         case APIC_TMR_DIV32:
1412             shift_num = 5;
1413             break;
1414         case APIC_TMR_DIV64:
1415             shift_num = 6;
1416             break;
1417         case APIC_TMR_DIV128:
1418             shift_num = 7;
1419             break;
1420         default:
1421             PrintError("apic %u: core %u: Invalid Timer Divider configuration\n",
1422                        apic->lapic_id.val, core->cpu_id);
1423             return;
1424     }
1425
1426     tmr_ticks = cpu_cycles >> shift_num;
1427     //    PrintDebug("Timer Ticks: %p\n", (void *)tmr_ticks);
1428
1429     if (tmr_ticks < apic->tmr_cur_cnt) {
1430         apic->tmr_cur_cnt -= tmr_ticks;
1431     } else {
1432         tmr_ticks -= apic->tmr_cur_cnt;
1433         apic->tmr_cur_cnt = 0;
1434
1435         // raise irq
1436         PrintDebug("apic %u: core %u: Raising APIC Timer interrupt (periodic=%d) (icnt=%d) (div=%d)\n",
1437                    apic->lapic_id.val, core->cpu_id,
1438                    apic->tmr_vec_tbl.tmr_mode, apic->tmr_init_cnt, shift_num);
1439
1440         if (apic_intr_pending(core, priv_data)) {
1441             PrintDebug("apic %u: core %u: Overriding pending IRQ %d\n", 
1442                        apic->lapic_id.val, core->cpu_id, 
1443                        apic_get_intr_number(core, priv_data));
1444         }
1445
1446         if (activate_internal_irq(apic, APIC_TMR_INT) == -1) {
1447             PrintError("apic %u: core %u: Could not raise Timer interrupt\n",
1448                        apic->lapic_id.val, core->cpu_id);
1449         }
1450     
1451         if (apic->tmr_vec_tbl.tmr_mode == APIC_TMR_PERIODIC) {
1452             tmr_ticks = tmr_ticks % apic->tmr_init_cnt;
1453             apic->tmr_cur_cnt = apic->tmr_init_cnt - tmr_ticks;
1454         }
1455     }
1456
1457
1458 }
1459
1460
1461 static struct intr_ctrl_ops intr_ops = {
1462     .intr_pending = apic_intr_pending,
1463     .get_intr_number = apic_get_intr_number,
1464     .begin_irq = apic_begin_irq,
1465 };
1466
1467
1468 static struct v3_timer_ops timer_ops = {
1469     .update_timer = apic_update_time,
1470 };
1471
1472
1473
1474
1475 static int apic_free(struct apic_dev_state * apic_dev) {
1476     int i = 0;
1477     struct v3_vm_info * vm = NULL;
1478
1479     for (i = 0; i < apic_dev->num_apics; i++) {
1480         struct apic_state * apic = &(apic_dev->apics[i]);
1481         struct guest_info * core = apic->core;
1482         
1483         vm = core->vm_info;
1484
1485         v3_remove_intr_controller(core, apic->controller_handle);
1486
1487         if (apic->timer) {
1488             v3_remove_timer(core, apic->timer);
1489         }
1490
1491         // unhook memory
1492
1493     }
1494
1495     v3_unhook_msr(vm, BASE_ADDR_MSR);
1496
1497     V3_Free(apic_dev);
1498     return 0;
1499 }
1500
1501
1502 static struct v3_device_ops dev_ops = {
1503     .free = (int (*)(void *))apic_free,
1504 };
1505
1506
1507
1508
1509
1510 static int apic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
1511     char * dev_id = v3_cfg_val(cfg, "ID");
1512     struct apic_dev_state * apic_dev = NULL;
1513     int i = 0;
1514
1515     PrintDebug("apic: creating an APIC for each core\n");
1516
1517     apic_dev = (struct apic_dev_state *)V3_Malloc(sizeof(struct apic_dev_state) + 
1518                                                   sizeof(struct apic_state) * vm->num_cores);
1519
1520     apic_dev->num_apics = vm->num_cores;
1521
1522     struct vm_device * dev = v3_add_device(vm, dev_id, &dev_ops, apic_dev);
1523
1524     if (dev == NULL) {
1525         PrintError("apic: Could not attach device %s\n", dev_id);
1526         V3_Free(apic_dev);
1527         return -1;
1528     }
1529
1530     
1531     for (i = 0; i < vm->num_cores; i++) {
1532         struct apic_state * apic = &(apic_dev->apics[i]);
1533         struct guest_info * core = &(vm->cores[i]);
1534
1535         apic->core = core;
1536
1537         init_apic_state(apic, i);
1538
1539         apic->controller_handle = v3_register_intr_controller(core, &intr_ops, apic_dev);
1540
1541         apic->timer = v3_add_timer(core, &timer_ops, apic_dev);
1542
1543         if (apic->timer == NULL) {
1544             PrintError("APIC: Failed to attach timer to core %d\n", i);
1545             v3_remove_device(dev);
1546             return -1;
1547         }
1548
1549         v3_hook_full_mem(vm, core->cpu_id, apic->base_addr, apic->base_addr + PAGE_SIZE_4KB, apic_read, apic_write, apic_dev);
1550
1551         PrintDebug("apic %u: (setup device): done, my id is %u\n", i, apic->lapic_id.val);
1552     }
1553
1554 #ifdef CONFIG_DEBUG_APIC
1555     for (i = 0; i < vm->num_cores; i++) {
1556         struct apic_state * apic = &(apic_dev->apics[i]);
1557         PrintDebug("apic: sanity check: apic %u (at %p) has id %u and msr value %llx\n",
1558                    i, apic, apic->lapic_id.val, apic->base_addr_msr.value);
1559     }
1560 #endif
1561
1562
1563     PrintDebug("apic: priv_data is at %p\n", apic_dev);
1564
1565     v3_hook_msr(vm, BASE_ADDR_MSR, read_apic_msr, write_apic_msr, apic_dev);
1566
1567     return 0;
1568 }
1569
1570
1571
1572 device_register("LAPIC", apic_init)