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.


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