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.


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