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.


fixed apic/ioapic interface
[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_ST, 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_ST;
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, 
308                          apic->base_addr + PAGE_SIZE_4KB, 
309                          apic_read, apic_write, apic_dev) == -1) {
310         PrintError("apic %u: core %u: Could not hook new APIC Base address\n",
311                    apic->lapic_id.val, core->cpu_id);
312         v3_unlock(apic->lock);
313         return -1;
314     }
315
316     v3_unlock(apic->lock);
317     return 0;
318 }
319
320
321 // irq_num is the bit offset into a 256 bit buffer...
322 static int activate_apic_irq(struct apic_state * apic, uint32_t irq_num) {
323     int major_offset = (irq_num & ~0x00000007) >> 3;
324     int minor_offset = irq_num & 0x00000007;
325     uint8_t * req_location = apic->int_req_reg + major_offset;
326     uint8_t * en_location = apic->int_en_reg + major_offset;
327     uint8_t flag = 0x1 << minor_offset;
328
329
330
331     if (irq_num <= 15) {
332 //      PrintError("apic %u: core ?: Attempting to raise an invalid interrupt: %d\n", apic->lapic_id.val,irq_num);
333         return -1;
334     }
335
336
337     PrintDebug("apic %u: core ?: Raising APIC IRQ %d\n", apic->lapic_id.val, irq_num);
338
339     if (*req_location & flag) {
340         //V3_Print("Interrupts coallescing\n");
341     }
342
343     if (*en_location & flag) {
344         *req_location |= flag;
345     } else {
346         PrintDebug("apic %u: core ?: Interrupt  not enabled... %.2x\n", 
347                    apic->lapic_id.val, *en_location);
348         return 0;
349     }
350
351     return 0;
352 }
353
354
355
356 static int get_highest_isr(struct apic_state * apic) {
357     int i = 0, j = 0;
358
359     // We iterate backwards to find the highest priority
360     for (i = 31; i >= 0; i--) {
361         uint8_t  * svc_major = apic->int_svc_reg + i;
362     
363         if ((*svc_major) & 0xff) {
364             for (j = 7; j >= 0; j--) {
365                 uint8_t flag = 0x1 << j;
366                 if ((*svc_major) & flag) {
367                     return ((i * 8) + j);
368                 }
369             }
370         }
371     }
372
373     return -1;
374 }
375  
376
377
378 static int get_highest_irr(struct apic_state * apic) {
379     int i = 0, j = 0;
380
381     // We iterate backwards to find the highest priority
382     for (i = 31; i >= 0; i--) {
383         uint8_t  * req_major = apic->int_req_reg + i;
384     
385         if ((*req_major) & 0xff) {
386             for (j = 7; j >= 0; j--) {
387                 uint8_t flag = 0x1 << j;
388                 if ((*req_major) & flag) {
389                     return ((i * 8) + j);
390                 }
391             }
392         }
393     }
394
395     return -1;
396 }
397  
398
399
400
401 static int apic_do_eoi(struct apic_state * apic) {
402     int isr_irq = get_highest_isr(apic);
403
404     if (isr_irq != -1) {
405         int major_offset = (isr_irq & ~0x00000007) >> 3;
406         int minor_offset = isr_irq & 0x00000007;
407         uint8_t flag = 0x1 << minor_offset;
408         uint8_t * svc_location = apic->int_svc_reg + major_offset;
409         
410         PrintDebug("apic %u: core ?: Received APIC EOI for IRQ %d\n", apic->lapic_id.val,isr_irq);
411         
412         *svc_location &= ~flag;
413
414 #ifdef CONFIG_CRAY_XT
415         
416         if ((isr_irq == 238) || 
417             (isr_irq == 239)) {
418             PrintDebug("apic %u: core ?: Acking IRQ %d\n", apic->lapic_id.val,isr_irq);
419         }
420         
421         if (isr_irq == 238) {
422             V3_ACK_IRQ(238);
423         }
424 #endif
425     } else {
426         //PrintError("apic %u: core ?: Spurious EOI...\n",apic->lapic_id.val);
427     }
428         
429     return 0;
430 }
431  
432
433 static int activate_internal_irq(struct apic_state * apic, apic_irq_type_t int_type) {
434     uint32_t vec_num = 0;
435     uint32_t del_mode = 0;
436     int masked = 0;
437
438
439     switch (int_type) {
440         case APIC_TMR_INT:
441             vec_num = apic->tmr_vec_tbl.vec;
442             del_mode = APIC_FIXED_DELIVERY;
443             masked = apic->tmr_vec_tbl.mask;
444             break;
445         case APIC_THERM_INT:
446             vec_num = apic->therm_loc_vec_tbl.vec;
447             del_mode = apic->therm_loc_vec_tbl.msg_type;
448             masked = apic->therm_loc_vec_tbl.mask;
449             break;
450         case APIC_PERF_INT:
451             vec_num = apic->perf_ctr_loc_vec_tbl.vec;
452             del_mode = apic->perf_ctr_loc_vec_tbl.msg_type;
453             masked = apic->perf_ctr_loc_vec_tbl.mask;
454             break;
455         case APIC_LINT0_INT:
456             vec_num = apic->lint0_vec_tbl.vec;
457             del_mode = apic->lint0_vec_tbl.msg_type;
458             masked = apic->lint0_vec_tbl.mask;
459             break;
460         case APIC_LINT1_INT:
461             vec_num = apic->lint1_vec_tbl.vec;
462             del_mode = apic->lint1_vec_tbl.msg_type;
463             masked = apic->lint1_vec_tbl.mask;
464             break;
465         case APIC_ERR_INT:
466             vec_num = apic->err_vec_tbl.vec;
467             del_mode = APIC_FIXED_DELIVERY;
468             masked = apic->err_vec_tbl.mask;
469             break;
470         default:
471             PrintError("apic %u: core ?: Invalid APIC interrupt type\n", apic->lapic_id.val);
472             return -1;
473     }
474
475     // interrupt is masked, don't send
476     if (masked == 1) {
477         PrintDebug("apic %u: core ?: Inerrupt is masked\n", apic->lapic_id.val);
478         return 0;
479     }
480
481     if (del_mode == APIC_FIXED_DELIVERY) {
482         //PrintDebug("Activating internal APIC IRQ %d\n", vec_num);
483         return activate_apic_irq(apic, vec_num);
484     } else {
485         PrintError("apic %u: core ?: Unhandled Delivery Mode\n", apic->lapic_id.val);
486         return -1;
487     }
488 }
489
490
491
492 static inline int should_deliver_cluster_ipi(struct guest_info * dst_core, 
493                                              struct apic_state * dst_apic, uint8_t mda) {
494
495     if  ( ((mda & 0xf0) == (dst_apic->log_dst.dst_log_id & 0xf0)) &&     // (I am in the cluster and
496           ((mda & 0x0f) & (dst_apic->log_dst.dst_log_id & 0x0f)) ) {  //  I am in the set)
497
498         PrintDebug("apic %u core %u: accepting clustered IRQ (mda 0x%x == log_dst 0x%x)\n",
499                    dst_apic->lapic_id.val, dst_core->cpu_id, mda, 
500                    dst_apic->log_dst.dst_log_id);
501         
502         return 1;
503     } else {
504         PrintDebug("apic %u core %u: rejecting clustered IRQ (mda 0x%x != log_dst 0x%x)\n",
505                    dst_apic->lapic_id.val, dst_core->cpu_id, mda, dst_
506                    dst_apic->log_dst.dst_log_id);
507         return 0;
508     }
509 }
510
511 static inline int should_deliver_flat_ipi(struct guest_info * dst_core,
512                                           struct apic_state * dst_apic, uint8_t mda) {
513
514     if (dst_apic->log_dst.dst_log_id & mda) {  // I am in the set 
515
516         PrintDebug("apic %u core %u: accepting flat IRQ (mda 0x%x == log_dst 0x%x)\n",
517                    dst_apic->lapic_id.val, dst_core->cpu_id, mda, 
518                    dst_apic->log_dst.dst_log_id);
519       return 1;
520   } else {
521         PrintDebug("apic %u core %u: rejecting flat IRQ (mda 0x%x != log_dst 0x%x)\n",
522                    dst_apic->lapic_id.val, dst_core->cpu_id, mda, 
523                    dst_apic->log_dst.dst_log_id);
524       return 0;
525   }
526 }
527
528
529
530 static int should_deliver_ipi(struct guest_info * dst_core, 
531                               struct apic_state * dst_apic, uint8_t mda) {
532
533
534     if (dst_apic->dst_fmt.model == 0xf) {
535
536         if (mda == 0xff) {
537             // always deliver broadcast
538             return 1;
539         }
540
541         return should_deliver_cluster_ipi(dst_core, dst_apic, mda);
542     } else if (dst_apic->dst_fmt.model == 0x0) {
543
544         if (mda == 0xff) {
545             // always deliver broadcast
546             return 1;
547         }
548
549         return should_deliver_flat_ipi(dst_core, dst_apic, mda);
550     } else {
551         PrintError("apic %u core %u: invalid destination format register value 0x%x for logical mode delivery.\n", 
552                    dst_apic->lapic_id.val, dst_core->cpu_id, dst_apic->dst_fmt.model);
553         return -1;
554     }
555 }
556
557
558 static int deliver_ipi(struct apic_state * src_apic, 
559                        struct apic_state * dst_apic, 
560                        uint32_t vector, uint8_t del_mode) {
561
562     struct guest_info * dst_core = dst_apic->core;
563
564     switch (del_mode) {
565
566         case 0:  //fixed
567         case 1: // lowest priority
568             PrintDebug(" delivering IRQ to core %u\n", dst_core->cpu_id); 
569
570             activate_apic_irq(dst_apic, vector);
571
572             if (dst_apic != src_apic) { 
573                 // Assume core # is same as logical processor for now
574                 // TODO FIX THIS FIX THIS
575                 // THERE SHOULD BE:  guestapicid->virtualapicid map,
576                 //                   cpu_id->logical processor map
577                 //     host maitains logical proc->phsysical proc
578                 PrintDebug(" non-local core, forcing it to exit\n"); 
579
580                 v3_interrupt_cpu(core->vm_info, dst_core->cpu_id, 0);
581             }
582
583             break;
584         case 5: { //INIT
585
586             PrintDebug(" INIT delivery to core %u\n", dst_core->cpu_id);
587
588             // TODO: any APIC reset on dest core (shouldn't be needed, but not sure...)
589
590             // Sanity check
591             if (dst_apic->ipi_state != INIT_ST) { 
592                 PrintError(" Warning: core %u is not in INIT state (mode = %d), ignored\n",
593                            dst_core->cpu_id, dst_core->cpu_mode);
594                 // Only a warning, since INIT INIT SIPI is common
595                 break;
596             }
597
598             // We transition the target core to SIPI state
599             dst_apic->ipi_state = SIPI;  // note: locking should not be needed here
600
601             // That should be it since the target core should be
602             // waiting in host on this transition
603             // either it's on another core or on a different preemptive thread
604             // in both cases, it will quickly notice this transition 
605             // in particular, we should not need to force an exit here
606
607             PrintDebug(" INIT delivery done\n");
608
609             break;                                                      
610         }
611         case 6: { //SIPI
612
613             // Sanity check
614             if (dst_apic->ipi_state != SIPI) { 
615                 PrintError(" core %u is not in SIPI state (mode = %d), ignored!\n",
616                            dst_core->cpu_id, dst_core->cpu_mode);
617                 break;
618             }
619
620             // Write the RIP, CS, and descriptor
621             // assume the rest is already good to go
622             //
623             // vector VV -> rip at 0
624             //              CS = VV00
625             //  This means we start executing at linear address VV000
626             //
627             // So the selector needs to be VV00
628             // and the base needs to be VV000
629             //
630             dst_core->rip = 0;
631             dst_core->segments.cs.selector = vector << 8;
632             dst_core->segments.cs.limit = 0xffff;
633             dst_core->segments.cs.base = vector << 12;
634
635             PrintDebug(" SIPI delivery (0x%x -> 0x%x:0x0) to core %u\n",
636                        vec, dst_core->segments.cs.selector, dst_core->cpu_id);
637             // Maybe need to adjust the APIC?
638             
639             // We transition the target core to SIPI state
640             dst_core->core_run_state = CORE_RUNNING;  // note: locking should not be needed here
641             dst_apic->ipi_state = STARTED;
642
643             // As with INIT, we should not need to do anything else
644
645             PrintDebug(" SIPI delivery done\n");
646
647             break;                                                      
648         }
649         case 2: // SMI                  
650         case 3: // reserved                                             
651         case 4: // NMI                                  
652         case 7: // ExtInt
653         default:
654             PrintError("IPI %d delivery is unsupported\n", del_mode); 
655             return -1;
656     }
657
658     return 0;
659
660 }
661
662
663 static int route_ipi(struct apic_dev_state * apic_dev,
664                      struct apic_state * src_apic, 
665                      struct int_cmd_reg * icr) {
666     struct apic_state * dest_apic = NULL;
667
668     PrintDebug("icc_bus: icc_bus=%p, src_apic=%u, icr_data=%llx, extirq=%u\n", 
669                icc_bus, src_apic, icr_data, extirq);
670
671
672     if ((icr->dst_mode == 0) && (icr->dst >= apic_dev->num_apics)) { 
673         PrintError("icc_bus: Attempted send to unregistered apic id=%u\n", 
674                    icr->dst);
675         return -1;
676     }
677
678     dest_apic =  &(apic_dev->apics[icr->dst]);
679
680
681     PrintDebug("icc_bus: IPI %s %u from %s %u to %s %s %u (icr=0x%llx, extirq=%u)\n",
682                deliverymode_str[icr->del_mode], 
683                icr->vec, 
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(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(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 (src_apic == NULL) {
731                 PrintError("Sending IPI to self from generic IPI sender\n");
732                 break;
733             }
734
735             if (icr->dst_mode == 0) { 
736                 if (deliver_ipi(src_apic, src_apic, icr->vec, icr->del_mode) == -1) {
737                     PrintError("Could not deliver IPI\n");
738                     return -1;
739                 }
740             } else {
741                 // logical delivery
742                 PrintError("icc_bus: use of logical delivery in self is not yet supported.\n");
743                 return -1;
744             }
745             break;
746             
747         case 2: 
748         case 3: { // all and all-but-me
749             // assuming that logical verus physical doesn't matter
750             // although it is odd that both are used
751             int i;
752
753             for (i = 0; i < apic_dev->num_apics; i++) { 
754                 dest_apic = &(apic_dev->apics[i]);
755
756                 if ((dest_apic != src_apic) || (icr->dst_shorthand == 2)) { 
757                     if (deliver_ipi(src_apic, dest_apic, icr->vec, icr->del_mode) == -1) {
758                         PrintError("Error: Could not deliver IPI\n");
759                         return -1;
760                     }
761                 }
762             }   
763
764             break;
765         }
766         default:
767             PrintError("Error routing IPI, invalid Mode (%d)\n", icr->dst_shorthand);
768             return -1;
769     }
770     
771
772     return 0;
773 }
774
775
776
777 static int apic_read(struct guest_info * core, addr_t guest_addr, void * dst, uint_t length, void * priv_data) {
778     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(priv_data);
779     struct apic_state * apic = &(apic_dev->apics[core->cpu_id]);
780     addr_t reg_addr  = guest_addr - apic->base_addr;
781     struct apic_msr * msr = (struct apic_msr *)&(apic->base_addr_msr.value);
782     uint32_t val = 0;
783
784
785     PrintDebug("apic %u: core %u: at %p: Read apic address space (%p)\n",
786                apic->lapic_id.val, core->cpu_id, apic, (void *)guest_addr);
787
788     if (msr->apic_enable == 0) {
789         PrintError("apic %u: core %u: Read from APIC address space with disabled APIC, apic msr=0x%llx\n",
790                    apic->lapic_id.val, core->cpu_id, apic->base_addr_msr.value);
791
792         return -1;
793     }
794
795
796     /* Because "May not be supported" doesn't matter to Linux developers... */
797     /*   if (length != 4) { */
798     /*     PrintError("Invalid apic read length (%d)\n", length); */
799     /*     return -1; */
800     /*   } */
801
802     switch (reg_addr & ~0x3) {
803         case EOI_OFFSET:
804             // Well, only an idiot would read from a architectural write only register
805             // Oh, Hello Linux.
806             //    PrintError("Attempting to read from write only register\n");
807             //    return -1;
808             break;
809
810             // data registers
811         case APIC_ID_OFFSET:
812             val = apic->lapic_id.val;
813             break;
814         case APIC_VERSION_OFFSET:
815             val = apic->apic_ver.val;
816             break;
817         case TPR_OFFSET:
818             val = apic->task_prio.val;
819             break;
820         case APR_OFFSET:
821             val = apic->arb_prio.val;
822             break;
823         case PPR_OFFSET:
824             val = apic->proc_prio.val;
825             break;
826         case REMOTE_READ_OFFSET:
827             val = apic->rem_rd_data;
828             break;
829         case LDR_OFFSET:
830             val = apic->log_dst.val;
831             break;
832         case DFR_OFFSET:
833             val = apic->dst_fmt.val;
834             break;
835         case SPURIOUS_INT_VEC_OFFSET:
836             val = apic->spurious_int.val;
837             break;
838         case ESR_OFFSET:
839             val = apic->err_status.val;
840             break;
841         case TMR_LOC_VEC_TBL_OFFSET:
842             val = apic->tmr_vec_tbl.val;
843             break;
844         case LINT0_VEC_TBL_OFFSET:
845             val = apic->lint0_vec_tbl.val;
846             break;
847         case LINT1_VEC_TBL_OFFSET:
848             val = apic->lint1_vec_tbl.val;
849             break;
850         case ERR_VEC_TBL_OFFSET:
851             val = apic->err_vec_tbl.val;
852             break;
853         case TMR_INIT_CNT_OFFSET:
854             val = apic->tmr_init_cnt;
855             break;
856         case TMR_DIV_CFG_OFFSET:
857             val = apic->tmr_div_cfg.val;
858             break;
859
860         case IER_OFFSET0:
861             val = *(uint32_t *)(apic->int_en_reg);
862             break;
863         case IER_OFFSET1:
864             val = *(uint32_t *)(apic->int_en_reg + 4);
865             break;
866         case IER_OFFSET2:
867             val = *(uint32_t *)(apic->int_en_reg + 8);
868             break;
869         case IER_OFFSET3:
870             val = *(uint32_t *)(apic->int_en_reg + 12);
871             break;
872         case IER_OFFSET4:
873             val = *(uint32_t *)(apic->int_en_reg + 16);
874             break;
875         case IER_OFFSET5:
876             val = *(uint32_t *)(apic->int_en_reg + 20);
877             break;
878         case IER_OFFSET6:
879             val = *(uint32_t *)(apic->int_en_reg + 24);
880             break;
881         case IER_OFFSET7:
882             val = *(uint32_t *)(apic->int_en_reg + 28);
883             break;
884
885         case ISR_OFFSET0:
886             val = *(uint32_t *)(apic->int_svc_reg);
887             break;
888         case ISR_OFFSET1:
889             val = *(uint32_t *)(apic->int_svc_reg + 4);
890             break;
891         case ISR_OFFSET2:
892             val = *(uint32_t *)(apic->int_svc_reg + 8);
893             break;
894         case ISR_OFFSET3:
895             val = *(uint32_t *)(apic->int_svc_reg + 12);
896             break;
897         case ISR_OFFSET4:
898             val = *(uint32_t *)(apic->int_svc_reg + 16);
899             break;
900         case ISR_OFFSET5:
901             val = *(uint32_t *)(apic->int_svc_reg + 20);
902             break;
903         case ISR_OFFSET6:
904             val = *(uint32_t *)(apic->int_svc_reg + 24);
905             break;
906         case ISR_OFFSET7:
907             val = *(uint32_t *)(apic->int_svc_reg + 28);
908             break;
909    
910         case TRIG_OFFSET0:
911             val = *(uint32_t *)(apic->trig_mode_reg);
912             break;
913         case TRIG_OFFSET1:
914             val = *(uint32_t *)(apic->trig_mode_reg + 4);
915             break;
916         case TRIG_OFFSET2:
917             val = *(uint32_t *)(apic->trig_mode_reg + 8);
918             break;
919         case TRIG_OFFSET3:
920             val = *(uint32_t *)(apic->trig_mode_reg + 12);
921             break;
922         case TRIG_OFFSET4:
923             val = *(uint32_t *)(apic->trig_mode_reg + 16);
924             break;
925         case TRIG_OFFSET5:
926             val = *(uint32_t *)(apic->trig_mode_reg + 20);
927             break;
928         case TRIG_OFFSET6:
929             val = *(uint32_t *)(apic->trig_mode_reg + 24);
930             break;
931         case TRIG_OFFSET7:
932             val = *(uint32_t *)(apic->trig_mode_reg + 28);
933             break;
934
935         case IRR_OFFSET0:
936             val = *(uint32_t *)(apic->int_req_reg);
937             break;
938         case IRR_OFFSET1:
939             val = *(uint32_t *)(apic->int_req_reg + 4);
940             break;
941         case IRR_OFFSET2:
942             val = *(uint32_t *)(apic->int_req_reg + 8);
943             break;
944         case IRR_OFFSET3:
945             val = *(uint32_t *)(apic->int_req_reg + 12);
946             break;
947         case IRR_OFFSET4:
948             val = *(uint32_t *)(apic->int_req_reg + 16);
949             break;
950         case IRR_OFFSET5:
951             val = *(uint32_t *)(apic->int_req_reg + 20);
952             break;
953         case IRR_OFFSET6:
954             val = *(uint32_t *)(apic->int_req_reg + 24);
955             break;
956         case IRR_OFFSET7:
957             val = *(uint32_t *)(apic->int_req_reg + 28);
958             break;
959         case TMR_CUR_CNT_OFFSET:
960             val = apic->tmr_cur_cnt;
961             break;
962
963             // We are not going to implement these....
964         case THERM_LOC_VEC_TBL_OFFSET:
965             val = apic->therm_loc_vec_tbl.val;
966             break;
967         case PERF_CTR_LOC_VEC_TBL_OFFSET:
968             val = apic->perf_ctr_loc_vec_tbl.val;
969             break;
970
971  
972
973             // handled registers
974         case INT_CMD_LO_OFFSET:    
975             val = apic->int_cmd.lo;
976             break;
977         case INT_CMD_HI_OFFSET:
978             val = apic->int_cmd.hi;
979             break;
980
981             // handle current timer count
982
983             // Unhandled Registers
984         case EXT_INT_LOC_VEC_TBL_OFFSET0:
985             val = apic->ext_intr_vec_tbl[0].val;
986             break;
987         case EXT_INT_LOC_VEC_TBL_OFFSET1:
988             val = apic->ext_intr_vec_tbl[1].val;
989             break;
990         case EXT_INT_LOC_VEC_TBL_OFFSET2:
991             val = apic->ext_intr_vec_tbl[2].val;
992             break;
993         case EXT_INT_LOC_VEC_TBL_OFFSET3:
994             val = apic->ext_intr_vec_tbl[3].val;
995             break;
996     
997
998         case EXT_APIC_FEATURE_OFFSET:
999         case EXT_APIC_CMD_OFFSET:
1000         case SEOI_OFFSET:
1001
1002         default:
1003             PrintError("apic %u: core %u: Read from Unhandled APIC Register: %x (getting zero)\n", 
1004                        apic->lapic_id.val, core->cpu_id, (uint32_t)reg_addr);
1005             return -1;
1006     }
1007
1008
1009     if (length == 1) {
1010         uint_t byte_addr = reg_addr & 0x3;
1011         uint8_t * val_ptr = (uint8_t *)dst;
1012     
1013         *val_ptr = *(((uint8_t *)&val) + byte_addr);
1014
1015     } else if ((length == 2) && 
1016                ((reg_addr & 0x3) == 0x3)) {
1017         uint_t byte_addr = reg_addr & 0x3;
1018         uint16_t * val_ptr = (uint16_t *)dst;
1019         *val_ptr = *(((uint16_t *)&val) + byte_addr);
1020
1021     } else if (length == 4) {
1022         uint32_t * val_ptr = (uint32_t *)dst;
1023         *val_ptr = val;
1024
1025     } else {
1026         PrintError("apic %u: core %u: Invalid apic read length (%d)\n", 
1027                    apic->lapic_id.val, core->cpu_id, length);
1028         return -1;
1029     }
1030
1031     PrintDebug("apic %u: core %u: Read finished (val=%x)\n", 
1032                apic->lapic_id.val, core->cpu_id, *(uint32_t *)dst);
1033
1034     return length;
1035 }
1036
1037
1038 /**
1039  *
1040  */
1041 static int apic_write(struct guest_info * core, addr_t guest_addr, void * src, uint_t length, void * priv_data) {
1042     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(priv_data);
1043     struct apic_state * apic = &(apic_dev->apics[core->cpu_id]); 
1044     addr_t reg_addr  = guest_addr - apic->base_addr;
1045     struct apic_msr * msr = (struct apic_msr *)&(apic->base_addr_msr.value);
1046     uint32_t op_val = *(uint32_t *)src;
1047
1048     PrintDebug("apic %u: core %u: at %p and priv_data is at %p\n",
1049                apic->lapic_id.val, core->cpu_id, apic, priv_data);
1050
1051     PrintDebug("Write to address space (%p) (val=%x)\n", 
1052                (void *)guest_addr, *(uint32_t *)src);
1053
1054     if (msr->apic_enable == 0) {
1055         PrintError("apic %u: core %u: Write to APIC address space with disabled APIC, apic msr=0x%llx\n",
1056                    apic->lapic_id.val, core->cpu_id, apic->base_addr_msr.value);
1057         return -1;
1058     }
1059
1060
1061     if (length != 4) {
1062         PrintError("apic %u: core %u: Invalid apic write length (%d)\n", 
1063                    apic->lapic_id.val, length, core->cpu_id);
1064         return -1;
1065     }
1066
1067     switch (reg_addr) {
1068         case REMOTE_READ_OFFSET:
1069         case APIC_VERSION_OFFSET:
1070         case APR_OFFSET:
1071         case IRR_OFFSET0:
1072         case IRR_OFFSET1:
1073         case IRR_OFFSET2:
1074         case IRR_OFFSET3:
1075         case IRR_OFFSET4:
1076         case IRR_OFFSET5:
1077         case IRR_OFFSET6:
1078         case IRR_OFFSET7:
1079         case ISR_OFFSET0:
1080         case ISR_OFFSET1:
1081         case ISR_OFFSET2:
1082         case ISR_OFFSET3:
1083         case ISR_OFFSET4:
1084         case ISR_OFFSET5:
1085         case ISR_OFFSET6:
1086         case ISR_OFFSET7:
1087         case TRIG_OFFSET0:
1088         case TRIG_OFFSET1:
1089         case TRIG_OFFSET2:
1090         case TRIG_OFFSET3:
1091         case TRIG_OFFSET4:
1092         case TRIG_OFFSET5:
1093         case TRIG_OFFSET6:
1094         case TRIG_OFFSET7:
1095         case PPR_OFFSET:
1096         case EXT_APIC_FEATURE_OFFSET:
1097
1098             PrintError("apic %u: core %u: Attempting to write to read only register %p (error)\n", 
1099                        apic->lapic_id.val, core->cpu_id, (void *)reg_addr);
1100             //  return -1;
1101
1102             break;
1103
1104             // Data registers
1105         case APIC_ID_OFFSET:
1106             PrintDebug("apic %u: core %u: my id is being changed to %u\n", 
1107                        apic->lapic_id.val, core->cpu_id, op_val);
1108
1109             apic->lapic_id.val = op_val;
1110             break;
1111         case TPR_OFFSET:
1112             apic->task_prio.val = op_val;
1113             break;
1114         case LDR_OFFSET:
1115             PrintDebug("apic %u: core %u: setting log_dst.val to 0x%x\n",
1116                        apic->lapic_id.val, core->cpu_id, op_val);
1117             apic->log_dst.val = op_val;
1118             break;
1119         case DFR_OFFSET:
1120             apic->dst_fmt.val = op_val;
1121             break;
1122         case SPURIOUS_INT_VEC_OFFSET:
1123             apic->spurious_int.val = op_val;
1124             break;
1125         case ESR_OFFSET:
1126             apic->err_status.val = op_val;
1127             break;
1128         case TMR_LOC_VEC_TBL_OFFSET:
1129             apic->tmr_vec_tbl.val = op_val;
1130             break;
1131         case THERM_LOC_VEC_TBL_OFFSET:
1132             apic->therm_loc_vec_tbl.val = op_val;
1133             break;
1134         case PERF_CTR_LOC_VEC_TBL_OFFSET:
1135             apic->perf_ctr_loc_vec_tbl.val = op_val;
1136             break;
1137         case LINT0_VEC_TBL_OFFSET:
1138             apic->lint0_vec_tbl.val = op_val;
1139             break;
1140         case LINT1_VEC_TBL_OFFSET:
1141             apic->lint1_vec_tbl.val = op_val;
1142             break;
1143         case ERR_VEC_TBL_OFFSET:
1144             apic->err_vec_tbl.val = op_val;
1145             break;
1146         case TMR_INIT_CNT_OFFSET:
1147             apic->tmr_init_cnt = op_val;
1148             apic->tmr_cur_cnt = op_val;
1149             break;
1150         case TMR_CUR_CNT_OFFSET:
1151             apic->tmr_cur_cnt = op_val;
1152             break;
1153         case TMR_DIV_CFG_OFFSET:
1154             apic->tmr_div_cfg.val = op_val;
1155             break;
1156
1157
1158             // Enable mask (256 bits)
1159         case IER_OFFSET0:
1160             *(uint32_t *)(apic->int_en_reg) = op_val;
1161             break;
1162         case IER_OFFSET1:
1163             *(uint32_t *)(apic->int_en_reg + 4) = op_val;
1164             break;
1165         case IER_OFFSET2:
1166             *(uint32_t *)(apic->int_en_reg + 8) = op_val;
1167             break;
1168         case IER_OFFSET3:
1169             *(uint32_t *)(apic->int_en_reg + 12) = op_val;
1170             break;
1171         case IER_OFFSET4:
1172             *(uint32_t *)(apic->int_en_reg + 16) = op_val;
1173             break;
1174         case IER_OFFSET5:
1175             *(uint32_t *)(apic->int_en_reg + 20) = op_val;
1176             break;
1177         case IER_OFFSET6:
1178             *(uint32_t *)(apic->int_en_reg + 24) = op_val;
1179             break;
1180         case IER_OFFSET7:
1181             *(uint32_t *)(apic->int_en_reg + 28) = op_val;
1182             break;
1183
1184         case EXT_INT_LOC_VEC_TBL_OFFSET0:
1185             apic->ext_intr_vec_tbl[0].val = op_val;
1186             break;
1187         case EXT_INT_LOC_VEC_TBL_OFFSET1:
1188             apic->ext_intr_vec_tbl[1].val = op_val;
1189             break;
1190         case EXT_INT_LOC_VEC_TBL_OFFSET2:
1191             apic->ext_intr_vec_tbl[2].val = op_val;
1192             break;
1193         case EXT_INT_LOC_VEC_TBL_OFFSET3:
1194             apic->ext_intr_vec_tbl[3].val = op_val;
1195             break;
1196
1197
1198             // Action Registers
1199         case EOI_OFFSET:
1200             // do eoi
1201             apic_do_eoi(apic);
1202             break;
1203
1204         case INT_CMD_LO_OFFSET:
1205             apic->int_cmd.lo = op_val;
1206
1207             PrintDebug("apic %u: core %u: sending cmd 0x%llx to apic %u\n", 
1208                        apic->lapic_id.val, core->cpu_id,
1209                        apic->int_cmd.val, apic->int_cmd.dst);
1210
1211             if (route_ipi(apic_dev, apic, &(apic->int_cmd)) == -1) { 
1212                 PrintError("IPI Routing failure\n");
1213                 return -1;
1214             }
1215
1216             break;
1217
1218         case INT_CMD_HI_OFFSET:
1219             apic->int_cmd.hi = op_val;
1220             break;
1221
1222
1223         // Unhandled Registers
1224         case EXT_APIC_CMD_OFFSET:
1225         case SEOI_OFFSET:
1226         default:
1227             PrintError("apic %u: core %u: Write to Unhandled APIC Register: %x (ignored)\n", 
1228                        apic->lapic_id.val, core->cpu_id, (uint32_t)reg_addr);
1229
1230             return -1;
1231     }
1232
1233     PrintDebug("apic %u: core %u: Write finished\n", apic->lapic_id.val, core->cpu_id);
1234
1235     return length;
1236 }
1237
1238
1239
1240 /* Interrupt Controller Functions */
1241
1242 // returns 1 if an interrupt is pending, 0 otherwise
1243 static int apic_intr_pending(struct guest_info * core, void * private_data) {
1244     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(private_data);
1245     struct apic_state * apic = &(apic_dev->apics[core->cpu_id]); 
1246     int req_irq = get_highest_irr(apic);
1247     int svc_irq = get_highest_isr(apic);
1248
1249     //    PrintDebug("apic %u: core %u: req_irq=%d, svc_irq=%d\n",apic->lapic_id.val,info->cpu_id,req_irq,svc_irq);
1250
1251     if ((req_irq >= 0) && 
1252         (req_irq > svc_irq)) {
1253         return 1;
1254     }
1255
1256     return 0;
1257 }
1258
1259 static int apic_get_intr_number(struct guest_info * core, void * private_data) {
1260     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(private_data);
1261     struct apic_state * apic = &(apic_dev->apics[core->cpu_id]); 
1262     int req_irq = get_highest_irr(apic);
1263     int svc_irq = get_highest_isr(apic);
1264
1265     if (svc_irq == -1) {
1266         return req_irq;
1267     } else if (svc_irq < req_irq) {
1268         return req_irq;
1269     }
1270
1271     return -1;
1272 }
1273
1274
1275 int v3_apic_send_ipi(struct v3_vm_info * vm, struct vm_device * dev, 
1276                      struct v3_gen_ipi * ipi) {
1277     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(dev->private_data);
1278     struct int_cmd_reg tmp_icr;
1279
1280     // zero out all the fields
1281     tmp_icr.val = 0;
1282
1283
1284     tmp_icr.vec = ipi->vector;
1285     tmp_icr.del_mode = ipi->mode;
1286     tmp_icr.dst_mode = ipi->logical;
1287     tmp_icr.trig_mode = ipi->trigger_mode;
1288     tmp_icr.dst_shorthand = ipi->dst_shorthand;
1289     tmp_icr.dst = ipi->dst;
1290     
1291
1292     route_ipi(apic_dev, NULL, &tmp_icr);
1293     return -1;
1294 }
1295
1296
1297 int v3_apic_raise_intr(struct v3_vm_info * vm, struct vm_device * dev, 
1298                        uint32_t irq, uint32_t dst) {
1299     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(dev->private_data);
1300     struct apic_state * apic = &(apic_dev->apics[dst]); 
1301
1302     activate_apic_irq(apic, irq);
1303
1304     if (V3_Get_CPU() != dst) {
1305         v3_interrupt_cpu(vm, dst, 0);
1306     }
1307
1308     return 0;
1309 }
1310
1311
1312
1313 static int apic_begin_irq(struct guest_info * core, void * private_data, int irq) {
1314     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(private_data);
1315     struct apic_state * apic = &(apic_dev->apics[core->cpu_id]); 
1316     int major_offset = (irq & ~0x00000007) >> 3;
1317     int minor_offset = irq & 0x00000007;
1318     uint8_t * req_location = apic->int_req_reg + major_offset;
1319     uint8_t * svc_location = apic->int_svc_reg + major_offset;
1320     uint8_t flag = 0x01 << minor_offset;
1321
1322     if (*req_location & flag) {
1323         // we will only pay attention to a begin irq if we
1324         // know that we initiated it!
1325         *svc_location |= flag;
1326         *req_location &= ~flag;
1327     } else {
1328         // do nothing... 
1329         PrintDebug("apic %u: core %u: begin irq for %d ignored since I don't own it\n",
1330                    apic->lapic_id.val, info->cpu_id, irq);
1331     }
1332
1333     return 0;
1334 }
1335
1336
1337
1338
1339 /* Timer Functions */
1340 static void apic_update_time(struct guest_info * core, 
1341                              uint64_t cpu_cycles, uint64_t cpu_freq, 
1342                              void * priv_data) {
1343     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(priv_data);
1344     struct apic_state * apic = &(apic_dev->apics[core->cpu_id]); 
1345
1346     // The 32 bit GCC runtime is a pile of shit
1347 #ifdef __V3_64BIT__
1348     uint64_t tmr_ticks = 0;
1349 #else 
1350     uint32_t tmr_ticks = 0;
1351 #endif
1352
1353     uint8_t tmr_div = *(uint8_t *)&(apic->tmr_div_cfg.val);
1354     uint_t shift_num = 0;
1355
1356
1357     // Check whether this is true:
1358     //   -> If the Init count is zero then the timer is disabled
1359     //      and doesn't just blitz interrupts to the CPU
1360     if ((apic->tmr_init_cnt == 0) || 
1361         ( (apic->tmr_vec_tbl.tmr_mode == APIC_TMR_ONESHOT) &&
1362           (apic->tmr_cur_cnt == 0))) {
1363         //PrintDebug("apic %u: core %u: APIC timer not yet initialized\n",apic->lapic_id.val,info->cpu_id);
1364         return;
1365     }
1366
1367
1368     switch (tmr_div) {
1369         case APIC_TMR_DIV1:
1370             shift_num = 0;
1371             break;
1372         case APIC_TMR_DIV2:
1373             shift_num = 1;
1374             break;
1375         case APIC_TMR_DIV4:
1376             shift_num = 2;
1377             break;
1378         case APIC_TMR_DIV8:
1379             shift_num = 3;
1380             break;
1381         case APIC_TMR_DIV16:
1382             shift_num = 4;
1383             break;
1384         case APIC_TMR_DIV32:
1385             shift_num = 5;
1386             break;
1387         case APIC_TMR_DIV64:
1388             shift_num = 6;
1389             break;
1390         case APIC_TMR_DIV128:
1391             shift_num = 7;
1392             break;
1393         default:
1394             PrintError("apic %u: core %u: Invalid Timer Divider configuration\n",
1395                        apic->lapic_id.val, core->cpu_id);
1396             return;
1397     }
1398
1399     tmr_ticks = cpu_cycles >> shift_num;
1400     //    PrintDebug("Timer Ticks: %p\n", (void *)tmr_ticks);
1401
1402     if (tmr_ticks < apic->tmr_cur_cnt) {
1403         apic->tmr_cur_cnt -= tmr_ticks;
1404     } else {
1405         tmr_ticks -= apic->tmr_cur_cnt;
1406         apic->tmr_cur_cnt = 0;
1407
1408         // raise irq
1409         PrintDebug("apic %u: core %u: Raising APIC Timer interrupt (periodic=%d) (icnt=%d) (div=%d)\n",
1410                    apic->lapic_id.val, info->cpu_id,
1411                    apic->tmr_vec_tbl.tmr_mode, apic->tmr_init_cnt, shift_num);
1412
1413         if (apic_intr_pending(core, priv_data)) {
1414             PrintDebug("apic %u: core %u: Overriding pending IRQ %d\n", 
1415                        apic->lapic_id.val, info->cpu_id, 
1416                        apic_get_intr_number(info, priv_data));
1417         }
1418
1419         if (activate_internal_irq(apic, APIC_TMR_INT) == -1) {
1420             PrintError("apic %u: core %u: Could not raise Timer interrupt\n",
1421                        apic->lapic_id.val, core->cpu_id);
1422         }
1423     
1424         if (apic->tmr_vec_tbl.tmr_mode == APIC_TMR_PERIODIC) {
1425             tmr_ticks = tmr_ticks % apic->tmr_init_cnt;
1426             apic->tmr_cur_cnt = apic->tmr_init_cnt - tmr_ticks;
1427         }
1428     }
1429
1430
1431 }
1432
1433
1434 static struct intr_ctrl_ops intr_ops = {
1435     .intr_pending = apic_intr_pending,
1436     .get_intr_number = apic_get_intr_number,
1437     .begin_irq = apic_begin_irq,
1438 };
1439
1440
1441 static struct vm_timer_ops timer_ops = {
1442     .update_timer = apic_update_time,
1443 };
1444
1445
1446
1447
1448 static int apic_free(struct vm_device * dev) {
1449
1450     /* TODO: This should crosscall to force an unhook on each CPU */
1451
1452     //   struct apic_state * apic = (struct apic_state *)dev->private_data;
1453
1454     v3_unhook_msr(dev->vm, BASE_ADDR_MSR);
1455
1456     return 0;
1457 }
1458
1459
1460 static struct v3_device_ops dev_ops = {
1461     .free = apic_free,
1462     .reset = NULL,
1463     .start = NULL,
1464     .stop = NULL,
1465 };
1466
1467
1468
1469
1470
1471 static int apic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
1472     char * dev_id = v3_cfg_val(cfg, "ID");
1473     struct apic_dev_state * apic_dev = NULL;
1474     int i = 0;
1475
1476     PrintDebug("apic: creating an APIC for each core\n");
1477
1478     apic_dev = (struct apic_dev_state *)V3_Malloc(sizeof(struct apic_dev_state) + 
1479                                                   sizeof(struct apic_state) * vm->num_cores);
1480
1481     apic_dev->num_apics = vm->num_cores;
1482
1483     struct vm_device * dev = v3_allocate_device(dev_id, &dev_ops, apic_dev);
1484
1485     if (v3_attach_device(vm, dev) == -1) {
1486         PrintError("apic: Could not attach device %s\n", dev_id);
1487         return -1;
1488     }
1489
1490     
1491     for (i = 0; i < vm->num_cores; i++) {
1492         struct apic_state * apic = &(apic_dev->apics[i]);
1493         struct guest_info * core = &(vm->cores[i]);
1494
1495         apic->core = core;
1496
1497         init_apic_state(apic, i);
1498
1499         v3_register_intr_controller(core, &intr_ops, apic_dev);
1500
1501         v3_add_timer(core, &timer_ops, apic_dev);
1502
1503         v3_hook_full_mem(vm, core->cpu_id, apic->base_addr, apic->base_addr + PAGE_SIZE_4KB, apic_read, apic_write, apic_dev);
1504
1505         PrintDebug("apic %u: (setup device): done, my id is %u\n", i, apic->lapic_id.val);
1506     }
1507
1508 #ifdef CONFIG_DEBUG_APIC
1509     for (i = 0; i < vm->num_cores; i++) {
1510         struct apic_state * apic = &(apic_dev->apics[i]);
1511         PrintDebug("apic: sanity check: apic %u (at %p) has id %u and msr value %llx\n",
1512                    i, apic, apic->lapic_id.val, apic->base_addr_msr.value);
1513     }
1514 #endif
1515
1516
1517     PrintDebug("apic: priv_data is at %p\n", apic_dev);
1518
1519     v3_hook_msr(vm, BASE_ADDR_MSR, read_apic_msr, write_apic_msr, apic_dev);
1520
1521     return 0;
1522 }
1523
1524
1525
1526 device_register("LAPIC", apic_init)