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.


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