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.


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