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.


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