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.


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