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.


IO APIC implementation
[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 typedef enum { APIC_TMR_INT, APIC_THERM_INT, APIC_PERF_INT, 
28                APIC_LINT0_INT, APIC_LINT1_INT, APIC_ERR_INT } apic_irq_type_t;
29
30 #define APIC_FIXED_DELIVERY  0x0
31 #define APIC_SMI_DELIVERY    0x2
32 #define APIC_NMI_DELIVERY    0x4
33 #define APIC_INIT_DELIVERY   0x5
34 #define APIC_EXTINT_DELIVERY 0x7
35
36
37 #define BASE_ADDR_MSR 0x0000001B
38 #define DEFAULT_BASE_ADDR 0xfee00000
39
40 #define APIC_ID_OFFSET                    0x020
41 #define APIC_VERSION_OFFSET               0x030
42 #define TPR_OFFSET                        0x080
43 #define APR_OFFSET                        0x090
44 #define PPR_OFFSET                        0x0a0
45 #define EOI_OFFSET                        0x0b0
46 #define REMOTE_READ_OFFSET                0x0c0
47 #define LDR_OFFSET                        0x0d0
48 #define DFR_OFFSET                        0x0e0
49 #define SPURIOUS_INT_VEC_OFFSET           0x0f0
50
51 #define ISR_OFFSET0                       0x100   // 0x100 - 0x170
52 #define ISR_OFFSET1                       0x110   // 0x100 - 0x170
53 #define ISR_OFFSET2                       0x120   // 0x100 - 0x170
54 #define ISR_OFFSET3                       0x130   // 0x100 - 0x170
55 #define ISR_OFFSET4                       0x140   // 0x100 - 0x170
56 #define ISR_OFFSET5                       0x150   // 0x100 - 0x170
57 #define ISR_OFFSET6                       0x160   // 0x100 - 0x170
58 #define ISR_OFFSET7                       0x170   // 0x100 - 0x170
59
60 #define TRIG_OFFSET0                      0x180   // 0x180 - 0x1f0
61 #define TRIG_OFFSET1                      0x190   // 0x180 - 0x1f0
62 #define TRIG_OFFSET2                      0x1a0   // 0x180 - 0x1f0
63 #define TRIG_OFFSET3                      0x1b0   // 0x180 - 0x1f0
64 #define TRIG_OFFSET4                      0x1c0   // 0x180 - 0x1f0
65 #define TRIG_OFFSET5                      0x1d0   // 0x180 - 0x1f0
66 #define TRIG_OFFSET6                      0x1e0   // 0x180 - 0x1f0
67 #define TRIG_OFFSET7                      0x1f0   // 0x180 - 0x1f0
68
69
70 #define IRR_OFFSET0                       0x200   // 0x200 - 0x270
71 #define IRR_OFFSET1                       0x210   // 0x200 - 0x270
72 #define IRR_OFFSET2                       0x220   // 0x200 - 0x270
73 #define IRR_OFFSET3                       0x230   // 0x200 - 0x270
74 #define IRR_OFFSET4                       0x240   // 0x200 - 0x270
75 #define IRR_OFFSET5                       0x250   // 0x200 - 0x270
76 #define IRR_OFFSET6                       0x260   // 0x200 - 0x270
77 #define IRR_OFFSET7                       0x270   // 0x200 - 0x270
78
79
80 #define ESR_OFFSET                        0x280
81 #define INT_CMD_LO_OFFSET                 0x300
82 #define INT_CMD_HI_OFFSET                 0x310
83 #define TMR_LOC_VEC_TBL_OFFSET            0x320
84 #define THERM_LOC_VEC_TBL_OFFSET          0x330
85 #define PERF_CTR_LOC_VEC_TBL_OFFSET       0x340
86 #define LINT0_VEC_TBL_OFFSET              0x350
87 #define LINT1_VEC_TBL_OFFSET              0x360
88 #define ERR_VEC_TBL_OFFSET                0x370
89 #define TMR_INIT_CNT_OFFSET               0x380
90 #define TMR_CUR_CNT_OFFSET                0x390
91 #define TMR_DIV_CFG_OFFSET                0x3e0
92 #define EXT_APIC_FEATURE_OFFSET           0x400
93 #define EXT_APIC_CMD_OFFSET               0x410
94 #define SEOI_OFFSET                       0x420
95
96 #define IER_OFFSET0                       0x480   // 0x480 - 0x4f0
97 #define IER_OFFSET1                       0x490   // 0x480 - 0x4f0
98 #define IER_OFFSET2                       0x4a0   // 0x480 - 0x4f0
99 #define IER_OFFSET3                       0x4b0   // 0x480 - 0x4f0
100 #define IER_OFFSET4                       0x4c0   // 0x480 - 0x4f0
101 #define IER_OFFSET5                       0x4d0   // 0x480 - 0x4f0
102 #define IER_OFFSET6                       0x4e0   // 0x480 - 0x4f0
103 #define IER_OFFSET7                       0x4f0   // 0x480 - 0x4f0
104
105 #define EXT_INT_LOC_VEC_TBL_OFFSET0       0x500   // 0x500 - 0x530
106 #define EXT_INT_LOC_VEC_TBL_OFFSET1       0x510   // 0x500 - 0x530
107 #define EXT_INT_LOC_VEC_TBL_OFFSET2       0x520   // 0x500 - 0x530
108 #define EXT_INT_LOC_VEC_TBL_OFFSET3       0x530   // 0x500 - 0x530
109
110
111
112 struct apic_msr {
113   union {
114     uint64_t val;
115     struct {
116       uchar_t rsvd;
117       uint_t bootstrap_cpu : 1;
118       uint_t rsvd2         : 2;
119       uint_t apic_enable   : 1;
120       ullong_t base_addr   : 40;
121       uint_t rsvd3         : 12;
122     } __attribute__((packed));
123   } __attribute__((packed));
124 } __attribute__((packed));
125
126
127
128
129 struct apic_state {
130   addr_t base_addr;
131
132   /* MSRs */
133   v3_msr_t base_addr_msr;
134
135
136   /* memory map registers */
137
138   struct lapic_id_reg lapic_id;
139   struct apic_ver_reg apic_ver;
140   struct ext_apic_ctrl_reg ext_apic_ctrl;
141   struct local_vec_tbl_reg local_vec_tbl;
142   struct tmr_vec_tbl_reg tmr_vec_tbl;
143   struct tmr_div_cfg_reg tmr_div_cfg;
144   struct lint_vec_tbl_reg lint0_vec_tbl;
145   struct lint_vec_tbl_reg lint1_vec_tbl;
146   struct perf_ctr_loc_vec_tbl_reg perf_ctr_loc_vec_tbl;
147   struct therm_loc_vec_tbl_reg therm_loc_vec_tbl;
148   struct err_vec_tbl_reg err_vec_tbl;
149   struct err_status_reg err_status;
150   struct spurious_int_reg spurious_int;
151   struct int_cmd_reg int_cmd;
152   struct log_dst_reg log_dst;
153   struct dst_fmt_reg dst_fmt;
154   struct arb_prio_reg arb_prio;
155   struct task_prio_reg task_prio;
156   struct proc_prio_reg proc_prio;
157   struct ext_apic_feature_reg ext_apic_feature;
158   struct spec_eoi_reg spec_eoi;
159   
160
161   uint32_t tmr_cur_cnt;
162   uint32_t tmr_init_cnt;
163
164
165
166   uint32_t rem_rd_data;
167
168
169   uchar_t int_req_reg[32];
170   uchar_t int_svc_reg[32];
171   uchar_t int_en_reg[32];
172   uchar_t trig_mode_reg[32];
173   
174   uint32_t eoi;
175
176
177 };
178
179
180 static void init_apic_state(struct apic_state * apic) {
181   apic->base_addr = DEFAULT_BASE_ADDR;
182   apic->base_addr_msr.value = 0x0000000000000900LL;
183   apic->base_addr_msr.value |= ((uint64_t)DEFAULT_BASE_ADDR); 
184
185   PrintDebug("Sizeof Interrupt Request Register %d, should be 32\n", 
186              (uint_t)sizeof(apic->int_req_reg));
187
188   memset(apic->int_req_reg, 0, sizeof(apic->int_req_reg));
189   memset(apic->int_svc_reg, 0, sizeof(apic->int_svc_reg));
190   memset(apic->int_en_reg, 0xff, sizeof(apic->int_en_reg));
191   memset(apic->trig_mode_reg, 0, sizeof(apic->trig_mode_reg));
192
193   apic->eoi = 0x00000000;
194   apic->rem_rd_data = 0x00000000;
195   apic->tmr_init_cnt = 0x00000000;
196   apic->tmr_cur_cnt = 0x00000000;
197
198   // TODO:
199   // We need to figure out what the APIC ID is....
200   apic->lapic_id.val = 0x00000000;
201
202   // The P6 has 6 LVT entries, so we set the value to (6-1)...
203   apic->apic_ver.val = 0x80050010;
204
205   apic->task_prio.val = 0x00000000;
206   apic->arb_prio.val = 0x00000000;
207   apic->proc_prio.val = 0x00000000;
208   apic->log_dst.val = 0x00000000;
209   apic->dst_fmt.val = 0xffffffff;
210   apic->spurious_int.val = 0x000000ff;
211   apic->err_status.val = 0x00000000;
212   apic->int_cmd.val = 0x0000000000000000LL;
213   apic->tmr_vec_tbl.val = 0x00010000;
214   apic->therm_loc_vec_tbl.val = 0x00010000;
215   apic->perf_ctr_loc_vec_tbl.val = 0x00010000;
216   apic->lint0_vec_tbl.val = 0x00010000;
217   apic->lint1_vec_tbl.val = 0x00010000;
218   apic->err_vec_tbl.val = 0x00010000;
219   apic->tmr_div_cfg.val = 0x00000000;
220   apic->ext_apic_feature.val = 0x00040007;
221   apic->ext_apic_ctrl.val = 0x00000000;
222   apic->spec_eoi.val = 0x00000000;
223 }
224
225
226
227
228 static int read_apic_msr(uint_t msr, v3_msr_t * dst, void * priv_data) {
229   struct vm_device * dev = (struct vm_device *)priv_data;
230   struct apic_state * apic = (struct apic_state *)dev->private_data;
231   PrintDebug("READING APIC BASE ADDR: HI=%x LO=%x\n", apic->base_addr_msr.hi, apic->base_addr_msr.lo);
232
233   return -1;
234 }
235
236
237 static int write_apic_msr(uint_t msr, v3_msr_t src, void * priv_data) {
238   //  struct vm_device * dev = (struct vm_device *)priv_data;
239   //  struct apic_state * apic = (struct apic_state *)dev->private_data;
240
241   PrintDebug("WRITING APIC BASE ADDR: HI=%x LO=%x\n", src.hi, src.lo);
242
243   return -1;
244 }
245
246
247 // irq_num is the bit offset into a 256 bit buffer...
248 static int activate_apic_irq(struct apic_state * apic, uint32_t irq_num) {
249   int major_offset = irq_num & ~0x00000007;
250   int minor_offset = irq_num & 0x00000007;
251   uchar_t * req_location = apic->int_req_reg + major_offset;
252   uchar_t * en_location = apic->int_en_reg + major_offset;
253   uchar_t flag = 0x1 << minor_offset;
254
255   if (irq_num <= 15) {
256     PrintError("Attempting to raise an invalid interrupt: %d\n", irq_num);
257     return -1;
258   }
259
260   if (*en_location & flag) {
261     *req_location |= flag;
262   } else {
263     return 0;
264   }
265
266   return 0;
267 }
268
269
270 static int activate_internal_irq(struct apic_state * apic, apic_irq_type_t int_type) {
271   uint32_t vec_num = 0;
272   uint32_t del_mode = 0;
273   int masked = 0;
274
275
276   switch (int_type) {
277   case APIC_TMR_INT:
278     vec_num = apic->tmr_vec_tbl.vec;
279     del_mode = APIC_FIXED_DELIVERY;
280     masked = apic->tmr_vec_tbl.mask;
281     break;
282   case APIC_THERM_INT:
283     vec_num = apic->therm_loc_vec_tbl.vec;
284     del_mode = apic->therm_loc_vec_tbl.msg_type;
285     masked = apic->therm_loc_vec_tbl.mask;
286     break;
287   case APIC_PERF_INT:
288     vec_num = apic->perf_ctr_loc_vec_tbl.vec;
289     del_mode = apic->perf_ctr_loc_vec_tbl.msg_type;
290     masked = apic->perf_ctr_loc_vec_tbl.mask;
291     break;
292   case APIC_LINT0_INT:
293     vec_num = apic->lint0_vec_tbl.vec;
294     del_mode = apic->lint0_vec_tbl.msg_type;
295     masked = apic->lint0_vec_tbl.mask;
296     break;
297   case APIC_LINT1_INT:
298     vec_num = apic->lint1_vec_tbl.vec;
299     del_mode = apic->lint1_vec_tbl.msg_type;
300     masked = apic->lint1_vec_tbl.mask;
301     break;
302   case APIC_ERR_INT:
303     vec_num = apic->err_vec_tbl.vec;
304     del_mode = APIC_FIXED_DELIVERY;
305     masked = apic->err_vec_tbl.mask;
306     break;
307   default:
308     PrintError("Invalid APIC interrupt type\n");
309     return -1;
310   }
311
312   // interrupt is masked, don't send
313   if (masked == 1) {
314     return 0;
315   }
316
317   if (del_mode == APIC_FIXED_DELIVERY) {
318     //PrintDebug("Activating internal APIC IRQ %d\n", vec_num);
319     return activate_apic_irq(apic, vec_num);
320   } else {
321     PrintError("Unhandled Delivery Mode\n");
322     return -1;
323   }
324 }
325
326
327 static int apic_read(addr_t guest_addr, void * dst, uint_t length, void * priv_data) {
328   struct vm_device * dev = (struct vm_device *)priv_data;
329   struct apic_state * apic = (struct apic_state *)dev->private_data;
330   addr_t reg_addr  = guest_addr - apic->base_addr;
331   struct apic_msr * msr = (struct apic_msr *)&(apic->base_addr_msr.value);
332   uint32_t * val_ptr = (uint32_t *)dst;
333
334   PrintDebug("Read apic address space (%p)\n", 
335              (void *)guest_addr);
336
337   if (msr->apic_enable == 0) {
338     PrintError("Write to APIC address space with disabled APIC\n");
339     return -1;
340   }
341
342
343   if (length != 4) {
344     PrintError("Invalid apic readlength\n");
345     return -1;
346   }
347
348   switch (reg_addr) {
349   case EOI_OFFSET:
350     PrintError("Attempting to read from write only register\n");
351     return -1;
352     break;
353
354     // data registers
355   case APIC_ID_OFFSET:
356     *val_ptr = apic->lapic_id.val;
357     break;
358   case APIC_VERSION_OFFSET:
359     *val_ptr = apic->apic_ver.val;
360     break;
361   case TPR_OFFSET:
362     *val_ptr = apic->task_prio.val;
363     break;
364   case APR_OFFSET:
365     *val_ptr = apic->arb_prio.val;
366     break;
367   case PPR_OFFSET:
368     *val_ptr = apic->proc_prio.val;
369     break;
370   case REMOTE_READ_OFFSET:
371     *val_ptr = apic->rem_rd_data;
372     break;
373   case LDR_OFFSET:
374     *val_ptr = apic->log_dst.val;
375     break;
376   case DFR_OFFSET:
377     *val_ptr = apic->dst_fmt.val;
378     break;
379   case SPURIOUS_INT_VEC_OFFSET:
380     *val_ptr = apic->spurious_int.val;
381     break;
382   case ESR_OFFSET:
383     *val_ptr = apic->err_status.val;
384     break;
385   case TMR_LOC_VEC_TBL_OFFSET:
386     *val_ptr = apic->tmr_vec_tbl.val;
387     break;
388   case LINT0_VEC_TBL_OFFSET:
389     *val_ptr = apic->lint0_vec_tbl.val;
390     break;
391   case LINT1_VEC_TBL_OFFSET:
392     *val_ptr = apic->lint1_vec_tbl.val;
393     break;
394   case ERR_VEC_TBL_OFFSET:
395     *val_ptr = apic->err_vec_tbl.val;
396     break;
397   case TMR_INIT_CNT_OFFSET:
398     *val_ptr = apic->tmr_init_cnt;
399     break;
400   case TMR_DIV_CFG_OFFSET:
401     *val_ptr = apic->tmr_div_cfg.val;
402     break;
403
404   case IER_OFFSET0:
405     *val_ptr = *(uint32_t *)(apic->int_en_reg);
406     break;
407   case IER_OFFSET1:
408     *val_ptr = *(uint32_t *)(apic->int_en_reg + 4);
409     break;
410   case IER_OFFSET2:
411     *val_ptr = *(uint32_t *)(apic->int_en_reg + 8);
412     break;
413   case IER_OFFSET3:
414     *val_ptr = *(uint32_t *)(apic->int_en_reg + 12);
415     break;
416   case IER_OFFSET4:
417     *val_ptr = *(uint32_t *)(apic->int_en_reg + 16);
418     break;
419   case IER_OFFSET5:
420     *val_ptr = *(uint32_t *)(apic->int_en_reg + 20);
421     break;
422   case IER_OFFSET6:
423     *val_ptr = *(uint32_t *)(apic->int_en_reg + 24);
424     break;
425   case IER_OFFSET7:
426     *val_ptr = *(uint32_t *)(apic->int_en_reg + 28);
427     break;
428
429   case ISR_OFFSET0:
430     *val_ptr = *(uint32_t *)(apic->int_svc_reg);
431     break;
432   case ISR_OFFSET1:
433     *val_ptr = *(uint32_t *)(apic->int_svc_reg + 4);
434     break;
435   case ISR_OFFSET2:
436     *val_ptr = *(uint32_t *)(apic->int_svc_reg + 8);
437     break;
438   case ISR_OFFSET3:
439     *val_ptr = *(uint32_t *)(apic->int_svc_reg + 12);
440     break;
441   case ISR_OFFSET4:
442     *val_ptr = *(uint32_t *)(apic->int_svc_reg + 16);
443     break;
444   case ISR_OFFSET5:
445     *val_ptr = *(uint32_t *)(apic->int_svc_reg + 20);
446     break;
447   case ISR_OFFSET6:
448     *val_ptr = *(uint32_t *)(apic->int_svc_reg + 24);
449     break;
450   case ISR_OFFSET7:
451     *val_ptr = *(uint32_t *)(apic->int_svc_reg + 28);
452     break;
453    
454   case TRIG_OFFSET0:
455     *val_ptr = *(uint32_t *)(apic->trig_mode_reg);
456     break;
457   case TRIG_OFFSET1:
458     *val_ptr = *(uint32_t *)(apic->trig_mode_reg + 4);
459     break;
460   case TRIG_OFFSET2:
461     *val_ptr = *(uint32_t *)(apic->trig_mode_reg + 8);
462     break;
463   case TRIG_OFFSET3:
464     *val_ptr = *(uint32_t *)(apic->trig_mode_reg + 12);
465     break;
466   case TRIG_OFFSET4:
467     *val_ptr = *(uint32_t *)(apic->trig_mode_reg + 16);
468     break;
469   case TRIG_OFFSET5:
470     *val_ptr = *(uint32_t *)(apic->trig_mode_reg + 20);
471     break;
472   case TRIG_OFFSET6:
473     *val_ptr = *(uint32_t *)(apic->trig_mode_reg + 24);
474     break;
475   case TRIG_OFFSET7:
476     *val_ptr = *(uint32_t *)(apic->trig_mode_reg + 28);
477     break;
478
479   case IRR_OFFSET0:
480     *val_ptr = *(uint32_t *)(apic->int_req_reg);
481     break;
482   case IRR_OFFSET1:
483     *val_ptr = *(uint32_t *)(apic->int_req_reg + 4);
484     break;
485   case IRR_OFFSET2:
486     *val_ptr = *(uint32_t *)(apic->int_req_reg + 8);
487     break;
488   case IRR_OFFSET3:
489     *val_ptr = *(uint32_t *)(apic->int_req_reg + 12);
490     break;
491   case IRR_OFFSET4:
492     *val_ptr = *(uint32_t *)(apic->int_req_reg + 16);
493     break;
494   case IRR_OFFSET5:
495     *val_ptr = *(uint32_t *)(apic->int_req_reg + 20);
496     break;
497   case IRR_OFFSET6:
498     *val_ptr = *(uint32_t *)(apic->int_req_reg + 24);
499     break;
500   case IRR_OFFSET7:
501     *val_ptr = *(uint32_t *)(apic->int_req_reg + 28);
502     break;
503   case TMR_CUR_CNT_OFFSET:
504     *val_ptr = apic->tmr_cur_cnt;
505     break;
506
507     // We are not going to implement these....
508   case THERM_LOC_VEC_TBL_OFFSET:
509     *val_ptr = apic->therm_loc_vec_tbl.val;
510     break;
511   case PERF_CTR_LOC_VEC_TBL_OFFSET:
512     *val_ptr = apic->perf_ctr_loc_vec_tbl.val;
513     break;
514
515  
516
517     // handled registers
518   case INT_CMD_LO_OFFSET:    
519     *val_ptr = apic->int_cmd.lo;
520     break;
521   case INT_CMD_HI_OFFSET:
522     *val_ptr = apic->int_cmd.hi;
523     break;
524
525     // handle current timer count
526
527     // Unhandled Registers
528   case EXT_INT_LOC_VEC_TBL_OFFSET0:
529   case EXT_INT_LOC_VEC_TBL_OFFSET1:
530   case EXT_INT_LOC_VEC_TBL_OFFSET2:
531   case EXT_INT_LOC_VEC_TBL_OFFSET3:
532   case EXT_APIC_FEATURE_OFFSET:
533   case EXT_APIC_CMD_OFFSET:
534   case SEOI_OFFSET:
535
536   default:
537     PrintError("Read from Unhandled APIC Register: %x\n", (uint32_t)reg_addr);
538     return -1;
539   }
540
541   PrintDebug("Read finished (val=%x)\n", *(uint32_t *)dst);
542
543   return length;
544 }
545
546
547 static int apic_write(addr_t guest_addr, void * src, uint_t length, void * priv_data) {
548   struct vm_device * dev = (struct vm_device *)priv_data;
549   struct apic_state * apic = (struct apic_state *)dev->private_data;
550   addr_t reg_addr  = guest_addr - apic->base_addr;
551   struct apic_msr * msr = (struct apic_msr *)&(apic->base_addr_msr.value);
552   uint32_t op_val = *(uint32_t *)src;
553
554   PrintDebug("Write to apic address space (%p) (val=%x)\n", 
555              (void *)guest_addr, *(uint32_t *)src);
556
557   if (msr->apic_enable == 0) {
558     PrintError("Write to APIC address space with disabled APIC\n");
559     return -1;
560   }
561
562
563   if (length != 4) {
564     PrintError("Invalid apic write length\n");
565     return -1;
566   }
567
568   switch (reg_addr) {
569   case REMOTE_READ_OFFSET:
570   case APIC_VERSION_OFFSET:
571   case APR_OFFSET:
572   case IRR_OFFSET0:
573   case IRR_OFFSET1:
574   case IRR_OFFSET2:
575   case IRR_OFFSET3:
576   case IRR_OFFSET4:
577   case IRR_OFFSET5:
578   case IRR_OFFSET6:
579   case IRR_OFFSET7:
580   case ISR_OFFSET0:
581   case ISR_OFFSET1:
582   case ISR_OFFSET2:
583   case ISR_OFFSET3:
584   case ISR_OFFSET4:
585   case ISR_OFFSET5:
586   case ISR_OFFSET6:
587   case ISR_OFFSET7:
588   case TRIG_OFFSET0:
589   case TRIG_OFFSET1:
590   case TRIG_OFFSET2:
591   case TRIG_OFFSET3:
592   case TRIG_OFFSET4:
593   case TRIG_OFFSET5:
594   case TRIG_OFFSET6:
595   case TRIG_OFFSET7:
596   case PPR_OFFSET:
597   case EXT_APIC_FEATURE_OFFSET:
598     PrintError("Attempting to write to read only register\n");
599     return -1;
600     break;
601
602     // Data registers
603   case APIC_ID_OFFSET:
604     apic->lapic_id.val = op_val;
605     break;
606   case TPR_OFFSET:
607     apic->task_prio.val = op_val;
608     break;
609   case LDR_OFFSET:
610     apic->log_dst.val = op_val;
611     break;
612   case DFR_OFFSET:
613     apic->dst_fmt.val = op_val;
614     break;
615   case SPURIOUS_INT_VEC_OFFSET:
616     apic->spurious_int.val = op_val;
617     break;
618   case ESR_OFFSET:
619     apic->err_status.val = op_val;
620     break;
621   case TMR_LOC_VEC_TBL_OFFSET:
622     apic->tmr_vec_tbl.val = op_val;
623     break;
624   case THERM_LOC_VEC_TBL_OFFSET:
625     apic->therm_loc_vec_tbl.val = op_val;
626     break;
627   case PERF_CTR_LOC_VEC_TBL_OFFSET:
628     apic->perf_ctr_loc_vec_tbl.val = op_val;
629     break;
630   case LINT0_VEC_TBL_OFFSET:
631     apic->lint0_vec_tbl.val = op_val;
632     break;
633   case LINT1_VEC_TBL_OFFSET:
634     apic->lint1_vec_tbl.val = op_val;
635     break;
636   case ERR_VEC_TBL_OFFSET:
637     apic->err_vec_tbl.val = op_val;
638     break;
639   case TMR_INIT_CNT_OFFSET:
640     apic->tmr_init_cnt = op_val;
641     apic->tmr_cur_cnt = op_val;
642     break;
643   case TMR_CUR_CNT_OFFSET:
644     apic->tmr_cur_cnt = op_val;
645     break;
646   case TMR_DIV_CFG_OFFSET:
647     apic->tmr_div_cfg.val = op_val;
648     break;
649
650
651     // Enable mask (256 bits)
652   case IER_OFFSET0:
653     *(uint32_t *)(apic->int_en_reg) = op_val;
654     break;
655   case IER_OFFSET1:
656     *(uint32_t *)(apic->int_en_reg + 4) = op_val;
657     break;
658   case IER_OFFSET2:
659     *(uint32_t *)(apic->int_en_reg + 8) = op_val;
660     break;
661   case IER_OFFSET3:
662     *(uint32_t *)(apic->int_en_reg + 12) = op_val;
663     break;
664   case IER_OFFSET4:
665     *(uint32_t *)(apic->int_en_reg + 16) = op_val;
666     break;
667   case IER_OFFSET5:
668     *(uint32_t *)(apic->int_en_reg + 20) = op_val;
669     break;
670   case IER_OFFSET6:
671     *(uint32_t *)(apic->int_en_reg + 24) = op_val;
672     break;
673   case IER_OFFSET7:
674     *(uint32_t *)(apic->int_en_reg + 28) = op_val;
675     break;
676    
677
678     // Action Registers
679   case INT_CMD_LO_OFFSET:
680   case INT_CMD_HI_OFFSET:
681   case EOI_OFFSET:
682     // do eoi
683
684     // Unhandled Registers
685   case EXT_INT_LOC_VEC_TBL_OFFSET0:
686   case EXT_INT_LOC_VEC_TBL_OFFSET1:
687   case EXT_INT_LOC_VEC_TBL_OFFSET2:
688   case EXT_INT_LOC_VEC_TBL_OFFSET3:
689   case EXT_APIC_CMD_OFFSET:
690   case SEOI_OFFSET:
691   default:
692     PrintError("Write to Unhandled APIC Register: %x\n", (uint32_t)reg_addr);
693     return -1;
694   }
695
696   PrintDebug("Write finished\n");
697
698   return length;
699 }
700
701
702
703 /* Interrupt Controller Functions */
704
705 static int apic_intr_pending(void * private_data) {
706   struct vm_device * dev = (struct vm_device *)private_data;
707   struct apic_state * apic = (struct apic_state *)dev->private_data;
708   int i = 0;
709
710   // just scan the request register looking for any set bit
711   // we should probably just do this with uint64 casts 
712   for (i = 0; i < 32; i++) {
713     if (apic->int_req_reg[i] & 0xff) {
714       return 1;
715     }
716   }
717
718   return 0;
719 }
720
721 static int apic_get_intr_number(void * private_data) {
722   struct vm_device * dev = (struct vm_device *)private_data;
723   struct apic_state * apic = (struct apic_state *)dev->private_data;
724   int i = 0, j = 0;
725
726
727   // We iterate backwards to find the highest priority
728   for (i = 31; i >= 0; i--) {
729     uchar_t req_major = apic->int_req_reg[i];
730     
731     if (req_major & 0xff) {
732       for (j = 7; j >= 0; j--) {
733         if ((req_major >> j) == 0x1) {
734           return (i * 32) + j;
735         }
736       }
737     }
738   }
739
740   return -1;
741 }
742
743 static int apic_raise_intr(void * private_data, int irq) {
744   return 0;
745 }
746
747 static int apic_lower_intr(void * private_data, int irq) {
748   return 0;
749 }
750
751 static int apic_begin_irq(void * private_data, int irq) {
752   struct vm_device * dev = (struct vm_device *)private_data;
753   struct apic_state * apic = (struct apic_state *)dev->private_data;
754   int major_offset = irq & ~0x00000007;
755   int minor_offset = irq & 0x00000007;
756   uchar_t * req_location = apic->int_req_reg + major_offset;
757   uchar_t * svc_location = apic->int_svc_reg + major_offset;
758   uchar_t flag = 0x01 << minor_offset;
759
760   *svc_location |= flag;
761   *req_location &= ~flag;
762
763   return 0;
764 }
765
766
767
768 int v3_apic_raise_intr(struct vm_device * apic_dev, int intr_num) {
769   struct apic_state * apic = (struct apic_state *)apic_dev->private_data;
770   return activate_apic_irq(apic, intr_num);
771 }
772
773
774
775 /* Timer Functions */
776 static void apic_update_time(ullong_t cpu_cycles, ullong_t cpu_freq, void * priv_data) {
777   struct vm_device * dev = (struct vm_device *)priv_data;
778   struct apic_state * apic = (struct apic_state *)dev->private_data;
779   // The 32 bit GCC runtime is a pile of shit
780 #ifdef __V3_64BIT__
781   uint64_t tmr_ticks = 0;
782 #else 
783   uint32_t tmr_ticks = 0;
784 #endif
785
786   uchar_t tmr_div = *(uchar_t *)&(apic->tmr_div_cfg.val);
787   uint_t shift_num = 0;
788
789
790   // Check whether this is true:
791   //   -> If the Init count is zero then the timer is disabled
792   //      and doesn't just blitz interrupts to the CPU
793   if ((apic->tmr_init_cnt == 0) || 
794       ( (apic->tmr_vec_tbl.tmr_mode == APIC_TMR_ONESHOT) &&
795         (apic->tmr_cur_cnt == 0))) {
796     //PrintDebug("APIC timer not yet initialized\n");
797     return;
798   }
799
800
801   switch (tmr_div) {
802   case APIC_TMR_DIV1:
803     shift_num = 0;
804     break;
805   case APIC_TMR_DIV2:
806     shift_num = 1;
807     break;
808   case APIC_TMR_DIV4:
809     shift_num = 2;
810     break;
811   case APIC_TMR_DIV8:
812     shift_num = 3;
813     break;
814   case APIC_TMR_DIV16:
815     shift_num = 4;
816     break;
817   case APIC_TMR_DIV32:
818     shift_num = 5;
819     break;
820   case APIC_TMR_DIV64:
821     shift_num = 6;
822     break;
823  case APIC_TMR_DIV128:
824     shift_num = 7;
825     break;
826   default:
827     PrintError("Invalid Timer Divider configuration\n");
828     return;
829   }
830
831   tmr_ticks = cpu_cycles >> shift_num;
832   //  PrintDebug("Timer Ticks: %p\n", (void *)tmr_ticks);
833
834   if (tmr_ticks <= apic->tmr_cur_cnt) {
835     apic->tmr_cur_cnt -= tmr_ticks;
836   } else {
837     tmr_ticks -= apic->tmr_cur_cnt;
838     apic->tmr_cur_cnt = 0;
839
840     // raise irq
841     if (activate_internal_irq(apic, APIC_TMR_INT) == -1) {
842       PrintError("Could not raise Timer interrupt\n");
843     }
844   }
845
846   if (apic->tmr_vec_tbl.tmr_mode == APIC_TMR_PERIODIC) {
847     tmr_ticks = tmr_ticks % apic->tmr_init_cnt;
848     apic->tmr_init_cnt = apic->tmr_init_cnt - tmr_ticks;
849   }
850 }
851
852
853
854 static struct intr_ctrl_ops intr_ops = {
855   .intr_pending = apic_intr_pending,
856   .get_intr_number = apic_get_intr_number,
857   .raise_intr = apic_raise_intr,
858   .begin_irq = apic_begin_irq,
859   .lower_intr = apic_lower_intr, 
860 };
861
862
863 static struct vm_timer_ops timer_ops = {
864   .update_time = apic_update_time,
865 };
866
867
868 static int apic_init(struct vm_device * dev) {
869   struct guest_info * info = dev->vm;
870   struct apic_state * apic = (struct apic_state *)(dev->private_data);
871
872   v3_register_intr_controller(dev->vm, &intr_ops, dev);
873   v3_add_timer(dev->vm, &timer_ops, dev);
874
875   init_apic_state(apic);
876
877   v3_hook_msr(info, BASE_ADDR_MSR, read_apic_msr, write_apic_msr, dev);
878
879   v3_hook_full_mem(info, apic->base_addr, apic->base_addr + PAGE_SIZE_4KB, apic_read, apic_write, dev);
880
881   return 0;
882 }
883
884 static int apic_deinit(struct vm_device * dev) {
885   struct guest_info * info = dev->vm;
886
887   v3_unhook_msr(info, BASE_ADDR_MSR);
888
889   return 0;
890 }
891
892
893 static struct vm_device_ops dev_ops = {
894   .init = apic_init,
895   .deinit = apic_deinit,
896   .reset = NULL,
897   .start = NULL,
898   .stop = NULL,
899 };
900
901
902 struct vm_device * v3_create_apic() {
903   PrintDebug("Creating APIC\n");
904
905   struct apic_state * apic = (struct apic_state *)V3_Malloc(sizeof(struct apic_state));
906
907   struct vm_device * device = v3_create_device("APIC", &dev_ops, apic);
908   
909   return device;
910 }