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