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.


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