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.


added handlers for extended interrupt vectors
[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 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
187 static void init_apic_state(struct apic_state * apic) {
188     apic->base_addr = DEFAULT_BASE_ADDR;
189     apic->base_addr_msr.value = 0x0000000000000900LL;
190     apic->base_addr_msr.value |= ((uint64_t)DEFAULT_BASE_ADDR); 
191
192     PrintDebug("Sizeof Interrupt Request Register %d, should be 32\n", 
193                (uint_t)sizeof(apic->int_req_reg));
194
195     memset(apic->int_req_reg, 0, sizeof(apic->int_req_reg));
196     memset(apic->int_svc_reg, 0, sizeof(apic->int_svc_reg));
197     memset(apic->int_en_reg, 0xff, sizeof(apic->int_en_reg));
198     memset(apic->trig_mode_reg, 0, sizeof(apic->trig_mode_reg));
199
200     apic->eoi = 0x00000000;
201     apic->rem_rd_data = 0x00000000;
202     apic->tmr_init_cnt = 0x00000000;
203     apic->tmr_cur_cnt = 0x00000000;
204
205     // TODO:
206     // We need to figure out what the APIC ID is....
207     apic->lapic_id.val = 0x00000000;
208
209     // The P6 has 6 LVT entries, so we set the value to (6-1)...
210     apic->apic_ver.val = 0x80050010;
211
212     apic->task_prio.val = 0x00000000;
213     apic->arb_prio.val = 0x00000000;
214     apic->proc_prio.val = 0x00000000;
215     apic->log_dst.val = 0x00000000;
216     apic->dst_fmt.val = 0xffffffff;
217     apic->spurious_int.val = 0x000000ff;
218     apic->err_status.val = 0x00000000;
219     apic->int_cmd.val = 0x0000000000000000LL;
220     apic->tmr_vec_tbl.val = 0x00010000;
221     apic->therm_loc_vec_tbl.val = 0x00010000;
222     apic->perf_ctr_loc_vec_tbl.val = 0x00010000;
223     apic->lint0_vec_tbl.val = 0x00010000;
224     apic->lint1_vec_tbl.val = 0x00010000;
225     apic->err_vec_tbl.val = 0x00010000;
226     apic->tmr_div_cfg.val = 0x00000000;
227     //apic->ext_apic_feature.val = 0x00000007;
228     apic->ext_apic_feature.val = 0x00040007;
229     apic->ext_apic_ctrl.val = 0x00000000;
230     apic->spec_eoi.val = 0x00000000;
231 }
232
233
234
235
236 static int read_apic_msr(uint_t msr, v3_msr_t * dst, void * priv_data) {
237     struct vm_device * dev = (struct vm_device *)priv_data;
238     struct apic_state * apic = (struct apic_state *)dev->private_data;
239     PrintError("READING APIC BASE ADDR: HI=%x LO=%x\n", apic->base_addr_msr.hi, apic->base_addr_msr.lo);
240
241     return -1;
242 }
243
244
245 static int write_apic_msr(uint_t msr, v3_msr_t src, void * priv_data) {
246     //  struct vm_device * dev = (struct vm_device *)priv_data;
247     //  struct apic_state * apic = (struct apic_state *)dev->private_data;
248
249     PrintError("WRITING APIC BASE ADDR: HI=%x LO=%x\n", src.hi, src.lo);
250
251     return -1;
252 }
253
254
255 // irq_num is the bit offset into a 256 bit buffer...
256 static int activate_apic_irq(struct apic_state * apic, uint32_t irq_num) {
257     int major_offset = (irq_num & ~0x00000007) >> 3;
258     int minor_offset = irq_num & 0x00000007;
259     uchar_t * req_location = apic->int_req_reg + major_offset;
260     uchar_t * en_location = apic->int_en_reg + major_offset;
261     uchar_t flag = 0x1 << minor_offset;
262
263     if (irq_num <= 15) {
264         PrintError("Attempting to raise an invalid interrupt: %d\n", irq_num);
265         return -1;
266     }
267
268     PrintDebug("Raising APIC IRQ %d\n", irq_num);
269
270     if (*en_location & flag) {
271         *req_location |= flag;
272     } else {
273         PrintDebug("Interrupt  not enabled... %.2x\n", *en_location);
274         return 0;
275     }
276
277     return 0;
278 }
279
280
281
282 static int get_highest_isr(struct apic_state * apic) {
283     int i = 0, j = 0;
284
285     // We iterate backwards to find the highest priority
286     for (i = 31; i >= 0; i--) {
287         uchar_t  * svc_major = apic->int_svc_reg + i;
288     
289         if ((*svc_major) & 0xff) {
290             for (j = 7; j >= 0; j--) {
291                 uchar_t flag = 0x1 << j;
292                 if ((*svc_major) & flag) {
293
294
295                     return ((i * 8) + j);
296                 }
297             }
298         }
299     }
300
301     return -1;
302 }
303  
304
305
306 static int get_highest_irr(struct apic_state * apic) {
307     int i = 0, j = 0;
308
309     // We iterate backwards to find the highest priority
310     for (i = 31; i >= 0; i--) {
311         uchar_t  * req_major = apic->int_req_reg + i;
312     
313         if ((*req_major) & 0xff) {
314             for (j = 7; j >= 0; j--) {
315                 uchar_t flag = 0x1 << j;
316                 if ((*req_major) & flag) {
317
318
319                     return ((i * 8) + j);
320                 }
321             }
322         }
323     }
324
325     return -1;
326 }
327  
328
329
330
331 static int apic_do_eoi(struct apic_state * apic) {
332     int isr_irq = get_highest_isr(apic);
333
334     if (isr_irq != -1) {
335         int major_offset = (isr_irq & ~0x00000007) >> 3;
336         int minor_offset = isr_irq & 0x00000007;
337         uchar_t flag = 0x1 << minor_offset;
338         uchar_t * svc_location = apic->int_svc_reg + major_offset;
339         
340         PrintDebug("Received APIC EOI\n");
341         
342         *svc_location &= ~flag;
343
344 #ifdef CRAY_XT
345         
346         if ((isr_irq == 238) || 
347             (isr_irq == 239)) {
348             PrintError("Acking IRQ %d\n", isr_irq);
349         }
350         
351         if (isr_irq == 238) {
352             V3_ACK_IRQ(238);
353         }
354 #endif
355     } else {
356         PrintError("Spurious EOI...\n");
357     }
358         
359     return 0;
360 }
361  
362
363 static int activate_internal_irq(struct apic_state * apic, apic_irq_type_t int_type) {
364     uint32_t vec_num = 0;
365     uint32_t del_mode = 0;
366     int masked = 0;
367
368
369     switch (int_type) {
370         case APIC_TMR_INT:
371             vec_num = apic->tmr_vec_tbl.vec;
372             del_mode = APIC_FIXED_DELIVERY;
373             masked = apic->tmr_vec_tbl.mask;
374             break;
375         case APIC_THERM_INT:
376             vec_num = apic->therm_loc_vec_tbl.vec;
377             del_mode = apic->therm_loc_vec_tbl.msg_type;
378             masked = apic->therm_loc_vec_tbl.mask;
379             break;
380         case APIC_PERF_INT:
381             vec_num = apic->perf_ctr_loc_vec_tbl.vec;
382             del_mode = apic->perf_ctr_loc_vec_tbl.msg_type;
383             masked = apic->perf_ctr_loc_vec_tbl.mask;
384             break;
385         case APIC_LINT0_INT:
386             vec_num = apic->lint0_vec_tbl.vec;
387             del_mode = apic->lint0_vec_tbl.msg_type;
388             masked = apic->lint0_vec_tbl.mask;
389             break;
390         case APIC_LINT1_INT:
391             vec_num = apic->lint1_vec_tbl.vec;
392             del_mode = apic->lint1_vec_tbl.msg_type;
393             masked = apic->lint1_vec_tbl.mask;
394             break;
395         case APIC_ERR_INT:
396             vec_num = apic->err_vec_tbl.vec;
397             del_mode = APIC_FIXED_DELIVERY;
398             masked = apic->err_vec_tbl.mask;
399             break;
400         default:
401             PrintError("Invalid APIC interrupt type\n");
402             return -1;
403     }
404
405     // interrupt is masked, don't send
406     if (masked == 1) {
407         PrintDebug("Inerrupt is masked\n");
408         return 0;
409     }
410
411     if (del_mode == APIC_FIXED_DELIVERY) {
412         //PrintDebug("Activating internal APIC IRQ %d\n", vec_num);
413         return activate_apic_irq(apic, vec_num);
414     } else {
415         PrintError("Unhandled Delivery Mode\n");
416         return -1;
417     }
418 }
419
420
421 static int apic_read(addr_t guest_addr, void * dst, uint_t length, void * priv_data) {
422     struct vm_device * dev = (struct vm_device *)priv_data;
423     struct apic_state * apic = (struct apic_state *)dev->private_data;
424     addr_t reg_addr  = guest_addr - apic->base_addr;
425     struct apic_msr * msr = (struct apic_msr *)&(apic->base_addr_msr.value);
426     uint32_t val = 0;
427
428
429     PrintDebug("Read apic address space (%p)\n", 
430                (void *)guest_addr);
431
432     if (msr->apic_enable == 0) {
433         PrintError("Write to APIC address space with disabled APIC\n");
434         return -1;
435     }
436
437
438     /* Because "May not be supported" doesn't matter to Linux developers... */
439     /*   if (length != 4) { */
440     /*     PrintError("Invalid apic read length (%d)\n", length); */
441     /*     return -1; */
442     /*   } */
443
444     switch (reg_addr & ~0x3) {
445         case EOI_OFFSET:
446             // Well, only an idiot would read from a architectural write only register
447             // Oh, Hello Linux.
448             //    PrintError("Attempting to read from write only register\n");
449             //    return -1;
450             break;
451
452             // data registers
453         case APIC_ID_OFFSET:
454             val = apic->lapic_id.val;
455             break;
456         case APIC_VERSION_OFFSET:
457             val = apic->apic_ver.val;
458             break;
459         case TPR_OFFSET:
460             val = apic->task_prio.val;
461             break;
462         case APR_OFFSET:
463             val = apic->arb_prio.val;
464             break;
465         case PPR_OFFSET:
466             val = apic->proc_prio.val;
467             break;
468         case REMOTE_READ_OFFSET:
469             val = apic->rem_rd_data;
470             break;
471         case LDR_OFFSET:
472             val = apic->log_dst.val;
473             break;
474         case DFR_OFFSET:
475             val = apic->dst_fmt.val;
476             break;
477         case SPURIOUS_INT_VEC_OFFSET:
478             val = apic->spurious_int.val;
479             break;
480         case ESR_OFFSET:
481             val = apic->err_status.val;
482             break;
483         case TMR_LOC_VEC_TBL_OFFSET:
484             val = apic->tmr_vec_tbl.val;
485             break;
486         case LINT0_VEC_TBL_OFFSET:
487             val = apic->lint0_vec_tbl.val;
488             break;
489         case LINT1_VEC_TBL_OFFSET:
490             val = apic->lint1_vec_tbl.val;
491             break;
492         case ERR_VEC_TBL_OFFSET:
493             val = apic->err_vec_tbl.val;
494             break;
495         case TMR_INIT_CNT_OFFSET:
496             val = apic->tmr_init_cnt;
497             break;
498         case TMR_DIV_CFG_OFFSET:
499             val = apic->tmr_div_cfg.val;
500             break;
501
502         case IER_OFFSET0:
503             val = *(uint32_t *)(apic->int_en_reg);
504             break;
505         case IER_OFFSET1:
506             val = *(uint32_t *)(apic->int_en_reg + 4);
507             break;
508         case IER_OFFSET2:
509             val = *(uint32_t *)(apic->int_en_reg + 8);
510             break;
511         case IER_OFFSET3:
512             val = *(uint32_t *)(apic->int_en_reg + 12);
513             break;
514         case IER_OFFSET4:
515             val = *(uint32_t *)(apic->int_en_reg + 16);
516             break;
517         case IER_OFFSET5:
518             val = *(uint32_t *)(apic->int_en_reg + 20);
519             break;
520         case IER_OFFSET6:
521             val = *(uint32_t *)(apic->int_en_reg + 24);
522             break;
523         case IER_OFFSET7:
524             val = *(uint32_t *)(apic->int_en_reg + 28);
525             break;
526
527         case ISR_OFFSET0:
528             val = *(uint32_t *)(apic->int_svc_reg);
529             break;
530         case ISR_OFFSET1:
531             val = *(uint32_t *)(apic->int_svc_reg + 4);
532             break;
533         case ISR_OFFSET2:
534             val = *(uint32_t *)(apic->int_svc_reg + 8);
535             break;
536         case ISR_OFFSET3:
537             val = *(uint32_t *)(apic->int_svc_reg + 12);
538             break;
539         case ISR_OFFSET4:
540             val = *(uint32_t *)(apic->int_svc_reg + 16);
541             break;
542         case ISR_OFFSET5:
543             val = *(uint32_t *)(apic->int_svc_reg + 20);
544             break;
545         case ISR_OFFSET6:
546             val = *(uint32_t *)(apic->int_svc_reg + 24);
547             break;
548         case ISR_OFFSET7:
549             val = *(uint32_t *)(apic->int_svc_reg + 28);
550             break;
551    
552         case TRIG_OFFSET0:
553             val = *(uint32_t *)(apic->trig_mode_reg);
554             break;
555         case TRIG_OFFSET1:
556             val = *(uint32_t *)(apic->trig_mode_reg + 4);
557             break;
558         case TRIG_OFFSET2:
559             val = *(uint32_t *)(apic->trig_mode_reg + 8);
560             break;
561         case TRIG_OFFSET3:
562             val = *(uint32_t *)(apic->trig_mode_reg + 12);
563             break;
564         case TRIG_OFFSET4:
565             val = *(uint32_t *)(apic->trig_mode_reg + 16);
566             break;
567         case TRIG_OFFSET5:
568             val = *(uint32_t *)(apic->trig_mode_reg + 20);
569             break;
570         case TRIG_OFFSET6:
571             val = *(uint32_t *)(apic->trig_mode_reg + 24);
572             break;
573         case TRIG_OFFSET7:
574             val = *(uint32_t *)(apic->trig_mode_reg + 28);
575             break;
576
577         case IRR_OFFSET0:
578             val = *(uint32_t *)(apic->int_req_reg);
579             break;
580         case IRR_OFFSET1:
581             val = *(uint32_t *)(apic->int_req_reg + 4);
582             break;
583         case IRR_OFFSET2:
584             val = *(uint32_t *)(apic->int_req_reg + 8);
585             break;
586         case IRR_OFFSET3:
587             val = *(uint32_t *)(apic->int_req_reg + 12);
588             break;
589         case IRR_OFFSET4:
590             val = *(uint32_t *)(apic->int_req_reg + 16);
591             break;
592         case IRR_OFFSET5:
593             val = *(uint32_t *)(apic->int_req_reg + 20);
594             break;
595         case IRR_OFFSET6:
596             val = *(uint32_t *)(apic->int_req_reg + 24);
597             break;
598         case IRR_OFFSET7:
599             val = *(uint32_t *)(apic->int_req_reg + 28);
600             break;
601         case TMR_CUR_CNT_OFFSET:
602             val = apic->tmr_cur_cnt;
603             break;
604
605             // We are not going to implement these....
606         case THERM_LOC_VEC_TBL_OFFSET:
607             val = apic->therm_loc_vec_tbl.val;
608             break;
609         case PERF_CTR_LOC_VEC_TBL_OFFSET:
610             val = apic->perf_ctr_loc_vec_tbl.val;
611             break;
612
613  
614
615             // handled registers
616         case INT_CMD_LO_OFFSET:    
617             val = apic->int_cmd.lo;
618             break;
619         case INT_CMD_HI_OFFSET:
620             val = apic->int_cmd.hi;
621             break;
622
623             // handle current timer count
624
625             // Unhandled Registers
626         case EXT_INT_LOC_VEC_TBL_OFFSET0:
627             val = apic->ext_intr_vec_tbl[0].val;
628             break;
629         case EXT_INT_LOC_VEC_TBL_OFFSET1:
630             val = apic->ext_intr_vec_tbl[1].val;
631             break;
632         case EXT_INT_LOC_VEC_TBL_OFFSET2:
633             val = apic->ext_intr_vec_tbl[2].val;
634             break;
635         case EXT_INT_LOC_VEC_TBL_OFFSET3:
636             val = apic->ext_intr_vec_tbl[3].val;
637             break;
638     
639
640         case EXT_APIC_FEATURE_OFFSET:
641         case EXT_APIC_CMD_OFFSET:
642         case SEOI_OFFSET:
643
644         default:
645             PrintError("Read from Unhandled APIC Register: %x\n", (uint32_t)reg_addr);
646             return -1;
647     }
648
649
650     if (length == 1) {
651         uint_t byte_addr = reg_addr & 0x3;
652         uint8_t * val_ptr = (uint8_t *)dst;
653     
654         *val_ptr = *(((uint8_t *)&val) + byte_addr);
655
656     } else if ((length == 2) && 
657                ((reg_addr & 0x3) == 0x3)) {
658         uint_t byte_addr = reg_addr & 0x3;
659         uint16_t * val_ptr = (uint16_t *)dst;
660         *val_ptr = *(((uint16_t *)&val) + byte_addr);
661
662     } else if (length == 4) {
663         uint32_t * val_ptr = (uint32_t *)dst;
664         *val_ptr = val;
665
666     } else {
667         PrintError("Invalid apic read length (%d)\n", length);
668         return -1;
669     }
670
671     PrintDebug("Read finished (val=%x)\n", *(uint32_t *)dst);
672
673     return length;
674 }
675
676
677 static int apic_write(addr_t guest_addr, void * src, uint_t length, void * priv_data) {
678     struct vm_device * dev = (struct vm_device *)priv_data;
679     struct apic_state * apic = (struct apic_state *)dev->private_data;
680     addr_t reg_addr  = guest_addr - apic->base_addr;
681     struct apic_msr * msr = (struct apic_msr *)&(apic->base_addr_msr.value);
682     uint32_t op_val = *(uint32_t *)src;
683
684     PrintDebug("Write to apic address space (%p) (val=%x)\n", 
685                (void *)guest_addr, *(uint32_t *)src);
686
687     if (msr->apic_enable == 0) {
688         PrintError("Write to APIC address space with disabled APIC\n");
689         return -1;
690     }
691
692
693     if (length != 4) {
694         PrintError("Invalid apic write length (%d)\n", length);
695         return -1;
696     }
697
698     switch (reg_addr) {
699         case REMOTE_READ_OFFSET:
700         case APIC_VERSION_OFFSET:
701         case APR_OFFSET:
702         case IRR_OFFSET0:
703         case IRR_OFFSET1:
704         case IRR_OFFSET2:
705         case IRR_OFFSET3:
706         case IRR_OFFSET4:
707         case IRR_OFFSET5:
708         case IRR_OFFSET6:
709         case IRR_OFFSET7:
710         case ISR_OFFSET0:
711         case ISR_OFFSET1:
712         case ISR_OFFSET2:
713         case ISR_OFFSET3:
714         case ISR_OFFSET4:
715         case ISR_OFFSET5:
716         case ISR_OFFSET6:
717         case ISR_OFFSET7:
718         case TRIG_OFFSET0:
719         case TRIG_OFFSET1:
720         case TRIG_OFFSET2:
721         case TRIG_OFFSET3:
722         case TRIG_OFFSET4:
723         case TRIG_OFFSET5:
724         case TRIG_OFFSET6:
725         case TRIG_OFFSET7:
726         case PPR_OFFSET:
727         case EXT_APIC_FEATURE_OFFSET:
728 #if 1
729             PrintError("Attempting to write to read only register %p (ignored)\n", (void *)reg_addr);
730 #else   
731             PrintError("Attempting to write to read only register %p (error)\n", (void *)reg_addr);
732             return -1;
733 #endif
734             break;
735
736             // Data registers
737         case APIC_ID_OFFSET:
738             apic->lapic_id.val = op_val;
739             break;
740         case TPR_OFFSET:
741             apic->task_prio.val = op_val;
742             break;
743         case LDR_OFFSET:
744             apic->log_dst.val = op_val;
745             break;
746         case DFR_OFFSET:
747             apic->dst_fmt.val = op_val;
748             break;
749         case SPURIOUS_INT_VEC_OFFSET:
750             apic->spurious_int.val = op_val;
751             break;
752         case ESR_OFFSET:
753             apic->err_status.val = op_val;
754             break;
755         case TMR_LOC_VEC_TBL_OFFSET:
756             apic->tmr_vec_tbl.val = op_val;
757             break;
758         case THERM_LOC_VEC_TBL_OFFSET:
759             apic->therm_loc_vec_tbl.val = op_val;
760             break;
761         case PERF_CTR_LOC_VEC_TBL_OFFSET:
762             apic->perf_ctr_loc_vec_tbl.val = op_val;
763             break;
764         case LINT0_VEC_TBL_OFFSET:
765             apic->lint0_vec_tbl.val = op_val;
766             break;
767         case LINT1_VEC_TBL_OFFSET:
768             apic->lint1_vec_tbl.val = op_val;
769             break;
770         case ERR_VEC_TBL_OFFSET:
771             apic->err_vec_tbl.val = op_val;
772             break;
773         case TMR_INIT_CNT_OFFSET:
774             apic->tmr_init_cnt = op_val;
775             apic->tmr_cur_cnt = op_val;
776             break;
777         case TMR_CUR_CNT_OFFSET:
778             apic->tmr_cur_cnt = op_val;
779             break;
780         case TMR_DIV_CFG_OFFSET:
781             apic->tmr_div_cfg.val = op_val;
782             break;
783
784
785             // Enable mask (256 bits)
786         case IER_OFFSET0:
787             *(uint32_t *)(apic->int_en_reg) = op_val;
788             break;
789         case IER_OFFSET1:
790             *(uint32_t *)(apic->int_en_reg + 4) = op_val;
791             break;
792         case IER_OFFSET2:
793             *(uint32_t *)(apic->int_en_reg + 8) = op_val;
794             break;
795         case IER_OFFSET3:
796             *(uint32_t *)(apic->int_en_reg + 12) = op_val;
797             break;
798         case IER_OFFSET4:
799             *(uint32_t *)(apic->int_en_reg + 16) = op_val;
800             break;
801         case IER_OFFSET5:
802             *(uint32_t *)(apic->int_en_reg + 20) = op_val;
803             break;
804         case IER_OFFSET6:
805             *(uint32_t *)(apic->int_en_reg + 24) = op_val;
806             break;
807         case IER_OFFSET7:
808             *(uint32_t *)(apic->int_en_reg + 28) = op_val;
809             break;
810
811         case EXT_INT_LOC_VEC_TBL_OFFSET0:
812             apic->ext_intr_vec_tbl[0].val = op_val;
813             break;
814         case EXT_INT_LOC_VEC_TBL_OFFSET1:
815             apic->ext_intr_vec_tbl[1].val = op_val;
816             break;
817         case EXT_INT_LOC_VEC_TBL_OFFSET2:
818             apic->ext_intr_vec_tbl[2].val = op_val;
819             break;
820         case EXT_INT_LOC_VEC_TBL_OFFSET3:
821             apic->ext_intr_vec_tbl[3].val = op_val;
822             break;
823
824
825             // Action Registers
826         case EOI_OFFSET:
827             // do eoi
828             apic_do_eoi(apic);
829             break;
830
831         case INT_CMD_LO_OFFSET:
832         case INT_CMD_HI_OFFSET:
833             // Unhandled Registers
834
835         case EXT_APIC_CMD_OFFSET:
836         case SEOI_OFFSET:
837         default:
838             PrintError("Write to Unhandled APIC Register: %x\n", (uint32_t)reg_addr);
839             return -1;
840     }
841
842     PrintDebug("Write finished\n");
843
844     return length;
845 }
846
847
848
849 /* Interrupt Controller Functions */
850
851 // returns 1 if an interrupt is pending, 0 otherwise
852 static int apic_intr_pending(void * private_data) {
853     struct vm_device * dev = (struct vm_device *)private_data;
854     struct apic_state * apic = (struct apic_state *)dev->private_data;
855     int req_irq = get_highest_irr(apic);
856     int svc_irq = get_highest_isr(apic);
857
858     if ((req_irq >= 0) && 
859         (req_irq > svc_irq)) {
860         return 1;
861     }
862
863     return 0;
864 }
865
866 static int apic_get_intr_number(void * private_data) {
867     struct vm_device * dev = (struct vm_device *)private_data;
868     struct apic_state * apic = (struct apic_state *)dev->private_data;
869     int req_irq = get_highest_irr(apic);
870     int svc_irq = get_highest_isr(apic);
871
872     if (svc_irq == -1) {
873         return req_irq;
874     } else if (svc_irq < req_irq) {
875         return req_irq;
876     }
877
878     return -1;
879 }
880
881 static int apic_raise_intr(void * private_data, int irq) {
882 #ifdef CRAY_XT
883     // The Seastar is connected directly to the LAPIC via LINT0 on the ICC bus
884
885     if (irq == 238) {
886         struct vm_device * dev = (struct vm_device *)private_data;
887         struct apic_state * apic = (struct apic_state *)dev->private_data;
888
889         return activate_apic_irq(apic, irq);
890     }
891 #endif
892     return 0;
893 }
894
895 static int apic_lower_intr(void * private_data, int irq) {
896     return 0;
897 }
898
899 static int apic_begin_irq(void * private_data, int irq) {
900     struct vm_device * dev = (struct vm_device *)private_data;
901     struct apic_state * apic = (struct apic_state *)dev->private_data;
902     int major_offset = (irq & ~0x00000007) >> 3;
903     int minor_offset = irq & 0x00000007;
904     uchar_t * req_location = apic->int_req_reg + major_offset;
905     uchar_t * svc_location = apic->int_svc_reg + major_offset;
906     uchar_t flag = 0x01 << minor_offset;
907
908     *svc_location |= flag;
909     *req_location &= ~flag;
910
911 #ifdef CRAY_XT
912     if ((irq == 238) || (irq == 239)) {
913         PrintError("APIC: Begin IRQ %d (ISR=%x), (IRR=%x)\n", irq, *svc_location, *req_location);
914     }
915 #endif
916
917     return 0;
918 }
919
920
921
922 int v3_apic_raise_intr(struct vm_device * apic_dev, int intr_num) {
923     struct apic_state * apic = (struct apic_state *)apic_dev->private_data;
924     return activate_apic_irq(apic, intr_num);
925 }
926
927
928
929 /* Timer Functions */
930 static void apic_update_time(ullong_t cpu_cycles, ullong_t cpu_freq, void * priv_data) {
931     struct vm_device * dev = (struct vm_device *)priv_data;
932     struct apic_state * apic = (struct apic_state *)dev->private_data;
933     // The 32 bit GCC runtime is a pile of shit
934 #ifdef __V3_64BIT__
935     uint64_t tmr_ticks = 0;
936 #else 
937     uint32_t tmr_ticks = 0;
938 #endif
939
940     uchar_t tmr_div = *(uchar_t *)&(apic->tmr_div_cfg.val);
941     uint_t shift_num = 0;
942
943
944     // Check whether this is true:
945     //   -> If the Init count is zero then the timer is disabled
946     //      and doesn't just blitz interrupts to the CPU
947     if ((apic->tmr_init_cnt == 0) || 
948         ( (apic->tmr_vec_tbl.tmr_mode == APIC_TMR_ONESHOT) &&
949           (apic->tmr_cur_cnt == 0))) {
950         //PrintDebug("APIC timer not yet initialized\n");
951         return;
952     }
953
954
955     switch (tmr_div) {
956         case APIC_TMR_DIV1:
957             shift_num = 0;
958             break;
959         case APIC_TMR_DIV2:
960             shift_num = 1;
961             break;
962         case APIC_TMR_DIV4:
963             shift_num = 2;
964             break;
965         case APIC_TMR_DIV8:
966             shift_num = 3;
967             break;
968         case APIC_TMR_DIV16:
969             shift_num = 4;
970             break;
971         case APIC_TMR_DIV32:
972             shift_num = 5;
973             break;
974         case APIC_TMR_DIV64:
975             shift_num = 6;
976             break;
977         case APIC_TMR_DIV128:
978             shift_num = 7;
979             break;
980         default:
981             PrintError("Invalid Timer Divider configuration\n");
982             return;
983     }
984
985     tmr_ticks = cpu_cycles >> shift_num;
986     PrintDebug("Timer Ticks: %p\n", (void *)tmr_ticks);
987
988     if (tmr_ticks < apic->tmr_cur_cnt) {
989         apic->tmr_cur_cnt -= tmr_ticks;
990     } else {
991         tmr_ticks -= apic->tmr_cur_cnt;
992         apic->tmr_cur_cnt = 0;
993
994         // raise irq
995         PrintDebug("Raising APIC Timer interrupt (periodic=%d) (icnt=%d) (div=%d)\n", 
996                    apic->tmr_vec_tbl.tmr_mode, apic->tmr_init_cnt, shift_num);
997
998         if (activate_internal_irq(apic, APIC_TMR_INT) == -1) {
999             PrintError("Could not raise Timer interrupt\n");
1000         }
1001     
1002         if (apic->tmr_vec_tbl.tmr_mode == APIC_TMR_PERIODIC) {
1003             tmr_ticks = tmr_ticks % apic->tmr_init_cnt;
1004             apic->tmr_cur_cnt = apic->tmr_init_cnt - tmr_ticks;
1005         }
1006     }
1007
1008
1009 }
1010
1011
1012
1013 static struct intr_ctrl_ops intr_ops = {
1014     .intr_pending = apic_intr_pending,
1015     .get_intr_number = apic_get_intr_number,
1016     .raise_intr = apic_raise_intr,
1017     .begin_irq = apic_begin_irq,
1018     .lower_intr = apic_lower_intr, 
1019 };
1020
1021
1022 static struct vm_timer_ops timer_ops = {
1023     .update_time = apic_update_time,
1024 };
1025
1026
1027 static int apic_init(struct vm_device * dev) {
1028     struct guest_info * info = dev->vm;
1029     struct apic_state * apic = (struct apic_state *)(dev->private_data);
1030
1031     v3_register_intr_controller(dev->vm, &intr_ops, dev);
1032     v3_add_timer(dev->vm, &timer_ops, dev);
1033
1034     init_apic_state(apic);
1035
1036     v3_hook_msr(info, BASE_ADDR_MSR, read_apic_msr, write_apic_msr, dev);
1037
1038     v3_hook_full_mem(info, apic->base_addr, apic->base_addr + PAGE_SIZE_4KB, apic_read, apic_write, dev);
1039
1040     return 0;
1041 }
1042
1043 static int apic_deinit(struct vm_device * dev) {
1044     struct guest_info * info = dev->vm;
1045
1046     v3_unhook_msr(info, BASE_ADDR_MSR);
1047
1048     return 0;
1049 }
1050
1051
1052 static struct vm_device_ops dev_ops = {
1053     .init = apic_init,
1054     .deinit = apic_deinit,
1055     .reset = NULL,
1056     .start = NULL,
1057     .stop = NULL,
1058 };
1059
1060
1061 struct vm_device * v3_create_apic() {
1062     PrintDebug("Creating APIC\n");
1063
1064     struct apic_state * apic = (struct apic_state *)V3_Malloc(sizeof(struct apic_state));
1065
1066     struct vm_device * device = v3_create_device("APIC", &dev_ops, apic);
1067   
1068     return device;
1069 }