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.


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