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.


hacked in support for writes to readonly apic register 0x30 - they are just ignored
[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           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 #if 1
656     PrintError("Attempting to write to read only register %p (ignored)\n", (void *)reg_addr);
657 #else   
658     PrintError("Attempting to write to read only register %p (error)\n", (void *)reg_addr);
659     return -1;
660 #endif
661     break;
662
663     // Data registers
664   case APIC_ID_OFFSET:
665     apic->lapic_id.val = op_val;
666     break;
667   case TPR_OFFSET:
668     apic->task_prio.val = op_val;
669     break;
670   case LDR_OFFSET:
671     apic->log_dst.val = op_val;
672     break;
673   case DFR_OFFSET:
674     apic->dst_fmt.val = op_val;
675     break;
676   case SPURIOUS_INT_VEC_OFFSET:
677     apic->spurious_int.val = op_val;
678     break;
679   case ESR_OFFSET:
680     apic->err_status.val = op_val;
681     break;
682   case TMR_LOC_VEC_TBL_OFFSET:
683     apic->tmr_vec_tbl.val = op_val;
684     break;
685   case THERM_LOC_VEC_TBL_OFFSET:
686     apic->therm_loc_vec_tbl.val = op_val;
687     break;
688   case PERF_CTR_LOC_VEC_TBL_OFFSET:
689     apic->perf_ctr_loc_vec_tbl.val = op_val;
690     break;
691   case LINT0_VEC_TBL_OFFSET:
692     apic->lint0_vec_tbl.val = op_val;
693     break;
694   case LINT1_VEC_TBL_OFFSET:
695     apic->lint1_vec_tbl.val = op_val;
696     break;
697   case ERR_VEC_TBL_OFFSET:
698     apic->err_vec_tbl.val = op_val;
699     break;
700   case TMR_INIT_CNT_OFFSET:
701     apic->tmr_init_cnt = op_val;
702     apic->tmr_cur_cnt = op_val;
703     break;
704   case TMR_CUR_CNT_OFFSET:
705     apic->tmr_cur_cnt = op_val;
706     break;
707   case TMR_DIV_CFG_OFFSET:
708     apic->tmr_div_cfg.val = op_val;
709     break;
710
711
712     // Enable mask (256 bits)
713   case IER_OFFSET0:
714     *(uint32_t *)(apic->int_en_reg) = op_val;
715     break;
716   case IER_OFFSET1:
717     *(uint32_t *)(apic->int_en_reg + 4) = op_val;
718     break;
719   case IER_OFFSET2:
720     *(uint32_t *)(apic->int_en_reg + 8) = op_val;
721     break;
722   case IER_OFFSET3:
723     *(uint32_t *)(apic->int_en_reg + 12) = op_val;
724     break;
725   case IER_OFFSET4:
726     *(uint32_t *)(apic->int_en_reg + 16) = op_val;
727     break;
728   case IER_OFFSET5:
729     *(uint32_t *)(apic->int_en_reg + 20) = op_val;
730     break;
731   case IER_OFFSET6:
732     *(uint32_t *)(apic->int_en_reg + 24) = op_val;
733     break;
734   case IER_OFFSET7:
735     *(uint32_t *)(apic->int_en_reg + 28) = op_val;
736     break;
737    
738
739     // Action Registers
740   case INT_CMD_LO_OFFSET:
741   case INT_CMD_HI_OFFSET:
742   case EOI_OFFSET:
743     {
744       // do eoi
745       apic_do_eoi(apic);
746       break;
747
748     }
749     // Unhandled Registers
750   case EXT_INT_LOC_VEC_TBL_OFFSET0:
751   case EXT_INT_LOC_VEC_TBL_OFFSET1:
752   case EXT_INT_LOC_VEC_TBL_OFFSET2:
753   case EXT_INT_LOC_VEC_TBL_OFFSET3:
754   case EXT_APIC_CMD_OFFSET:
755   case SEOI_OFFSET:
756   default:
757     PrintError("Write to Unhandled APIC Register: %x\n", (uint32_t)reg_addr);
758     return -1;
759   }
760
761   PrintDebug("Write finished\n");
762
763   return length;
764 }
765
766
767
768 /* Interrupt Controller Functions */
769
770 static int apic_intr_pending(void * private_data) {
771   struct vm_device * dev = (struct vm_device *)private_data;
772   struct apic_state * apic = (struct apic_state *)dev->private_data;
773   int i = 0;
774
775
776   // just scan the request register looking for any set bit
777   // we should probably just do this with uint64 casts 
778   for (i = 0; i < 32; i++) {
779     if (apic->int_req_reg[i] & 0xff) {
780       return 1;
781     }
782   }
783   return 0;
784 }
785
786 static int apic_get_intr_number(void * private_data) {
787   struct vm_device * dev = (struct vm_device *)private_data;
788   struct apic_state * apic = (struct apic_state *)dev->private_data;
789   int i = 0, j = 0;
790
791
792   // We iterate backwards to find the highest priority
793   for (i = 31; i >= 0; i--) {
794     uchar_t req_major = apic->int_req_reg[i];
795     
796     if (req_major & 0xff) {
797       for (j = 7; j >= 0; j--) {
798         if ((req_major >> j) == 0x1) {
799           return (i * 8) + j;
800         }
801       }
802     }
803   }
804
805   return -1;
806 }
807
808 static int apic_raise_intr(void * private_data, int irq) {
809   return 0;
810 }
811
812 static int apic_lower_intr(void * private_data, int irq) {
813   return 0;
814 }
815
816 static int apic_begin_irq(void * private_data, int irq) {
817   struct vm_device * dev = (struct vm_device *)private_data;
818   struct apic_state * apic = (struct apic_state *)dev->private_data;
819   int major_offset = (irq & ~0x00000007) >> 3;
820   int minor_offset = irq & 0x00000007;
821   uchar_t * req_location = apic->int_req_reg + major_offset;
822   uchar_t * svc_location = apic->int_svc_reg + major_offset;
823   uchar_t flag = 0x01 << minor_offset;
824
825   *svc_location |= flag;
826   *req_location &= ~flag;
827
828   return 0;
829 }
830
831
832
833 int v3_apic_raise_intr(struct vm_device * apic_dev, int intr_num) {
834   struct apic_state * apic = (struct apic_state *)apic_dev->private_data;
835   return activate_apic_irq(apic, intr_num);
836 }
837
838
839
840 /* Timer Functions */
841 static void apic_update_time(ullong_t cpu_cycles, ullong_t cpu_freq, void * priv_data) {
842   struct vm_device * dev = (struct vm_device *)priv_data;
843   struct apic_state * apic = (struct apic_state *)dev->private_data;
844   // The 32 bit GCC runtime is a pile of shit
845 #ifdef __V3_64BIT__
846   uint64_t tmr_ticks = 0;
847 #else 
848   uint32_t tmr_ticks = 0;
849 #endif
850
851   uchar_t tmr_div = *(uchar_t *)&(apic->tmr_div_cfg.val);
852   uint_t shift_num = 0;
853
854
855   // Check whether this is true:
856   //   -> If the Init count is zero then the timer is disabled
857   //      and doesn't just blitz interrupts to the CPU
858   if ((apic->tmr_init_cnt == 0) || 
859       ( (apic->tmr_vec_tbl.tmr_mode == APIC_TMR_ONESHOT) &&
860         (apic->tmr_cur_cnt == 0))) {
861     //PrintDebug("APIC timer not yet initialized\n");
862     return;
863   }
864
865
866   switch (tmr_div) {
867   case APIC_TMR_DIV1:
868     shift_num = 0;
869     break;
870   case APIC_TMR_DIV2:
871     shift_num = 1;
872     break;
873   case APIC_TMR_DIV4:
874     shift_num = 2;
875     break;
876   case APIC_TMR_DIV8:
877     shift_num = 3;
878     break;
879   case APIC_TMR_DIV16:
880     shift_num = 4;
881     break;
882   case APIC_TMR_DIV32:
883     shift_num = 5;
884     break;
885   case APIC_TMR_DIV64:
886     shift_num = 6;
887     break;
888  case APIC_TMR_DIV128:
889     shift_num = 7;
890     break;
891   default:
892     PrintError("Invalid Timer Divider configuration\n");
893     return;
894   }
895
896   tmr_ticks = cpu_cycles >> shift_num;
897   //  PrintDebug("Timer Ticks: %p\n", (void *)tmr_ticks);
898
899   if (tmr_ticks < apic->tmr_cur_cnt) {
900     apic->tmr_cur_cnt -= tmr_ticks;
901   } else {
902     tmr_ticks -= apic->tmr_cur_cnt;
903     apic->tmr_cur_cnt = 0;
904
905     // raise irq
906     PrintDebug("Raising APIC Timer interrupt (periodic=%d) (icnt=%d) (div=%d)\n", 
907                apic->tmr_vec_tbl.tmr_mode, apic->tmr_init_cnt, shift_num);
908     if (activate_internal_irq(apic, APIC_TMR_INT) == -1) {
909       PrintError("Could not raise Timer interrupt\n");
910     }
911     
912     if (apic->tmr_vec_tbl.tmr_mode == APIC_TMR_PERIODIC) {
913       tmr_ticks = tmr_ticks % apic->tmr_init_cnt;
914       apic->tmr_cur_cnt = apic->tmr_init_cnt - tmr_ticks;
915     }
916   }
917
918
919 }
920
921
922
923 static struct intr_ctrl_ops intr_ops = {
924   .intr_pending = apic_intr_pending,
925   .get_intr_number = apic_get_intr_number,
926   .raise_intr = apic_raise_intr,
927   .begin_irq = apic_begin_irq,
928   .lower_intr = apic_lower_intr, 
929 };
930
931
932 static struct vm_timer_ops timer_ops = {
933   .update_time = apic_update_time,
934 };
935
936
937 static int apic_init(struct vm_device * dev) {
938   struct guest_info * info = dev->vm;
939   struct apic_state * apic = (struct apic_state *)(dev->private_data);
940
941   v3_register_intr_controller(dev->vm, &intr_ops, dev);
942   v3_add_timer(dev->vm, &timer_ops, dev);
943
944   init_apic_state(apic);
945
946   v3_hook_msr(info, BASE_ADDR_MSR, read_apic_msr, write_apic_msr, dev);
947
948   v3_hook_full_mem(info, apic->base_addr, apic->base_addr + PAGE_SIZE_4KB, apic_read, apic_write, dev);
949
950   return 0;
951 }
952
953 static int apic_deinit(struct vm_device * dev) {
954   struct guest_info * info = dev->vm;
955
956   v3_unhook_msr(info, BASE_ADDR_MSR);
957
958   return 0;
959 }
960
961
962 static struct vm_device_ops dev_ops = {
963   .init = apic_init,
964   .deinit = apic_deinit,
965   .reset = NULL,
966   .start = NULL,
967   .stop = NULL,
968 };
969
970
971 struct vm_device * v3_create_apic() {
972   PrintDebug("Creating APIC\n");
973
974   struct apic_state * apic = (struct apic_state *)V3_Malloc(sizeof(struct apic_state));
975
976   struct vm_device * device = v3_create_device("APIC", &dev_ops, apic);
977   
978   return device;
979 }