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.


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