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.


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