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.


Functional 2 core linux guest
[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 <devices/icc_bus.h>
24 #include <palacios/vmm.h>
25 #include <palacios/vmm_msr.h>
26 #include <palacios/vmm_sprintf.h>
27 #include <palacios/vm_guest.h>
28
29
30 #ifndef CONFIG_DEBUG_APIC
31 #undef PrintDebug
32 #define PrintDebug(fmt, args...)
33 #endif
34
35
36 typedef enum { APIC_TMR_INT, APIC_THERM_INT, APIC_PERF_INT, 
37                APIC_LINT0_INT, APIC_LINT1_INT, APIC_ERR_INT } apic_irq_type_t;
38
39 #define APIC_FIXED_DELIVERY  0x0
40 #define APIC_SMI_DELIVERY    0x2
41 #define APIC_NMI_DELIVERY    0x4
42 #define APIC_INIT_DELIVERY   0x5
43 #define APIC_EXTINT_DELIVERY 0x7
44
45
46 #define BASE_ADDR_MSR 0x0000001B
47 #define DEFAULT_BASE_ADDR 0xfee00000
48
49 #define APIC_ID_OFFSET                    0x020
50 #define APIC_VERSION_OFFSET               0x030
51 #define TPR_OFFSET                        0x080
52 #define APR_OFFSET                        0x090
53 #define PPR_OFFSET                        0x0a0
54 #define EOI_OFFSET                        0x0b0
55 #define REMOTE_READ_OFFSET                0x0c0
56 #define LDR_OFFSET                        0x0d0
57 #define DFR_OFFSET                        0x0e0
58 #define SPURIOUS_INT_VEC_OFFSET           0x0f0
59
60 #define ISR_OFFSET0                       0x100   // 0x100 - 0x170
61 #define ISR_OFFSET1                       0x110   // 0x100 - 0x170
62 #define ISR_OFFSET2                       0x120   // 0x100 - 0x170
63 #define ISR_OFFSET3                       0x130   // 0x100 - 0x170
64 #define ISR_OFFSET4                       0x140   // 0x100 - 0x170
65 #define ISR_OFFSET5                       0x150   // 0x100 - 0x170
66 #define ISR_OFFSET6                       0x160   // 0x100 - 0x170
67 #define ISR_OFFSET7                       0x170   // 0x100 - 0x170
68
69 #define TRIG_OFFSET0                      0x180   // 0x180 - 0x1f0
70 #define TRIG_OFFSET1                      0x190   // 0x180 - 0x1f0
71 #define TRIG_OFFSET2                      0x1a0   // 0x180 - 0x1f0
72 #define TRIG_OFFSET3                      0x1b0   // 0x180 - 0x1f0
73 #define TRIG_OFFSET4                      0x1c0   // 0x180 - 0x1f0
74 #define TRIG_OFFSET5                      0x1d0   // 0x180 - 0x1f0
75 #define TRIG_OFFSET6                      0x1e0   // 0x180 - 0x1f0
76 #define TRIG_OFFSET7                      0x1f0   // 0x180 - 0x1f0
77
78
79 #define IRR_OFFSET0                       0x200   // 0x200 - 0x270
80 #define IRR_OFFSET1                       0x210   // 0x200 - 0x270
81 #define IRR_OFFSET2                       0x220   // 0x200 - 0x270
82 #define IRR_OFFSET3                       0x230   // 0x200 - 0x270
83 #define IRR_OFFSET4                       0x240   // 0x200 - 0x270
84 #define IRR_OFFSET5                       0x250   // 0x200 - 0x270
85 #define IRR_OFFSET6                       0x260   // 0x200 - 0x270
86 #define IRR_OFFSET7                       0x270   // 0x200 - 0x270
87
88
89 #define ESR_OFFSET                        0x280
90 #define INT_CMD_LO_OFFSET                 0x300
91 #define INT_CMD_HI_OFFSET                 0x310
92 #define TMR_LOC_VEC_TBL_OFFSET            0x320
93 #define THERM_LOC_VEC_TBL_OFFSET          0x330
94 #define PERF_CTR_LOC_VEC_TBL_OFFSET       0x340
95 #define LINT0_VEC_TBL_OFFSET              0x350
96 #define LINT1_VEC_TBL_OFFSET              0x360
97 #define ERR_VEC_TBL_OFFSET                0x370
98 #define TMR_INIT_CNT_OFFSET               0x380
99 #define TMR_CUR_CNT_OFFSET                0x390
100 #define TMR_DIV_CFG_OFFSET                0x3e0
101 #define EXT_APIC_FEATURE_OFFSET           0x400
102 #define EXT_APIC_CMD_OFFSET               0x410
103 #define SEOI_OFFSET                       0x420
104
105 #define IER_OFFSET0                       0x480   // 0x480 - 0x4f0
106 #define IER_OFFSET1                       0x490   // 0x480 - 0x4f0
107 #define IER_OFFSET2                       0x4a0   // 0x480 - 0x4f0
108 #define IER_OFFSET3                       0x4b0   // 0x480 - 0x4f0
109 #define IER_OFFSET4                       0x4c0   // 0x480 - 0x4f0
110 #define IER_OFFSET5                       0x4d0   // 0x480 - 0x4f0
111 #define IER_OFFSET6                       0x4e0   // 0x480 - 0x4f0
112 #define IER_OFFSET7                       0x4f0   // 0x480 - 0x4f0
113
114 #define EXT_INT_LOC_VEC_TBL_OFFSET0       0x500   // 0x500 - 0x530
115 #define EXT_INT_LOC_VEC_TBL_OFFSET1       0x510   // 0x500 - 0x530
116 #define EXT_INT_LOC_VEC_TBL_OFFSET2       0x520   // 0x500 - 0x530
117 #define EXT_INT_LOC_VEC_TBL_OFFSET3       0x530   // 0x500 - 0x530
118
119
120
121
122
123 struct apic_msr {
124     union {
125         uint64_t value;
126         struct {
127             uchar_t rsvd;
128             uint_t bootstrap_cpu : 1;
129             uint_t rsvd2         : 2;
130             uint_t apic_enable   : 1;
131             ullong_t base_addr   : 40;
132             uint_t rsvd3         : 12;
133         } __attribute__((packed));
134     } __attribute__((packed));
135 } __attribute__((packed));
136
137
138 struct apic_state {
139     addr_t base_addr;
140
141     /* MSRs */
142     struct apic_msr base_addr_msr;
143
144
145     /* memory map registers */
146
147     struct lapic_id_reg lapic_id;
148     struct apic_ver_reg apic_ver;
149     struct ext_apic_ctrl_reg ext_apic_ctrl;
150     struct local_vec_tbl_reg local_vec_tbl;
151     struct tmr_vec_tbl_reg tmr_vec_tbl;
152     struct tmr_div_cfg_reg tmr_div_cfg;
153     struct lint_vec_tbl_reg lint0_vec_tbl;
154     struct lint_vec_tbl_reg lint1_vec_tbl;
155     struct perf_ctr_loc_vec_tbl_reg perf_ctr_loc_vec_tbl;
156     struct therm_loc_vec_tbl_reg therm_loc_vec_tbl;
157     struct err_vec_tbl_reg err_vec_tbl;
158     struct err_status_reg err_status;
159     struct spurious_int_reg spurious_int;
160     struct int_cmd_reg int_cmd;
161     struct log_dst_reg log_dst;
162     struct dst_fmt_reg dst_fmt;
163     struct arb_prio_reg arb_prio;
164     struct task_prio_reg task_prio;
165     struct proc_prio_reg proc_prio;
166     struct ext_apic_feature_reg ext_apic_feature;
167     struct spec_eoi_reg spec_eoi;
168   
169
170     uint32_t tmr_cur_cnt;
171     uint32_t tmr_init_cnt;
172
173
174     struct local_vec_tbl_reg ext_intr_vec_tbl[4];
175
176     uint32_t rem_rd_data;
177
178
179     uchar_t int_req_reg[32];
180     uchar_t int_svc_reg[32];
181     uchar_t int_en_reg[32];
182     uchar_t trig_mode_reg[32];
183   
184     uint32_t eoi;
185
186     struct vm_device * icc_bus;
187
188     v3_lock_t  lock;
189 };
190
191
192
193
194
195 static int apic_read(struct guest_info * core, addr_t guest_addr, void * dst, uint_t length, void * priv_data);
196 static int apic_write(struct guest_info * core, addr_t guest_addr, void * src, uint_t length, void * priv_data);
197
198 static void init_apic_state(struct apic_state * apic, uint32_t id, struct vm_device * icc) {
199     apic->base_addr = DEFAULT_BASE_ADDR;
200     if (id==0) { 
201         // boot processor, enabled
202         apic->base_addr_msr.value = 0x0000000000000900LL;
203     } else {
204         // ap processor, enabled
205         apic->base_addr_msr.value = 0x0000000000000800LL;
206     }
207
208     // same base address regardless of ap or main
209     apic->base_addr_msr.value |= ((uint64_t)DEFAULT_BASE_ADDR); 
210
211     PrintDebug("apic %u: (init_apic_state): msr=0x%llx\n",id, apic->base_addr_msr.value);
212
213     PrintDebug("apic %u: (init_apic_state): Sizeof Interrupt Request Register %d, should be 32\n",
214                id, (uint_t)sizeof(apic->int_req_reg));
215
216     memset(apic->int_req_reg, 0, sizeof(apic->int_req_reg));
217     memset(apic->int_svc_reg, 0, sizeof(apic->int_svc_reg));
218     memset(apic->int_en_reg, 0xff, sizeof(apic->int_en_reg));
219     memset(apic->trig_mode_reg, 0, sizeof(apic->trig_mode_reg));
220
221     apic->eoi = 0x00000000;
222     apic->rem_rd_data = 0x00000000;
223     apic->tmr_init_cnt = 0x00000000;
224     apic->tmr_cur_cnt = 0x00000000;
225
226     apic->lapic_id.val = id;
227     
228     apic->icc_bus = icc;
229
230     // The P6 has 6 LVT entries, so we set the value to (6-1)...
231     apic->apic_ver.val = 0x80050010;
232
233     apic->task_prio.val = 0x00000000;
234     apic->arb_prio.val = 0x00000000;
235     apic->proc_prio.val = 0x00000000;
236     apic->log_dst.val = 0x00000000;
237     apic->dst_fmt.val = 0xffffffff;
238     apic->spurious_int.val = 0x000000ff;
239     apic->err_status.val = 0x00000000;
240     apic->int_cmd.val = 0x0000000000000000LL;
241     apic->tmr_vec_tbl.val = 0x00010000;
242     apic->therm_loc_vec_tbl.val = 0x00010000;
243     apic->perf_ctr_loc_vec_tbl.val = 0x00010000;
244     apic->lint0_vec_tbl.val = 0x00010000;
245     apic->lint1_vec_tbl.val = 0x00010000;
246     apic->err_vec_tbl.val = 0x00010000;
247     apic->tmr_div_cfg.val = 0x00000000;
248     //apic->ext_apic_feature.val = 0x00000007;
249     apic->ext_apic_feature.val = 0x00040007;
250     apic->ext_apic_ctrl.val = 0x00000000;
251     apic->spec_eoi.val = 0x00000000;
252
253     v3_lock_init(&(apic->lock));
254 }
255
256
257
258
259 static int read_apic_msr(struct guest_info * core, uint_t msr, v3_msr_t * dst, void * priv_data) {
260     struct vm_device * dev = (struct vm_device *)priv_data;
261     struct apic_state * apics = (struct apic_state *)(dev->private_data);
262     struct apic_state * apic = &(apics[core->cpu_id]);
263
264     PrintDebug("apic %u: core %u: MSR read\n",apic->lapic_id.val,core->cpu_id);
265     v3_lock(apic->lock);
266     dst->value = apic->base_addr;
267     v3_unlock(apic->lock);
268     return 0;
269 }
270
271
272 static int write_apic_msr(struct guest_info * core, uint_t msr, v3_msr_t src, void * priv_data) {
273     struct vm_device * dev = (struct vm_device *)priv_data;
274     struct apic_state * apics = (struct apic_state *)(dev->private_data);
275     struct apic_state * apic = &(apics[core->cpu_id]);
276     struct v3_mem_region * old_reg = v3_get_mem_region(dev->vm, core->cpu_id, apic->base_addr);
277
278
279     PrintDebug("apic %u: core %u: MSR write\n",apic->lapic_id.val,core->cpu_id);
280
281     if (old_reg == NULL) {
282         // uh oh...
283         PrintError("apic %u: core %u: APIC Base address region does not exit...\n",apic->lapic_id.val,core->cpu_id);
284         return -1;
285     }
286     
287     v3_lock(apic->lock);
288
289     v3_delete_mem_region(dev->vm, old_reg);
290
291     apic->base_addr = src.value;
292
293     if (v3_hook_full_mem(dev->vm, core->cpu_id, apic->base_addr, apic->base_addr + PAGE_SIZE_4KB, apic_read, apic_write, dev) == -1) {
294         PrintError("apic %u: core %u: Could not hook new APIC Base address\n",apic->lapic_id.val,core->cpu_id);
295         v3_unlock(apic->lock);
296         return -1;
297     }
298
299     v3_unlock(apic->lock);
300     return 0;
301 }
302
303
304 // irq_num is the bit offset into a 256 bit buffer...
305 static int activate_apic_irq(struct apic_state * apic, uint32_t irq_num) {
306     int major_offset = (irq_num & ~0x00000007) >> 3;
307     int minor_offset = irq_num & 0x00000007;
308     uchar_t * req_location = apic->int_req_reg + major_offset;
309     uchar_t * en_location = apic->int_en_reg + major_offset;
310     uchar_t flag = 0x1 << minor_offset;
311
312
313 #if 1
314
315     if (irq_num <= 15) {
316         PrintError("apic %u: core ?: Attempting to raise an invalid interrupt: %d\n", apic->lapic_id.val,irq_num);
317         return -1;
318     }
319
320 #endif
321
322
323     PrintDebug("apic %u: core ?: Raising APIC IRQ %d\n", apic->lapic_id.val,irq_num);
324
325     if (*req_location & flag) {
326         //V3_Print("Interrupts coallescing\n");
327     }
328
329     if (*en_location & flag) {
330         *req_location |= flag;
331     } else {
332         PrintDebug("apic %u: core ?: Interrupt  not enabled... %.2x\n", apic->lapic_id.val, *en_location);
333         return 0;
334     }
335
336     return 0;
337 }
338
339
340
341 static int get_highest_isr(struct apic_state * apic) {
342     int i = 0, j = 0;
343
344     // We iterate backwards to find the highest priority
345     for (i = 31; i >= 0; i--) {
346         uchar_t  * svc_major = apic->int_svc_reg + i;
347     
348         if ((*svc_major) & 0xff) {
349             for (j = 7; j >= 0; j--) {
350                 uchar_t flag = 0x1 << j;
351                 if ((*svc_major) & flag) {
352                     return ((i * 8) + j);
353                 }
354             }
355         }
356     }
357
358     return -1;
359 }
360  
361
362
363 static int get_highest_irr(struct apic_state * apic) {
364     int i = 0, j = 0;
365
366     // We iterate backwards to find the highest priority
367     for (i = 31; i >= 0; i--) {
368         uchar_t  * req_major = apic->int_req_reg + i;
369     
370         if ((*req_major) & 0xff) {
371             for (j = 7; j >= 0; j--) {
372                 uchar_t flag = 0x1 << j;
373                 if ((*req_major) & flag) {
374                     return ((i * 8) + j);
375                 }
376             }
377         }
378     }
379
380     return -1;
381 }
382  
383
384
385
386 static int apic_do_eoi(struct apic_state * apic) {
387     int isr_irq = get_highest_isr(apic);
388
389     if (isr_irq != -1) {
390         int major_offset = (isr_irq & ~0x00000007) >> 3;
391         int minor_offset = isr_irq & 0x00000007;
392         uchar_t flag = 0x1 << minor_offset;
393         uchar_t * svc_location = apic->int_svc_reg + major_offset;
394         
395         PrintDebug("apic %u: core ?: Received APIC EOI for IRQ %d\n", apic->lapic_id.val,isr_irq);
396         
397         *svc_location &= ~flag;
398
399 #ifdef CONFIG_CRAY_XT
400         
401         if ((isr_irq == 238) || 
402             (isr_irq == 239)) {
403             PrintError("apic %u: core ?: Acking IRQ %d\n", apic->lapic_id.val,isr_irq);
404         }
405         
406         if (isr_irq == 238) {
407             V3_ACK_IRQ(238);
408         }
409 #endif
410     } else {
411         //PrintError("apic %u: core ?: Spurious EOI...\n",apic->lapic_id.val);
412     }
413         
414     return 0;
415 }
416  
417
418 static int activate_internal_irq(struct apic_state * apic, apic_irq_type_t int_type) {
419     uint32_t vec_num = 0;
420     uint32_t del_mode = 0;
421     int masked = 0;
422
423
424     switch (int_type) {
425         case APIC_TMR_INT:
426             vec_num = apic->tmr_vec_tbl.vec;
427             del_mode = APIC_FIXED_DELIVERY;
428             masked = apic->tmr_vec_tbl.mask;
429             break;
430         case APIC_THERM_INT:
431             vec_num = apic->therm_loc_vec_tbl.vec;
432             del_mode = apic->therm_loc_vec_tbl.msg_type;
433             masked = apic->therm_loc_vec_tbl.mask;
434             break;
435         case APIC_PERF_INT:
436             vec_num = apic->perf_ctr_loc_vec_tbl.vec;
437             del_mode = apic->perf_ctr_loc_vec_tbl.msg_type;
438             masked = apic->perf_ctr_loc_vec_tbl.mask;
439             break;
440         case APIC_LINT0_INT:
441             vec_num = apic->lint0_vec_tbl.vec;
442             del_mode = apic->lint0_vec_tbl.msg_type;
443             masked = apic->lint0_vec_tbl.mask;
444             break;
445         case APIC_LINT1_INT:
446             vec_num = apic->lint1_vec_tbl.vec;
447             del_mode = apic->lint1_vec_tbl.msg_type;
448             masked = apic->lint1_vec_tbl.mask;
449             break;
450         case APIC_ERR_INT:
451             vec_num = apic->err_vec_tbl.vec;
452             del_mode = APIC_FIXED_DELIVERY;
453             masked = apic->err_vec_tbl.mask;
454             break;
455         default:
456             PrintError("apic %u: core ?: Invalid APIC interrupt type\n",apic->lapic_id.val);
457             return -1;
458     }
459
460     // interrupt is masked, don't send
461     if (masked == 1) {
462         PrintDebug("apic %u: core ?: Inerrupt is masked\n",apic->lapic_id.val);
463         return 0;
464     }
465
466     if (del_mode == APIC_FIXED_DELIVERY) {
467         //PrintDebug("Activating internal APIC IRQ %d\n", vec_num);
468         return activate_apic_irq(apic, vec_num);
469     } else {
470         PrintError("apic %u: core ?: Unhandled Delivery Mode\n",apic->lapic_id.val);
471         return -1;
472     }
473 }
474
475
476 static int apic_read(struct guest_info * core, addr_t guest_addr, void * dst, uint_t length, void * priv_data) {
477     struct apic_state * apic = (struct apic_state *)(priv_data);
478     addr_t reg_addr  = guest_addr - apic->base_addr;
479     struct apic_msr * msr = (struct apic_msr *)&(apic->base_addr_msr.value);
480     uint32_t val = 0;
481
482
483     PrintDebug("apic %u: core %u: at %p: Read apic address space (%p)\n",apic->lapic_id.val,core->cpu_id, apic, (void *)guest_addr);
484
485     if (msr->apic_enable == 0) {
486         PrintError("apic %u: core %u: Read from APIC address space with disabled APIC, apic msr=0x%llx\n",apic->lapic_id.val,core->cpu_id,apic->base_addr_msr.value);
487
488         return -1;
489     }
490
491
492     /* Because "May not be supported" doesn't matter to Linux developers... */
493     /*   if (length != 4) { */
494     /*     PrintError("Invalid apic read length (%d)\n", length); */
495     /*     return -1; */
496     /*   } */
497
498     switch (reg_addr & ~0x3) {
499         case EOI_OFFSET:
500             // Well, only an idiot would read from a architectural write only register
501             // Oh, Hello Linux.
502             //    PrintError("Attempting to read from write only register\n");
503             //    return -1;
504             break;
505
506             // data registers
507         case APIC_ID_OFFSET:
508             val = apic->lapic_id.val;
509             break;
510         case APIC_VERSION_OFFSET:
511             val = apic->apic_ver.val;
512             break;
513         case TPR_OFFSET:
514             val = apic->task_prio.val;
515             break;
516         case APR_OFFSET:
517             val = apic->arb_prio.val;
518             break;
519         case PPR_OFFSET:
520             val = apic->proc_prio.val;
521             break;
522         case REMOTE_READ_OFFSET:
523             val = apic->rem_rd_data;
524             break;
525         case LDR_OFFSET:
526             val = apic->log_dst.val;
527             break;
528         case DFR_OFFSET:
529             val = apic->dst_fmt.val;
530             break;
531         case SPURIOUS_INT_VEC_OFFSET:
532             val = apic->spurious_int.val;
533             break;
534         case ESR_OFFSET:
535             val = apic->err_status.val;
536             break;
537         case TMR_LOC_VEC_TBL_OFFSET:
538             val = apic->tmr_vec_tbl.val;
539             break;
540         case LINT0_VEC_TBL_OFFSET:
541             val = apic->lint0_vec_tbl.val;
542             break;
543         case LINT1_VEC_TBL_OFFSET:
544             val = apic->lint1_vec_tbl.val;
545             break;
546         case ERR_VEC_TBL_OFFSET:
547             val = apic->err_vec_tbl.val;
548             break;
549         case TMR_INIT_CNT_OFFSET:
550             val = apic->tmr_init_cnt;
551             break;
552         case TMR_DIV_CFG_OFFSET:
553             val = apic->tmr_div_cfg.val;
554             break;
555
556         case IER_OFFSET0:
557             val = *(uint32_t *)(apic->int_en_reg);
558             break;
559         case IER_OFFSET1:
560             val = *(uint32_t *)(apic->int_en_reg + 4);
561             break;
562         case IER_OFFSET2:
563             val = *(uint32_t *)(apic->int_en_reg + 8);
564             break;
565         case IER_OFFSET3:
566             val = *(uint32_t *)(apic->int_en_reg + 12);
567             break;
568         case IER_OFFSET4:
569             val = *(uint32_t *)(apic->int_en_reg + 16);
570             break;
571         case IER_OFFSET5:
572             val = *(uint32_t *)(apic->int_en_reg + 20);
573             break;
574         case IER_OFFSET6:
575             val = *(uint32_t *)(apic->int_en_reg + 24);
576             break;
577         case IER_OFFSET7:
578             val = *(uint32_t *)(apic->int_en_reg + 28);
579             break;
580
581         case ISR_OFFSET0:
582             val = *(uint32_t *)(apic->int_svc_reg);
583             break;
584         case ISR_OFFSET1:
585             val = *(uint32_t *)(apic->int_svc_reg + 4);
586             break;
587         case ISR_OFFSET2:
588             val = *(uint32_t *)(apic->int_svc_reg + 8);
589             break;
590         case ISR_OFFSET3:
591             val = *(uint32_t *)(apic->int_svc_reg + 12);
592             break;
593         case ISR_OFFSET4:
594             val = *(uint32_t *)(apic->int_svc_reg + 16);
595             break;
596         case ISR_OFFSET5:
597             val = *(uint32_t *)(apic->int_svc_reg + 20);
598             break;
599         case ISR_OFFSET6:
600             val = *(uint32_t *)(apic->int_svc_reg + 24);
601             break;
602         case ISR_OFFSET7:
603             val = *(uint32_t *)(apic->int_svc_reg + 28);
604             break;
605    
606         case TRIG_OFFSET0:
607             val = *(uint32_t *)(apic->trig_mode_reg);
608             break;
609         case TRIG_OFFSET1:
610             val = *(uint32_t *)(apic->trig_mode_reg + 4);
611             break;
612         case TRIG_OFFSET2:
613             val = *(uint32_t *)(apic->trig_mode_reg + 8);
614             break;
615         case TRIG_OFFSET3:
616             val = *(uint32_t *)(apic->trig_mode_reg + 12);
617             break;
618         case TRIG_OFFSET4:
619             val = *(uint32_t *)(apic->trig_mode_reg + 16);
620             break;
621         case TRIG_OFFSET5:
622             val = *(uint32_t *)(apic->trig_mode_reg + 20);
623             break;
624         case TRIG_OFFSET6:
625             val = *(uint32_t *)(apic->trig_mode_reg + 24);
626             break;
627         case TRIG_OFFSET7:
628             val = *(uint32_t *)(apic->trig_mode_reg + 28);
629             break;
630
631         case IRR_OFFSET0:
632             val = *(uint32_t *)(apic->int_req_reg);
633             break;
634         case IRR_OFFSET1:
635             val = *(uint32_t *)(apic->int_req_reg + 4);
636             break;
637         case IRR_OFFSET2:
638             val = *(uint32_t *)(apic->int_req_reg + 8);
639             break;
640         case IRR_OFFSET3:
641             val = *(uint32_t *)(apic->int_req_reg + 12);
642             break;
643         case IRR_OFFSET4:
644             val = *(uint32_t *)(apic->int_req_reg + 16);
645             break;
646         case IRR_OFFSET5:
647             val = *(uint32_t *)(apic->int_req_reg + 20);
648             break;
649         case IRR_OFFSET6:
650             val = *(uint32_t *)(apic->int_req_reg + 24);
651             break;
652         case IRR_OFFSET7:
653             val = *(uint32_t *)(apic->int_req_reg + 28);
654             break;
655         case TMR_CUR_CNT_OFFSET:
656             val = apic->tmr_cur_cnt;
657             break;
658
659             // We are not going to implement these....
660         case THERM_LOC_VEC_TBL_OFFSET:
661             val = apic->therm_loc_vec_tbl.val;
662             break;
663         case PERF_CTR_LOC_VEC_TBL_OFFSET:
664             val = apic->perf_ctr_loc_vec_tbl.val;
665             break;
666
667  
668
669             // handled registers
670         case INT_CMD_LO_OFFSET:    
671             val = apic->int_cmd.lo;
672             break;
673         case INT_CMD_HI_OFFSET:
674             val = apic->int_cmd.hi;
675             break;
676
677             // handle current timer count
678
679             // Unhandled Registers
680         case EXT_INT_LOC_VEC_TBL_OFFSET0:
681             val = apic->ext_intr_vec_tbl[0].val;
682             break;
683         case EXT_INT_LOC_VEC_TBL_OFFSET1:
684             val = apic->ext_intr_vec_tbl[1].val;
685             break;
686         case EXT_INT_LOC_VEC_TBL_OFFSET2:
687             val = apic->ext_intr_vec_tbl[2].val;
688             break;
689         case EXT_INT_LOC_VEC_TBL_OFFSET3:
690             val = apic->ext_intr_vec_tbl[3].val;
691             break;
692     
693
694         case EXT_APIC_FEATURE_OFFSET:
695         case EXT_APIC_CMD_OFFSET:
696         case SEOI_OFFSET:
697
698         default:
699             PrintError("apic %u: core %u: Read from Unhandled APIC Register: %x (getting zero)\n", apic->lapic_id.val,core->cpu_id, (uint32_t)reg_addr);
700             //      return -1;
701             val=0;
702     }
703
704
705     if (length == 1) {
706         uint_t byte_addr = reg_addr & 0x3;
707         uint8_t * val_ptr = (uint8_t *)dst;
708     
709         *val_ptr = *(((uint8_t *)&val) + byte_addr);
710
711     } else if ((length == 2) && 
712                ((reg_addr & 0x3) == 0x3)) {
713         uint_t byte_addr = reg_addr & 0x3;
714         uint16_t * val_ptr = (uint16_t *)dst;
715         *val_ptr = *(((uint16_t *)&val) + byte_addr);
716
717     } else if (length == 4) {
718         uint32_t * val_ptr = (uint32_t *)dst;
719         *val_ptr = val;
720
721     } else {
722         PrintError("apic %u: core %u: Invalid apic read length (%d)\n", apic->lapic_id.val,core->cpu_id, length);
723         return -1;
724     }
725
726     PrintDebug("apic %u: core %u: Read finished (val=%x)\n", apic->lapic_id.val,core->cpu_id, *(uint32_t *)dst);
727
728     return length;
729 }
730
731
732 /**
733  *
734  */
735 static int apic_write(struct guest_info * core, addr_t guest_addr, void * src, uint_t length, void * priv_data) {
736     struct apic_state * apic = (struct apic_state *)(priv_data);
737     addr_t reg_addr  = guest_addr - apic->base_addr;
738     struct apic_msr * msr = (struct apic_msr *)&(apic->base_addr_msr.value);
739     uint32_t op_val = *(uint32_t *)src;
740
741     PrintDebug("apic %u: core %u: at %p and priv_data is at %p: Write to address space (%p) (val=%x)\n", 
742                apic->lapic_id.val, core->cpu_id, apic,priv_data,
743                (void *)guest_addr, *(uint32_t *)src);
744
745     if (msr->apic_enable == 0) {
746         PrintError("apic %u: core %u: Write to APIC address space with disabled APIC, apic msr=0x%llx\n",apic->lapic_id.val,core->cpu_id,apic->base_addr_msr.value);
747         return -1;
748     }
749
750
751     if (length != 4) {
752         PrintError("apic %u: core %u: Invalid apic write length (%d)\n", apic->lapic_id.val, length,core->cpu_id);
753         return -1;
754     }
755
756     switch (reg_addr) {
757         case REMOTE_READ_OFFSET:
758         case APIC_VERSION_OFFSET:
759         case APR_OFFSET:
760         case IRR_OFFSET0:
761         case IRR_OFFSET1:
762         case IRR_OFFSET2:
763         case IRR_OFFSET3:
764         case IRR_OFFSET4:
765         case IRR_OFFSET5:
766         case IRR_OFFSET6:
767         case IRR_OFFSET7:
768         case ISR_OFFSET0:
769         case ISR_OFFSET1:
770         case ISR_OFFSET2:
771         case ISR_OFFSET3:
772         case ISR_OFFSET4:
773         case ISR_OFFSET5:
774         case ISR_OFFSET6:
775         case ISR_OFFSET7:
776         case TRIG_OFFSET0:
777         case TRIG_OFFSET1:
778         case TRIG_OFFSET2:
779         case TRIG_OFFSET3:
780         case TRIG_OFFSET4:
781         case TRIG_OFFSET5:
782         case TRIG_OFFSET6:
783         case TRIG_OFFSET7:
784         case PPR_OFFSET:
785         case EXT_APIC_FEATURE_OFFSET:
786 #if 1
787             PrintError("apic %u: core %u: Attempting to write to read only register %p (ignored)\n", apic->lapic_id.val,core->cpu_id, (void *)reg_addr);
788 #else   
789             PrintError("apic %u: core %u: Attempting to write to read only register %p (error)\n", apic->lapic_id.val,core->cpu_id, (void *)reg_addr);
790             return -1;
791 #endif
792             break;
793
794             // Data registers
795         case APIC_ID_OFFSET:
796             PrintDebug("apic %u: core %u: my id is being changed to %u\n",apic->lapic_id.val,core->cpu_id,op_val);
797             apic->lapic_id.val = op_val;
798             break;
799         case TPR_OFFSET:
800             apic->task_prio.val = op_val;
801             break;
802         case LDR_OFFSET:
803             apic->log_dst.val = op_val;
804             break;
805         case DFR_OFFSET:
806             apic->dst_fmt.val = op_val;
807             break;
808         case SPURIOUS_INT_VEC_OFFSET:
809             apic->spurious_int.val = op_val;
810             break;
811         case ESR_OFFSET:
812             apic->err_status.val = op_val;
813             break;
814         case TMR_LOC_VEC_TBL_OFFSET:
815             apic->tmr_vec_tbl.val = op_val;
816             break;
817         case THERM_LOC_VEC_TBL_OFFSET:
818             apic->therm_loc_vec_tbl.val = op_val;
819             break;
820         case PERF_CTR_LOC_VEC_TBL_OFFSET:
821             apic->perf_ctr_loc_vec_tbl.val = op_val;
822             break;
823         case LINT0_VEC_TBL_OFFSET:
824             apic->lint0_vec_tbl.val = op_val;
825             break;
826         case LINT1_VEC_TBL_OFFSET:
827             apic->lint1_vec_tbl.val = op_val;
828             break;
829         case ERR_VEC_TBL_OFFSET:
830             apic->err_vec_tbl.val = op_val;
831             break;
832         case TMR_INIT_CNT_OFFSET:
833             apic->tmr_init_cnt = op_val;
834             apic->tmr_cur_cnt = op_val;
835             break;
836         case TMR_CUR_CNT_OFFSET:
837             apic->tmr_cur_cnt = op_val;
838             break;
839         case TMR_DIV_CFG_OFFSET:
840             apic->tmr_div_cfg.val = op_val;
841             break;
842
843
844             // Enable mask (256 bits)
845         case IER_OFFSET0:
846             *(uint32_t *)(apic->int_en_reg) = op_val;
847             break;
848         case IER_OFFSET1:
849             *(uint32_t *)(apic->int_en_reg + 4) = op_val;
850             break;
851         case IER_OFFSET2:
852             *(uint32_t *)(apic->int_en_reg + 8) = op_val;
853             break;
854         case IER_OFFSET3:
855             *(uint32_t *)(apic->int_en_reg + 12) = op_val;
856             break;
857         case IER_OFFSET4:
858             *(uint32_t *)(apic->int_en_reg + 16) = op_val;
859             break;
860         case IER_OFFSET5:
861             *(uint32_t *)(apic->int_en_reg + 20) = op_val;
862             break;
863         case IER_OFFSET6:
864             *(uint32_t *)(apic->int_en_reg + 24) = op_val;
865             break;
866         case IER_OFFSET7:
867             *(uint32_t *)(apic->int_en_reg + 28) = op_val;
868             break;
869
870         case EXT_INT_LOC_VEC_TBL_OFFSET0:
871             apic->ext_intr_vec_tbl[0].val = op_val;
872             break;
873         case EXT_INT_LOC_VEC_TBL_OFFSET1:
874             apic->ext_intr_vec_tbl[1].val = op_val;
875             break;
876         case EXT_INT_LOC_VEC_TBL_OFFSET2:
877             apic->ext_intr_vec_tbl[2].val = op_val;
878             break;
879         case EXT_INT_LOC_VEC_TBL_OFFSET3:
880             apic->ext_intr_vec_tbl[3].val = op_val;
881             break;
882
883
884             // Action Registers
885         case EOI_OFFSET:
886             // do eoi
887             apic_do_eoi(apic);
888             break;
889
890         case INT_CMD_LO_OFFSET:
891             apic->int_cmd.lo = op_val;
892             // ICC???
893             PrintDebug("apic %u: core %u: sending cmd 0x%llx to apic %u\n",apic->lapic_id.val,core->cpu_id,
894                        apic->int_cmd.val, apic->int_cmd.dst);
895             if (v3_icc_send_ipi(apic->icc_bus, apic->lapic_id.val, apic->int_cmd.val,apic->dst_fmt.val,0)==-1) { 
896                 return -1;
897             }
898             break;
899         case INT_CMD_HI_OFFSET:
900             apic->int_cmd.hi = op_val;
901             break;
902             // Unhandled Registers
903
904         case EXT_APIC_CMD_OFFSET:
905         case SEOI_OFFSET:
906         default:
907             PrintError("apic %u: core %u: Write to Unhandled APIC Register: %x (ignored)\n", apic->lapic_id.val,core->cpu_id, (uint32_t)reg_addr);
908             //      return -1;
909     }
910
911     PrintDebug("apic %u: core %u: Write finished\n",apic->lapic_id.val,core->cpu_id);
912
913     return length;
914 }
915
916
917
918 /* Interrupt Controller Functions */
919
920 // returns 1 if an interrupt is pending, 0 otherwise
921 static int apic_intr_pending(struct guest_info * info, void * private_data) {
922     struct apic_state * apic = (struct apic_state *)private_data;
923     int req_irq = get_highest_irr(apic);
924     int svc_irq = get_highest_isr(apic);
925
926     //    PrintDebug("apic %u: core %u: req_irq=%d, svc_irq=%d\n",apic->lapic_id.val,info->cpu_id,req_irq,svc_irq);
927
928     if ((req_irq >= 0) && 
929         (req_irq > svc_irq)) {
930         return 1;
931     }
932
933     return 0;
934 }
935
936 static int apic_get_intr_number(struct guest_info * info, void * private_data) {
937     struct apic_state * apic = (struct apic_state *)private_data;
938     int req_irq = get_highest_irr(apic);
939     int svc_irq = get_highest_isr(apic);
940
941     if (svc_irq == -1) {
942         return req_irq;
943     } else if (svc_irq < req_irq) {
944         return req_irq;
945     }
946
947     return -1;
948 }
949
950
951 static int apic_raise_intr(struct guest_info * info, int irq, void * private_data) {
952   struct apic_state * apic = (struct apic_state *)private_data;
953
954   return activate_apic_irq(apic, irq);
955 }
956
957
958
959 static int apic_begin_irq(struct guest_info * info, void * private_data, int irq) {
960     struct apic_state * apic = (struct apic_state *)private_data;
961     int major_offset = (irq & ~0x00000007) >> 3;
962     int minor_offset = irq & 0x00000007;
963     uchar_t * req_location = apic->int_req_reg + major_offset;
964     uchar_t * svc_location = apic->int_svc_reg + major_offset;
965     uchar_t flag = 0x01 << minor_offset;
966
967     if (*req_location & flag) {
968         // we will only pay attention to a begin irq if we
969         // know that we initiated it!
970         *svc_location |= flag;
971         *req_location &= ~flag;
972     } else {
973         // do nothing... 
974         PrintDebug("apic %u: core %u: begin irq for %d ignored since I don't own it\n",
975                    apic->lapic_id.val,info->cpu_id,irq);
976     }
977
978
979
980     return 0;
981 }
982
983
984
985
986 /* Timer Functions */
987 static void apic_update_time(struct guest_info * info, ullong_t cpu_cycles, ullong_t cpu_freq, void * priv_data) {
988     struct apic_state * apic = (struct apic_state *)(priv_data);
989     // The 32 bit GCC runtime is a pile of shit
990 #ifdef __V3_64BIT__
991     uint64_t tmr_ticks = 0;
992 #else 
993     uint32_t tmr_ticks = 0;
994 #endif
995
996     uchar_t tmr_div = *(uchar_t *)&(apic->tmr_div_cfg.val);
997     uint_t shift_num = 0;
998
999
1000     // Check whether this is true:
1001     //   -> If the Init count is zero then the timer is disabled
1002     //      and doesn't just blitz interrupts to the CPU
1003     if ((apic->tmr_init_cnt == 0) || 
1004         ( (apic->tmr_vec_tbl.tmr_mode == APIC_TMR_ONESHOT) &&
1005           (apic->tmr_cur_cnt == 0))) {
1006         //PrintDebug("apic %u: core %u: APIC timer not yet initialized\n",apic->lapic_id.val,info->cpu_id);
1007         return;
1008     }
1009
1010
1011     switch (tmr_div) {
1012         case APIC_TMR_DIV1:
1013             shift_num = 0;
1014             break;
1015         case APIC_TMR_DIV2:
1016             shift_num = 1;
1017             break;
1018         case APIC_TMR_DIV4:
1019             shift_num = 2;
1020             break;
1021         case APIC_TMR_DIV8:
1022             shift_num = 3;
1023             break;
1024         case APIC_TMR_DIV16:
1025             shift_num = 4;
1026             break;
1027         case APIC_TMR_DIV32:
1028             shift_num = 5;
1029             break;
1030         case APIC_TMR_DIV64:
1031             shift_num = 6;
1032             break;
1033         case APIC_TMR_DIV128:
1034             shift_num = 7;
1035             break;
1036         default:
1037             PrintError("apic %u: core %u: Invalid Timer Divider configuration\n",apic->lapic_id.val,info->cpu_id);
1038             return;
1039     }
1040
1041     tmr_ticks = cpu_cycles >> shift_num;
1042     //    PrintDebug("Timer Ticks: %p\n", (void *)tmr_ticks);
1043
1044     if (tmr_ticks < apic->tmr_cur_cnt) {
1045         apic->tmr_cur_cnt -= tmr_ticks;
1046     } else {
1047         tmr_ticks -= apic->tmr_cur_cnt;
1048         apic->tmr_cur_cnt = 0;
1049
1050         // raise irq
1051         PrintDebug("apic %u: core %u: Raising APIC Timer interrupt (periodic=%d) (icnt=%d) (div=%d)\n", apic->lapic_id.val,info->cpu_id,
1052                    apic->tmr_vec_tbl.tmr_mode, apic->tmr_init_cnt, shift_num);
1053
1054         if (apic_intr_pending(info, priv_data)) {
1055             PrintDebug("apic %u: core %u: Overriding pending IRQ %d\n", apic->lapic_id.val,info->cpu_id, apic_get_intr_number(info, priv_data));
1056         }
1057
1058         if (activate_internal_irq(apic, APIC_TMR_INT) == -1) {
1059             PrintError("apic %u: core %u: Could not raise Timer interrupt\n",apic->lapic_id.val,info->cpu_id);
1060         }
1061     
1062         if (apic->tmr_vec_tbl.tmr_mode == APIC_TMR_PERIODIC) {
1063             tmr_ticks = tmr_ticks % apic->tmr_init_cnt;
1064             apic->tmr_cur_cnt = apic->tmr_init_cnt - tmr_ticks;
1065         }
1066     }
1067
1068
1069 }
1070
1071
1072 static struct intr_ctrl_ops intr_ops = {
1073     .intr_pending = apic_intr_pending,
1074     .get_intr_number = apic_get_intr_number,
1075     .begin_irq = apic_begin_irq,
1076 };
1077
1078
1079 static struct vm_timer_ops timer_ops = {
1080     .update_time = apic_update_time,
1081 };
1082
1083
1084
1085
1086 static int apic_free(struct vm_device * dev) {
1087
1088     /* TODO: This should crosscall to force an unhook on each CPU */
1089
1090     //   struct apic_state * apic = (struct apic_state *)dev->private_data;
1091
1092     v3_unhook_msr(dev->vm, BASE_ADDR_MSR);
1093
1094     return 0;
1095 }
1096
1097
1098 static struct v3_device_ops dev_ops = {
1099     .free = apic_free,
1100     .reset = NULL,
1101     .start = NULL,
1102     .stop = NULL,
1103 };
1104
1105
1106
1107 static int apic_should_deliver_flat(struct guest_info * core, uint8_t mda, void * private_data)
1108 {
1109   struct apic_state * apic = (struct apic_state *)private_data;
1110
1111   if (mda==0xff || (apic->log_dst.dst_log_id & mda)) { 
1112       return 1;
1113   } else {
1114       return 0;
1115   }
1116 }
1117
1118 static struct v3_icc_ops icc_ops = {
1119     .raise_intr = apic_raise_intr,
1120     .should_deliver_flat = apic_should_deliver_flat,
1121 };
1122
1123
1124
1125 static int apic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
1126     PrintDebug("apic: creating an APIC for each core\n");
1127     char * name = v3_cfg_val(cfg, "name");
1128     char * icc_name = v3_cfg_val(cfg,"bus");
1129     struct vm_device * icc = v3_find_dev(vm, icc_name);
1130     int i;
1131
1132     if (!icc) {
1133         PrintError("apic: Cannot find ICC Bus (%s)\n", icc_name);
1134         return -1;
1135     }
1136
1137     // We allocate one apic per core
1138     // APICs are accessed via index which correlates with the core's cpu_id 
1139     // 0..num_cores-1   at num_cores is the ioapic (one only)
1140     struct apic_state * apic = (struct apic_state *)V3_Malloc(sizeof(struct apic_state) * vm->num_cores);
1141
1142     struct vm_device * dev = v3_allocate_device(name, &dev_ops, apic);
1143
1144     if (v3_attach_device(vm, dev) == -1) {
1145         PrintError("apic: Could not attach device %s\n", name);
1146         return -1;
1147     }
1148
1149     
1150     for (i = 0; i < vm->num_cores; i++) {
1151         struct guest_info * core = &(vm->cores[i]);
1152
1153         init_apic_state(&(apic[i]),i,icc);
1154
1155         v3_register_intr_controller(core, &intr_ops, &(apic[i]));
1156
1157         v3_add_timer(core, &timer_ops, &(apic[i]));
1158
1159         v3_hook_full_mem(vm, core->cpu_id, apic->base_addr, apic->base_addr + PAGE_SIZE_4KB, apic_read, apic_write, &(apic[i]));
1160
1161         v3_icc_register_apic(core, icc, i, &icc_ops, &(apic[i]));
1162
1163         PrintDebug("apic %u: (setup device): done, my id is %u\n",i,apic[i].lapic_id.val);
1164
1165     }
1166
1167     for (i=0;i<vm->num_cores;i++) {
1168         PrintDebug("apic: sanity check: apic %u (at %p) has id %u and msr value %llx\n",
1169                    i, &(apic[i]), apic[i].lapic_id.val, apic[i].base_addr_msr.value);
1170     }
1171     PrintDebug("apic: priv_data is at %p\n", apic);
1172
1173     v3_hook_msr(vm, BASE_ADDR_MSR, read_apic_msr, write_apic_msr, dev);
1174
1175     return 0;
1176 }
1177
1178
1179
1180 device_register("LAPIC", apic_init)