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.


Updated devices to remove vm_device dependencies.
[palacios.git] / palacios / src / devices / apic.c
1 /* 
2  * This file is part of the Palacios Virtual Machine Monitor developed
3  * by the V3VEE Project with funding from the United States National 
4  * Science Foundation and the Department of Energy.  
5  *
6  * The V3VEE Project is a joint project between Northwestern University
7  * and the University of New Mexico.  You can find out more at 
8  * http://www.v3vee.org
9  *
10  * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu> 
11  * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
12  * All rights reserved.
13  *
14  * Author: Jack Lange <jarusl@cs.northwestern.edu>
15  *
16  * This is free software.  You are permitted to use,
17  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
18  */
19
20
21 #include <devices/apic.h>
22 #include <devices/apic_regs.h>
23 #include <palacios/vmm.h>
24 #include <palacios/vmm_msr.h>
25 #include <palacios/vmm_sprintf.h>
26 #include <palacios/vm_guest.h>
27 #include <palacios/vmm_types.h>
28
29
30 #ifndef CONFIG_DEBUG_APIC
31 #undef PrintDebug
32 #define PrintDebug(fmt, args...)
33 #endif
34
35 #ifdef CONFIG_DEBUG_APIC
36 static char * shorthand_str[] = { 
37     "(no shorthand)",
38     "(self)",
39     "(all)",
40     "(all-but-me)",
41 };
42
43 static char * deliverymode_str[] = { 
44     "(fixed)",
45     "(lowest priority)",
46     "(SMI)",
47     "(reserved)",
48     "(NMI)",
49     "(INIT)",
50     "(Start Up)",
51     "(ExtInt)",
52 };
53 #endif
54
55 typedef enum { APIC_TMR_INT, APIC_THERM_INT, APIC_PERF_INT, 
56                APIC_LINT0_INT, APIC_LINT1_INT, APIC_ERR_INT } apic_irq_type_t;
57
58 #define APIC_FIXED_DELIVERY  0x0
59 #define APIC_SMI_DELIVERY    0x2
60 #define APIC_NMI_DELIVERY    0x4
61 #define APIC_INIT_DELIVERY   0x5
62 #define APIC_EXTINT_DELIVERY 0x7
63
64
65 #define BASE_ADDR_MSR     0x0000001B
66 #define DEFAULT_BASE_ADDR 0xfee00000
67
68 #define APIC_ID_OFFSET                    0x020
69 #define APIC_VERSION_OFFSET               0x030
70 #define TPR_OFFSET                        0x080
71 #define APR_OFFSET                        0x090
72 #define PPR_OFFSET                        0x0a0
73 #define EOI_OFFSET                        0x0b0
74 #define REMOTE_READ_OFFSET                0x0c0
75 #define LDR_OFFSET                        0x0d0
76 #define DFR_OFFSET                        0x0e0
77 #define SPURIOUS_INT_VEC_OFFSET           0x0f0
78
79 #define ISR_OFFSET0                       0x100   // 0x100 - 0x170
80 #define ISR_OFFSET1                       0x110   // 0x100 - 0x170
81 #define ISR_OFFSET2                       0x120   // 0x100 - 0x170
82 #define ISR_OFFSET3                       0x130   // 0x100 - 0x170
83 #define ISR_OFFSET4                       0x140   // 0x100 - 0x170
84 #define ISR_OFFSET5                       0x150   // 0x100 - 0x170
85 #define ISR_OFFSET6                       0x160   // 0x100 - 0x170
86 #define ISR_OFFSET7                       0x170   // 0x100 - 0x170
87
88 #define TRIG_OFFSET0                      0x180   // 0x180 - 0x1f0
89 #define TRIG_OFFSET1                      0x190   // 0x180 - 0x1f0
90 #define TRIG_OFFSET2                      0x1a0   // 0x180 - 0x1f0
91 #define TRIG_OFFSET3                      0x1b0   // 0x180 - 0x1f0
92 #define TRIG_OFFSET4                      0x1c0   // 0x180 - 0x1f0
93 #define TRIG_OFFSET5                      0x1d0   // 0x180 - 0x1f0
94 #define TRIG_OFFSET6                      0x1e0   // 0x180 - 0x1f0
95 #define TRIG_OFFSET7                      0x1f0   // 0x180 - 0x1f0
96
97
98 #define IRR_OFFSET0                       0x200   // 0x200 - 0x270
99 #define IRR_OFFSET1                       0x210   // 0x200 - 0x270
100 #define IRR_OFFSET2                       0x220   // 0x200 - 0x270
101 #define IRR_OFFSET3                       0x230   // 0x200 - 0x270
102 #define IRR_OFFSET4                       0x240   // 0x200 - 0x270
103 #define IRR_OFFSET5                       0x250   // 0x200 - 0x270
104 #define IRR_OFFSET6                       0x260   // 0x200 - 0x270
105 #define IRR_OFFSET7                       0x270   // 0x200 - 0x270
106
107
108 #define ESR_OFFSET                        0x280
109 #define INT_CMD_LO_OFFSET                 0x300
110 #define INT_CMD_HI_OFFSET                 0x310
111 #define TMR_LOC_VEC_TBL_OFFSET            0x320
112 #define THERM_LOC_VEC_TBL_OFFSET          0x330
113 #define PERF_CTR_LOC_VEC_TBL_OFFSET       0x340
114 #define LINT0_VEC_TBL_OFFSET              0x350
115 #define LINT1_VEC_TBL_OFFSET              0x360
116 #define ERR_VEC_TBL_OFFSET                0x370
117 #define TMR_INIT_CNT_OFFSET               0x380
118 #define TMR_CUR_CNT_OFFSET                0x390
119 #define TMR_DIV_CFG_OFFSET                0x3e0
120 #define EXT_APIC_FEATURE_OFFSET           0x400
121 #define EXT_APIC_CMD_OFFSET               0x410
122 #define SEOI_OFFSET                       0x420
123
124 #define IER_OFFSET0                       0x480   // 0x480 - 0x4f0
125 #define IER_OFFSET1                       0x490   // 0x480 - 0x4f0
126 #define IER_OFFSET2                       0x4a0   // 0x480 - 0x4f0
127 #define IER_OFFSET3                       0x4b0   // 0x480 - 0x4f0
128 #define IER_OFFSET4                       0x4c0   // 0x480 - 0x4f0
129 #define IER_OFFSET5                       0x4d0   // 0x480 - 0x4f0
130 #define IER_OFFSET6                       0x4e0   // 0x480 - 0x4f0
131 #define IER_OFFSET7                       0x4f0   // 0x480 - 0x4f0
132
133 #define EXT_INT_LOC_VEC_TBL_OFFSET0       0x500   // 0x500 - 0x530
134 #define EXT_INT_LOC_VEC_TBL_OFFSET1       0x510   // 0x500 - 0x530
135 #define EXT_INT_LOC_VEC_TBL_OFFSET2       0x520   // 0x500 - 0x530
136 #define EXT_INT_LOC_VEC_TBL_OFFSET3       0x530   // 0x500 - 0x530
137
138 struct apic_msr {
139     union {
140         uint64_t value;
141         struct {
142             uint8_t rsvd;
143             uint8_t bootstrap_cpu : 1;
144             uint8_t rsvd2         : 2;
145             uint8_t apic_enable   : 1;
146             uint64_t base_addr    : 40;
147             uint32_t rsvd3        : 12;
148         } __attribute__((packed));
149     } __attribute__((packed));
150 } __attribute__((packed));
151
152
153
154 typedef enum {INIT_ST, 
155               SIPI, 
156               STARTED} ipi_state_t; 
157
158 struct apic_dev_state;
159
160 struct apic_state {
161     addr_t base_addr;
162
163     /* MSRs */
164     struct apic_msr base_addr_msr;
165
166
167     /* memory map registers */
168
169     struct lapic_id_reg lapic_id;
170     struct apic_ver_reg apic_ver;
171     struct ext_apic_ctrl_reg ext_apic_ctrl;
172     struct local_vec_tbl_reg local_vec_tbl;
173     struct tmr_vec_tbl_reg tmr_vec_tbl;
174     struct tmr_div_cfg_reg tmr_div_cfg;
175     struct lint_vec_tbl_reg lint0_vec_tbl;
176     struct lint_vec_tbl_reg lint1_vec_tbl;
177     struct perf_ctr_loc_vec_tbl_reg perf_ctr_loc_vec_tbl;
178     struct therm_loc_vec_tbl_reg therm_loc_vec_tbl;
179     struct err_vec_tbl_reg err_vec_tbl;
180     struct err_status_reg err_status;
181     struct spurious_int_reg spurious_int;
182     struct int_cmd_reg int_cmd;
183     struct log_dst_reg log_dst;
184     struct dst_fmt_reg dst_fmt;
185     struct arb_prio_reg arb_prio;
186     struct task_prio_reg task_prio;
187     struct proc_prio_reg proc_prio;
188     struct ext_apic_feature_reg ext_apic_feature;
189     struct spec_eoi_reg spec_eoi;
190   
191
192     uint32_t tmr_cur_cnt;
193     uint32_t tmr_init_cnt;
194
195
196     struct local_vec_tbl_reg ext_intr_vec_tbl[4];
197
198     uint32_t rem_rd_data;
199
200
201     ipi_state_t ipi_state;
202
203     uint8_t int_req_reg[32];
204     uint8_t int_svc_reg[32];
205     uint8_t int_en_reg[32];
206     uint8_t trig_mode_reg[32];
207
208     struct guest_info * core;
209
210     struct v3_timer * timer;
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 %d: Attempting to raise an invalid interrupt: %d\n", 
352                    apic->lapic_id.val, apic->core->cpu_id, irq_num);
353         return -1;
354     }
355
356
357     PrintDebug("apic %u: core %d: Raising APIC IRQ %d\n", apic->lapic_id.val, apic->core->cpu_id, irq_num);
358
359     if (*req_location & flag) {
360         PrintDebug("Interrupt %d  coallescing\n", irq_num);
361     }
362
363     if (*en_location & flag) {
364         *req_location |= flag;
365     } else {
366         PrintDebug("apic %u: core %d: Interrupt  not enabled... %.2x\n", 
367                    apic->lapic_id.val, apic->core->cpu_id,*en_location);
368         return 0;
369     }
370
371     return 0;
372 }
373
374
375
376 static int get_highest_isr(struct apic_state * apic) {
377     int i = 0, j = 0;
378
379     // We iterate backwards to find the highest priority
380     for (i = 31; i >= 0; i--) {
381         uint8_t  * svc_major = apic->int_svc_reg + i;
382     
383         if ((*svc_major) & 0xff) {
384             for (j = 7; j >= 0; j--) {
385                 uint8_t flag = 0x1 << j;
386                 if ((*svc_major) & flag) {
387                     return ((i * 8) + j);
388                 }
389             }
390         }
391     }
392
393     return -1;
394 }
395  
396
397
398 static int get_highest_irr(struct apic_state * apic) {
399     int i = 0, j = 0;
400
401     // We iterate backwards to find the highest priority
402     for (i = 31; i >= 0; i--) {
403         uint8_t  * req_major = apic->int_req_reg + i;
404     
405         if ((*req_major) & 0xff) {
406             for (j = 7; j >= 0; j--) {
407                 uint8_t flag = 0x1 << j;
408                 if ((*req_major) & flag) {
409                     return ((i * 8) + j);
410                 }
411             }
412         }
413     }
414
415     return -1;
416 }
417  
418
419
420
421 static int apic_do_eoi(struct apic_state * apic) {
422     int isr_irq = get_highest_isr(apic);
423
424     if (isr_irq != -1) {
425         int major_offset = (isr_irq & ~0x00000007) >> 3;
426         int minor_offset = isr_irq & 0x00000007;
427         uint8_t flag = 0x1 << minor_offset;
428         uint8_t * svc_location = apic->int_svc_reg + major_offset;
429         
430         PrintDebug("apic %u: core ?: Received APIC EOI for IRQ %d\n", apic->lapic_id.val,isr_irq);
431         
432         *svc_location &= ~flag;
433
434 #ifdef CONFIG_CRAY_XT
435         
436         if ((isr_irq == 238) || 
437             (isr_irq == 239)) {
438             PrintDebug("apic %u: core ?: Acking IRQ %d\n", apic->lapic_id.val,isr_irq);
439         }
440         
441         if (isr_irq == 238) {
442             V3_ACK_IRQ(238);
443         }
444 #endif
445     } else {
446         //PrintError("apic %u: core ?: Spurious EOI...\n",apic->lapic_id.val);
447     }
448         
449     return 0;
450 }
451  
452
453 static int activate_internal_irq(struct apic_state * apic, apic_irq_type_t int_type) {
454     uint32_t vec_num = 0;
455     uint32_t del_mode = 0;
456     int masked = 0;
457
458
459     switch (int_type) {
460         case APIC_TMR_INT:
461             vec_num = apic->tmr_vec_tbl.vec;
462             del_mode = APIC_FIXED_DELIVERY;
463             masked = apic->tmr_vec_tbl.mask;
464             break;
465         case APIC_THERM_INT:
466             vec_num = apic->therm_loc_vec_tbl.vec;
467             del_mode = apic->therm_loc_vec_tbl.msg_type;
468             masked = apic->therm_loc_vec_tbl.mask;
469             break;
470         case APIC_PERF_INT:
471             vec_num = apic->perf_ctr_loc_vec_tbl.vec;
472             del_mode = apic->perf_ctr_loc_vec_tbl.msg_type;
473             masked = apic->perf_ctr_loc_vec_tbl.mask;
474             break;
475         case APIC_LINT0_INT:
476             vec_num = apic->lint0_vec_tbl.vec;
477             del_mode = apic->lint0_vec_tbl.msg_type;
478             masked = apic->lint0_vec_tbl.mask;
479             break;
480         case APIC_LINT1_INT:
481             vec_num = apic->lint1_vec_tbl.vec;
482             del_mode = apic->lint1_vec_tbl.msg_type;
483             masked = apic->lint1_vec_tbl.mask;
484             break;
485         case APIC_ERR_INT:
486             vec_num = apic->err_vec_tbl.vec;
487             del_mode = APIC_FIXED_DELIVERY;
488             masked = apic->err_vec_tbl.mask;
489             break;
490         default:
491             PrintError("apic %u: core ?: Invalid APIC interrupt type\n", apic->lapic_id.val);
492             return -1;
493     }
494
495     // interrupt is masked, don't send
496     if (masked == 1) {
497         PrintDebug("apic %u: core ?: Inerrupt is masked\n", apic->lapic_id.val);
498         return 0;
499     }
500
501     if (del_mode == APIC_FIXED_DELIVERY) {
502         //PrintDebug("Activating internal APIC IRQ %d\n", vec_num);
503         return activate_apic_irq(apic, vec_num);
504     } else {
505         PrintError("apic %u: core ?: Unhandled Delivery Mode\n", apic->lapic_id.val);
506         return -1;
507     }
508 }
509
510
511
512 static inline int should_deliver_cluster_ipi(struct guest_info * dst_core, 
513                                              struct apic_state * dst_apic, uint8_t mda) {
514
515     if  ( ((mda & 0xf0) == (dst_apic->log_dst.dst_log_id & 0xf0)) &&     // (I am in the cluster and
516           ((mda & 0x0f) & (dst_apic->log_dst.dst_log_id & 0x0f)) ) {  //  I am in the set)
517
518         PrintDebug("apic %u core %u: accepting clustered IRQ (mda 0x%x == log_dst 0x%x)\n",
519                    dst_apic->lapic_id.val, dst_core->cpu_id, mda, 
520                    dst_apic->log_dst.dst_log_id);
521         
522         return 1;
523     } else {
524         PrintDebug("apic %u core %u: rejecting clustered IRQ (mda 0x%x != log_dst 0x%x)\n",
525                    dst_apic->lapic_id.val, dst_core->cpu_id, mda, 
526                    dst_apic->log_dst.dst_log_id);
527         return 0;
528     }
529 }
530
531 static inline int should_deliver_flat_ipi(struct guest_info * dst_core,
532                                           struct apic_state * dst_apic, uint8_t mda) {
533
534     if (dst_apic->log_dst.dst_log_id & mda) {  // I am in the set 
535
536         PrintDebug("apic %u core %u: accepting flat IRQ (mda 0x%x == log_dst 0x%x)\n",
537                    dst_apic->lapic_id.val, dst_core->cpu_id, mda, 
538                    dst_apic->log_dst.dst_log_id);
539       return 1;
540   } else {
541         PrintDebug("apic %u core %u: rejecting flat IRQ (mda 0x%x != log_dst 0x%x)\n",
542                    dst_apic->lapic_id.val, dst_core->cpu_id, mda, 
543                    dst_apic->log_dst.dst_log_id);
544       return 0;
545   }
546 }
547
548
549
550 static int should_deliver_ipi(struct guest_info * dst_core, 
551                               struct apic_state * dst_apic, uint8_t mda) {
552
553
554     if (dst_apic->dst_fmt.model == 0xf) {
555
556         if (mda == 0xff) {
557             // always deliver broadcast
558             return 1;
559         }
560
561         return should_deliver_flat_ipi(dst_core, dst_apic, mda);
562     } else if (dst_apic->dst_fmt.model == 0x0) {
563
564         if (mda == 0xff) {
565             // always deliver broadcast
566             return 1;
567         }
568
569         return should_deliver_cluster_ipi(dst_core, dst_apic, mda);
570     } else {
571         PrintError("apic %u core %u: invalid destination format register value 0x%x for logical mode delivery.\n", 
572                    dst_apic->lapic_id.val, dst_core->cpu_id, dst_apic->dst_fmt.model);
573         return -1;
574     }
575 }
576
577
578 static int deliver_ipi(struct apic_state * src_apic, 
579                        struct apic_state * dst_apic, 
580                        uint32_t vector, uint8_t del_mode) {
581
582     struct guest_info * dst_core = dst_apic->core;
583
584     switch (del_mode) {
585
586         case 0:  //fixed
587         case 1: // lowest priority
588             PrintDebug("delivering IRQ %d to core %u\n", vector, dst_core->cpu_id); 
589
590             activate_apic_irq(dst_apic, vector);
591
592             if (dst_apic != src_apic) { 
593                 // Assume core # is same as logical processor for now
594                 // TODO FIX THIS FIX THIS
595                 // THERE SHOULD BE:  guestapicid->virtualapicid map,
596                 //                   cpu_id->logical processor map
597                 //     host maitains logical proc->phsysical proc
598                 PrintDebug(" non-local core, forcing it to exit\n"); 
599
600                 v3_interrupt_cpu(dst_core->vm_info, dst_core->cpu_id, 0);
601             }
602
603             break;
604         case 5: { //INIT
605
606             PrintDebug(" INIT delivery to core %u\n", dst_core->cpu_id);
607
608             // TODO: any APIC reset on dest core (shouldn't be needed, but not sure...)
609
610             // Sanity check
611             if (dst_apic->ipi_state != INIT_ST) { 
612                 PrintError(" Warning: core %u is not in INIT state (mode = %d), ignored\n",
613                            dst_core->cpu_id, dst_apic->ipi_state);
614                 // Only a warning, since INIT INIT SIPI is common
615                 break;
616             }
617
618             // We transition the target core to SIPI state
619             dst_apic->ipi_state = SIPI;  // note: locking should not be needed here
620
621             // That should be it since the target core should be
622             // waiting in host on this transition
623             // either it's on another core or on a different preemptive thread
624             // in both cases, it will quickly notice this transition 
625             // in particular, we should not need to force an exit here
626
627             PrintDebug(" INIT delivery done\n");
628
629             break;                                                      
630         }
631         case 6: { //SIPI
632
633             // Sanity check
634             if (dst_apic->ipi_state != SIPI) { 
635                 PrintError(" core %u is not in SIPI state (mode = %d), ignored!\n",
636                            dst_core->cpu_id, dst_apic->ipi_state);
637                 break;
638             }
639
640             // Write the RIP, CS, and descriptor
641             // assume the rest is already good to go
642             //
643             // vector VV -> rip at 0
644             //              CS = VV00
645             //  This means we start executing at linear address VV000
646             //
647             // So the selector needs to be VV00
648             // and the base needs to be VV000
649             //
650             dst_core->rip = 0;
651             dst_core->segments.cs.selector = vector << 8;
652             dst_core->segments.cs.limit = 0xffff;
653             dst_core->segments.cs.base = vector << 12;
654
655             PrintDebug(" SIPI delivery (0x%x -> 0x%x:0x0) to core %u\n",
656                        vector, dst_core->segments.cs.selector, dst_core->cpu_id);
657             // Maybe need to adjust the APIC?
658             
659             // We transition the target core to SIPI state
660             dst_core->core_run_state = CORE_RUNNING;  // note: locking should not be needed here
661             dst_apic->ipi_state = STARTED;
662
663             // As with INIT, we should not need to do anything else
664
665             PrintDebug(" SIPI delivery done\n");
666
667             break;                                                      
668         }
669         case 2: // SMI                  
670         case 3: // reserved                                             
671         case 4: // NMI                                  
672         case 7: // ExtInt
673         default:
674             PrintError("IPI %d delivery is unsupported\n", del_mode); 
675             return -1;
676     }
677
678     return 0;
679
680 }
681
682
683 static int route_ipi(struct apic_dev_state * apic_dev,
684                      struct apic_state * src_apic, 
685                      struct int_cmd_reg * icr) {
686     struct apic_state * dest_apic = NULL;
687
688     PrintDebug("route_ipi: src_apic=%p, icr_data=%p\n", 
689                src_apic, (void *)(addr_t)icr->val);
690
691
692     if ((icr->dst_mode == 0) && (icr->dst >= apic_dev->num_apics)) { 
693         PrintError("route_ipi: Attempted send to unregistered apic id=%u\n", 
694                    icr->dst);
695         return -1;
696     }
697
698     dest_apic =  &(apic_dev->apics[icr->dst]);
699
700
701     PrintDebug("route_ipi: IPI %s %u from apic %p to %s %s %u (icr=0x%llx)\n",
702                deliverymode_str[icr->del_mode], 
703                icr->vec, 
704                src_apic,               
705                (icr->dst_mode == 0) ? "(physical)" : "(logical)", 
706                shorthand_str[icr->dst_shorthand], 
707                icr->dst,
708                icr->val);
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("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("apic %u: core %u: write to address space (%p) (val=%x)\n", 
1070                apic->lapic_id.val, core->cpu_id, (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 v3_gen_ipi * ipi, void * dev_data) {
1294     struct apic_dev_state * apic_dev = (struct apic_dev_state *)dev_data;
1295     struct int_cmd_reg tmp_icr;
1296
1297     // zero out all the fields
1298     tmp_icr.val = 0;
1299
1300
1301     tmp_icr.vec = ipi->vector;
1302     tmp_icr.del_mode = ipi->mode;
1303     tmp_icr.dst_mode = ipi->logical;
1304     tmp_icr.trig_mode = ipi->trigger_mode;
1305     tmp_icr.dst_shorthand = ipi->dst_shorthand;
1306     tmp_icr.dst = ipi->dst;
1307     
1308
1309     return route_ipi(apic_dev, NULL, &tmp_icr);
1310 }
1311
1312
1313 int v3_apic_raise_intr(struct v3_vm_info * vm, uint32_t irq, uint32_t dst, void * dev_data) {
1314     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(dev_data);
1315     struct apic_state * apic = &(apic_dev->apics[dst]); 
1316
1317     PrintDebug("apic %u core ?: raising interrupt IRQ %u (dst = %u).\n", apic->lapic_id.val, irq, dst); 
1318
1319     activate_apic_irq(apic, irq);
1320
1321     if (V3_Get_CPU() != dst) {
1322         v3_interrupt_cpu(vm, dst, 0);
1323     }
1324
1325     return 0;
1326 }
1327
1328
1329
1330 static int apic_begin_irq(struct guest_info * core, void * private_data, int irq) {
1331     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(private_data);
1332     struct apic_state * apic = &(apic_dev->apics[core->cpu_id]); 
1333     int major_offset = (irq & ~0x00000007) >> 3;
1334     int minor_offset = irq & 0x00000007;
1335     uint8_t * req_location = apic->int_req_reg + major_offset;
1336     uint8_t * svc_location = apic->int_svc_reg + major_offset;
1337     uint8_t flag = 0x01 << minor_offset;
1338
1339     if (*req_location & flag) {
1340         // we will only pay attention to a begin irq if we
1341         // know that we initiated it!
1342         *svc_location |= flag;
1343         *req_location &= ~flag;
1344     } else {
1345         // do nothing... 
1346         //PrintDebug("apic %u: core %u: begin irq for %d ignored since I don't own it\n",
1347         //         apic->lapic_id.val, core->cpu_id, irq);
1348     }
1349
1350     return 0;
1351 }
1352
1353
1354
1355
1356 /* Timer Functions */
1357 static void apic_update_time(struct guest_info * core, 
1358                              uint64_t cpu_cycles, uint64_t cpu_freq, 
1359                              void * priv_data) {
1360     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(priv_data);
1361     struct apic_state * apic = &(apic_dev->apics[core->cpu_id]); 
1362
1363     // The 32 bit GCC runtime is a pile of shit
1364 #ifdef __V3_64BIT__
1365     uint64_t tmr_ticks = 0;
1366 #else 
1367     uint32_t tmr_ticks = 0;
1368 #endif
1369
1370     uint8_t tmr_div = *(uint8_t *)&(apic->tmr_div_cfg.val);
1371     uint_t shift_num = 0;
1372
1373
1374     // Check whether this is true:
1375     //   -> If the Init count is zero then the timer is disabled
1376     //      and doesn't just blitz interrupts to the CPU
1377     if ((apic->tmr_init_cnt == 0) || 
1378         ( (apic->tmr_vec_tbl.tmr_mode == APIC_TMR_ONESHOT) &&
1379           (apic->tmr_cur_cnt == 0))) {
1380         //PrintDebug("apic %u: core %u: APIC timer not yet initialized\n",apic->lapic_id.val,info->cpu_id);
1381         return;
1382     }
1383
1384
1385     switch (tmr_div) {
1386         case APIC_TMR_DIV1:
1387             shift_num = 0;
1388             break;
1389         case APIC_TMR_DIV2:
1390             shift_num = 1;
1391             break;
1392         case APIC_TMR_DIV4:
1393             shift_num = 2;
1394             break;
1395         case APIC_TMR_DIV8:
1396             shift_num = 3;
1397             break;
1398         case APIC_TMR_DIV16:
1399             shift_num = 4;
1400             break;
1401         case APIC_TMR_DIV32:
1402             shift_num = 5;
1403             break;
1404         case APIC_TMR_DIV64:
1405             shift_num = 6;
1406             break;
1407         case APIC_TMR_DIV128:
1408             shift_num = 7;
1409             break;
1410         default:
1411             PrintError("apic %u: core %u: Invalid Timer Divider configuration\n",
1412                        apic->lapic_id.val, core->cpu_id);
1413             return;
1414     }
1415
1416     tmr_ticks = cpu_cycles >> shift_num;
1417     //    PrintDebug("Timer Ticks: %p\n", (void *)tmr_ticks);
1418
1419     if (tmr_ticks < apic->tmr_cur_cnt) {
1420         apic->tmr_cur_cnt -= tmr_ticks;
1421     } else {
1422         tmr_ticks -= apic->tmr_cur_cnt;
1423         apic->tmr_cur_cnt = 0;
1424
1425         // raise irq
1426         PrintDebug("apic %u: core %u: Raising APIC Timer interrupt (periodic=%d) (icnt=%d) (div=%d)\n",
1427                    apic->lapic_id.val, core->cpu_id,
1428                    apic->tmr_vec_tbl.tmr_mode, apic->tmr_init_cnt, shift_num);
1429
1430         if (apic_intr_pending(core, priv_data)) {
1431             PrintDebug("apic %u: core %u: Overriding pending IRQ %d\n", 
1432                        apic->lapic_id.val, core->cpu_id, 
1433                        apic_get_intr_number(core, priv_data));
1434         }
1435
1436         if (activate_internal_irq(apic, APIC_TMR_INT) == -1) {
1437             PrintError("apic %u: core %u: Could not raise Timer interrupt\n",
1438                        apic->lapic_id.val, core->cpu_id);
1439         }
1440     
1441         if (apic->tmr_vec_tbl.tmr_mode == APIC_TMR_PERIODIC) {
1442             tmr_ticks = tmr_ticks % apic->tmr_init_cnt;
1443             apic->tmr_cur_cnt = apic->tmr_init_cnt - tmr_ticks;
1444         }
1445     }
1446
1447
1448 }
1449
1450
1451 static struct intr_ctrl_ops intr_ops = {
1452     .intr_pending = apic_intr_pending,
1453     .get_intr_number = apic_get_intr_number,
1454     .begin_irq = apic_begin_irq,
1455 };
1456
1457
1458 static struct v3_timer_ops timer_ops = {
1459     .update_timer = apic_update_time,
1460 };
1461
1462
1463
1464
1465 static int apic_free(struct vm_device * dev) {
1466     struct apic_dev_state * apic_dev = (struct apic_dev_state *)dev->private_data;
1467     int i = 0;
1468
1469     for (i = 0; i < dev->vm->num_cores; i++) {
1470         struct apic_state * apic = &(apic_dev->apics[i]);
1471         struct guest_info * core = &(dev->vm->cores[i]);
1472         
1473
1474         // unregister intr controller
1475
1476         if (apic->timer) {
1477             v3_remove_timer(core, apic->timer);
1478         }
1479
1480         // unhook memory
1481
1482     }
1483
1484     v3_unhook_msr(dev->vm, BASE_ADDR_MSR);
1485
1486     V3_Free(apic_dev);
1487     return 0;
1488 }
1489
1490
1491 static struct v3_device_ops dev_ops = {
1492     .free = apic_free,
1493 };
1494
1495
1496
1497
1498
1499 static int apic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
1500     char * dev_id = v3_cfg_val(cfg, "ID");
1501     struct apic_dev_state * apic_dev = NULL;
1502     int i = 0;
1503
1504     PrintDebug("apic: creating an APIC for each core\n");
1505
1506     apic_dev = (struct apic_dev_state *)V3_Malloc(sizeof(struct apic_dev_state) + 
1507                                                   sizeof(struct apic_state) * vm->num_cores);
1508
1509     apic_dev->num_apics = vm->num_cores;
1510
1511     struct vm_device * dev = v3_allocate_device(dev_id, &dev_ops, apic_dev);
1512
1513     if (v3_attach_device(vm, dev) == -1) {
1514         PrintError("apic: Could not attach device %s\n", dev_id);
1515         V3_Free(apic_dev);
1516         return -1;
1517     }
1518
1519     
1520     for (i = 0; i < vm->num_cores; i++) {
1521         struct apic_state * apic = &(apic_dev->apics[i]);
1522         struct guest_info * core = &(vm->cores[i]);
1523
1524         apic->core = core;
1525
1526         init_apic_state(apic, i);
1527
1528         v3_register_intr_controller(core, &intr_ops, apic_dev);
1529
1530         apic->timer = v3_add_timer(core, &timer_ops, apic_dev);
1531
1532         if (apic->timer == NULL) {
1533             PrintError("APIC: Failed to attach timer to core %d\n", i);
1534             v3_detach_device(dev);
1535             return -1;
1536         }
1537
1538         v3_hook_full_mem(vm, core->cpu_id, apic->base_addr, apic->base_addr + PAGE_SIZE_4KB, apic_read, apic_write, apic_dev);
1539
1540         PrintDebug("apic %u: (setup device): done, my id is %u\n", i, apic->lapic_id.val);
1541     }
1542
1543 #ifdef CONFIG_DEBUG_APIC
1544     for (i = 0; i < vm->num_cores; i++) {
1545         struct apic_state * apic = &(apic_dev->apics[i]);
1546         PrintDebug("apic: sanity check: apic %u (at %p) has id %u and msr value %llx\n",
1547                    i, apic, apic->lapic_id.val, apic->base_addr_msr.value);
1548     }
1549 #endif
1550
1551
1552     PrintDebug("apic: priv_data is at %p\n", apic_dev);
1553
1554     v3_hook_msr(vm, BASE_ADDR_MSR, read_apic_msr, write_apic_msr, apic_dev);
1555
1556     return 0;
1557 }
1558
1559
1560
1561 device_register("LAPIC", apic_init)