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.


Semi-functional SMP (boots Kitten guest with two cores)
[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 <devices/icc_bus.h>
24 #include <palacios/vmm.h>
25 #include <palacios/vmm_msr.h>
26 #include <palacios/vmm_sprintf.h>
27 #include <palacios/vm_guest.h>
28
29
30 #ifndef CONFIG_DEBUG_APIC
31 #undef PrintDebug
32 #define PrintDebug(fmt, args...)
33 #endif
34
35
36 typedef enum { APIC_TMR_INT, APIC_THERM_INT, APIC_PERF_INT, 
37                APIC_LINT0_INT, APIC_LINT1_INT, APIC_ERR_INT } apic_irq_type_t;
38
39 #define APIC_FIXED_DELIVERY  0x0
40 #define APIC_SMI_DELIVERY    0x2
41 #define APIC_NMI_DELIVERY    0x4
42 #define APIC_INIT_DELIVERY   0x5
43 #define APIC_EXTINT_DELIVERY 0x7
44
45
46 #define BASE_ADDR_MSR 0x0000001B
47 #define DEFAULT_BASE_ADDR 0xfee00000
48
49 #define APIC_ID_OFFSET                    0x020
50 #define APIC_VERSION_OFFSET               0x030
51 #define TPR_OFFSET                        0x080
52 #define APR_OFFSET                        0x090
53 #define PPR_OFFSET                        0x0a0
54 #define EOI_OFFSET                        0x0b0
55 #define REMOTE_READ_OFFSET                0x0c0
56 #define LDR_OFFSET                        0x0d0
57 #define DFR_OFFSET                        0x0e0
58 #define SPURIOUS_INT_VEC_OFFSET           0x0f0
59
60 #define ISR_OFFSET0                       0x100   // 0x100 - 0x170
61 #define ISR_OFFSET1                       0x110   // 0x100 - 0x170
62 #define ISR_OFFSET2                       0x120   // 0x100 - 0x170
63 #define ISR_OFFSET3                       0x130   // 0x100 - 0x170
64 #define ISR_OFFSET4                       0x140   // 0x100 - 0x170
65 #define ISR_OFFSET5                       0x150   // 0x100 - 0x170
66 #define ISR_OFFSET6                       0x160   // 0x100 - 0x170
67 #define ISR_OFFSET7                       0x170   // 0x100 - 0x170
68
69 #define TRIG_OFFSET0                      0x180   // 0x180 - 0x1f0
70 #define TRIG_OFFSET1                      0x190   // 0x180 - 0x1f0
71 #define TRIG_OFFSET2                      0x1a0   // 0x180 - 0x1f0
72 #define TRIG_OFFSET3                      0x1b0   // 0x180 - 0x1f0
73 #define TRIG_OFFSET4                      0x1c0   // 0x180 - 0x1f0
74 #define TRIG_OFFSET5                      0x1d0   // 0x180 - 0x1f0
75 #define TRIG_OFFSET6                      0x1e0   // 0x180 - 0x1f0
76 #define TRIG_OFFSET7                      0x1f0   // 0x180 - 0x1f0
77
78
79 #define IRR_OFFSET0                       0x200   // 0x200 - 0x270
80 #define IRR_OFFSET1                       0x210   // 0x200 - 0x270
81 #define IRR_OFFSET2                       0x220   // 0x200 - 0x270
82 #define IRR_OFFSET3                       0x230   // 0x200 - 0x270
83 #define IRR_OFFSET4                       0x240   // 0x200 - 0x270
84 #define IRR_OFFSET5                       0x250   // 0x200 - 0x270
85 #define IRR_OFFSET6                       0x260   // 0x200 - 0x270
86 #define IRR_OFFSET7                       0x270   // 0x200 - 0x270
87
88
89 #define ESR_OFFSET                        0x280
90 #define INT_CMD_LO_OFFSET                 0x300
91 #define INT_CMD_HI_OFFSET                 0x310
92 #define TMR_LOC_VEC_TBL_OFFSET            0x320
93 #define THERM_LOC_VEC_TBL_OFFSET          0x330
94 #define PERF_CTR_LOC_VEC_TBL_OFFSET       0x340
95 #define LINT0_VEC_TBL_OFFSET              0x350
96 #define LINT1_VEC_TBL_OFFSET              0x360
97 #define ERR_VEC_TBL_OFFSET                0x370
98 #define TMR_INIT_CNT_OFFSET               0x380
99 #define TMR_CUR_CNT_OFFSET                0x390
100 #define TMR_DIV_CFG_OFFSET                0x3e0
101 #define EXT_APIC_FEATURE_OFFSET           0x400
102 #define EXT_APIC_CMD_OFFSET               0x410
103 #define SEOI_OFFSET                       0x420
104
105 #define IER_OFFSET0                       0x480   // 0x480 - 0x4f0
106 #define IER_OFFSET1                       0x490   // 0x480 - 0x4f0
107 #define IER_OFFSET2                       0x4a0   // 0x480 - 0x4f0
108 #define IER_OFFSET3                       0x4b0   // 0x480 - 0x4f0
109 #define IER_OFFSET4                       0x4c0   // 0x480 - 0x4f0
110 #define IER_OFFSET5                       0x4d0   // 0x480 - 0x4f0
111 #define IER_OFFSET6                       0x4e0   // 0x480 - 0x4f0
112 #define IER_OFFSET7                       0x4f0   // 0x480 - 0x4f0
113
114 #define EXT_INT_LOC_VEC_TBL_OFFSET0       0x500   // 0x500 - 0x530
115 #define EXT_INT_LOC_VEC_TBL_OFFSET1       0x510   // 0x500 - 0x530
116 #define EXT_INT_LOC_VEC_TBL_OFFSET2       0x520   // 0x500 - 0x530
117 #define EXT_INT_LOC_VEC_TBL_OFFSET3       0x530   // 0x500 - 0x530
118
119
120
121 struct apic_msr {
122     union {
123         uint64_t value;
124         struct {
125             uchar_t rsvd;
126             uint_t bootstrap_cpu : 1;
127             uint_t rsvd2         : 2;
128             uint_t apic_enable   : 1;
129             ullong_t base_addr   : 40;
130             uint_t rsvd3         : 12;
131         } __attribute__((packed));
132     } __attribute__((packed));
133 } __attribute__((packed));
134
135
136
137
138 struct apic_state {
139     addr_t base_addr;
140
141     /* MSRs */
142     struct apic_msr base_addr_msr;
143
144
145     /* memory map registers */
146
147     struct lapic_id_reg lapic_id;
148     struct apic_ver_reg apic_ver;
149     struct ext_apic_ctrl_reg ext_apic_ctrl;
150     struct local_vec_tbl_reg local_vec_tbl;
151     struct tmr_vec_tbl_reg tmr_vec_tbl;
152     struct tmr_div_cfg_reg tmr_div_cfg;
153     struct lint_vec_tbl_reg lint0_vec_tbl;
154     struct lint_vec_tbl_reg lint1_vec_tbl;
155     struct perf_ctr_loc_vec_tbl_reg perf_ctr_loc_vec_tbl;
156     struct therm_loc_vec_tbl_reg therm_loc_vec_tbl;
157     struct err_vec_tbl_reg err_vec_tbl;
158     struct err_status_reg err_status;
159     struct spurious_int_reg spurious_int;
160     struct int_cmd_reg int_cmd;
161     struct log_dst_reg log_dst;
162     struct dst_fmt_reg dst_fmt;
163     struct arb_prio_reg arb_prio;
164     struct task_prio_reg task_prio;
165     struct proc_prio_reg proc_prio;
166     struct ext_apic_feature_reg ext_apic_feature;
167     struct spec_eoi_reg spec_eoi;
168   
169
170     uint32_t tmr_cur_cnt;
171     uint32_t tmr_init_cnt;
172
173
174     struct local_vec_tbl_reg ext_intr_vec_tbl[4];
175
176     uint32_t rem_rd_data;
177
178
179     uchar_t int_req_reg[32];
180     uchar_t int_svc_reg[32];
181     uchar_t int_en_reg[32];
182     uchar_t trig_mode_reg[32];
183   
184     uint32_t eoi;
185
186     struct vm_device * icc_bus;
187
188     v3_lock_t  lock;
189 };
190
191 static int apic_read(struct guest_info * core, addr_t guest_addr, void * dst, uint_t length, void * priv_data);
192 static int apic_write(struct guest_info * core, addr_t guest_addr, void * src, uint_t length, void * priv_data);
193
194 static void init_apic_state(struct apic_state * apic, uint32_t id, struct vm_device * icc) {
195     apic->base_addr = DEFAULT_BASE_ADDR;
196     if (id==0) { 
197         // boot processor, enabled
198         apic->base_addr_msr.value = 0x0000000000000900LL;
199     } else {
200         // ap processor, enabled
201         apic->base_addr_msr.value = 0x0000000000000800LL;
202     }
203
204     // same base address regardless of ap or main
205     apic->base_addr_msr.value |= ((uint64_t)DEFAULT_BASE_ADDR); 
206
207     PrintDebug("apic %u: (init_apic_state): msr=0x%llx\n",id, apic->base_addr_msr.value);
208
209     PrintDebug("apic %u: (init_apic_state): Sizeof Interrupt Request Register %d, should be 32\n",
210                id, (uint_t)sizeof(apic->int_req_reg));
211
212     memset(apic->int_req_reg, 0, sizeof(apic->int_req_reg));
213     memset(apic->int_svc_reg, 0, sizeof(apic->int_svc_reg));
214     memset(apic->int_en_reg, 0xff, sizeof(apic->int_en_reg));
215     memset(apic->trig_mode_reg, 0, sizeof(apic->trig_mode_reg));
216
217     apic->eoi = 0x00000000;
218     apic->rem_rd_data = 0x00000000;
219     apic->tmr_init_cnt = 0x00000000;
220     apic->tmr_cur_cnt = 0x00000000;
221
222     apic->lapic_id.val = id;
223     
224     apic->icc_bus = icc;
225
226     // The P6 has 6 LVT entries, so we set the value to (6-1)...
227     apic->apic_ver.val = 0x80050010;
228
229     apic->task_prio.val = 0x00000000;
230     apic->arb_prio.val = 0x00000000;
231     apic->proc_prio.val = 0x00000000;
232     apic->log_dst.val = 0x00000000;
233     apic->dst_fmt.val = 0xffffffff;
234     apic->spurious_int.val = 0x000000ff;
235     apic->err_status.val = 0x00000000;
236     apic->int_cmd.val = 0x0000000000000000LL;
237     apic->tmr_vec_tbl.val = 0x00010000;
238     apic->therm_loc_vec_tbl.val = 0x00010000;
239     apic->perf_ctr_loc_vec_tbl.val = 0x00010000;
240     apic->lint0_vec_tbl.val = 0x00010000;
241     apic->lint1_vec_tbl.val = 0x00010000;
242     apic->err_vec_tbl.val = 0x00010000;
243     apic->tmr_div_cfg.val = 0x00000000;
244     //apic->ext_apic_feature.val = 0x00000007;
245     apic->ext_apic_feature.val = 0x00040007;
246     apic->ext_apic_ctrl.val = 0x00000000;
247     apic->spec_eoi.val = 0x00000000;
248
249     v3_lock_init(&(apic->lock));
250 }
251
252
253
254
255 static int read_apic_msr(struct guest_info * core, uint_t msr, v3_msr_t * dst, void * priv_data) {
256     struct vm_device * dev = (struct vm_device *)priv_data;
257     struct apic_state * apics = (struct apic_state *)(dev->private_data);
258     struct apic_state * apic = &(apics[core->cpu_id]);
259
260     PrintDebug("apic %u: core %u: MSR read\n",apic->lapic_id.val,core->cpu_id);
261     v3_lock(apic->lock);
262     dst->value = apic->base_addr;
263     v3_unlock(apic->lock);
264     return 0;
265 }
266
267
268 static int write_apic_msr(struct guest_info * core, uint_t msr, v3_msr_t src, void * priv_data) {
269     struct vm_device * dev = (struct vm_device *)priv_data;
270     struct apic_state * apics = (struct apic_state *)(dev->private_data);
271     struct apic_state * apic = &(apics[core->cpu_id]);
272     struct v3_mem_region * old_reg = v3_get_mem_region(dev->vm, core->cpu_id, apic->base_addr);
273
274
275     PrintDebug("apic %u: core %u: MSR write\n",apic->lapic_id.val,core->cpu_id);
276
277     if (old_reg == NULL) {
278         // uh oh...
279         PrintError("apic %u: core %u: APIC Base address region does not exit...\n",apic->lapic_id.val,core->cpu_id);
280         return -1;
281     }
282     
283     v3_lock(apic->lock);
284
285     v3_delete_mem_region(dev->vm, old_reg);
286
287     apic->base_addr = src.value;
288
289     if (v3_hook_full_mem(dev->vm, core->cpu_id, apic->base_addr, apic->base_addr + PAGE_SIZE_4KB, apic_read, apic_write, dev) == -1) {
290         PrintError("apic %u: core %u: Could not hook new APIC Base address\n",apic->lapic_id.val,core->cpu_id);
291         v3_unlock(apic->lock);
292         return -1;
293     }
294
295     v3_unlock(apic->lock);
296     return 0;
297 }
298
299
300 // irq_num is the bit offset into a 256 bit buffer...
301 static int activate_apic_irq(struct apic_state * apic, uint32_t irq_num) {
302     int major_offset = (irq_num & ~0x00000007) >> 3;
303     int minor_offset = irq_num & 0x00000007;
304     uchar_t * req_location = apic->int_req_reg + major_offset;
305     uchar_t * en_location = apic->int_en_reg + major_offset;
306     uchar_t flag = 0x1 << minor_offset;
307
308
309 #if 1
310
311     if (irq_num <= 15) {
312         PrintError("apic %u: core ?: Attempting to raise an invalid interrupt: %d\n", apic->lapic_id.val,irq_num);
313         return -1;
314     }
315
316 #endif
317
318
319     PrintDebug("apic %u: core ?: Raising APIC IRQ %d\n", apic->lapic_id.val,irq_num);
320
321     if (*req_location & flag) {
322         //V3_Print("Interrupts coallescing\n");
323     }
324
325     if (*en_location & flag) {
326         *req_location |= flag;
327     } else {
328         PrintDebug("apic %u: core ?: Interrupt  not enabled... %.2x\n", apic->lapic_id.val, *en_location);
329         return 0;
330     }
331
332     return 0;
333 }
334
335
336
337 static int get_highest_isr(struct apic_state * apic) {
338     int i = 0, j = 0;
339
340     // We iterate backwards to find the highest priority
341     for (i = 31; i >= 0; i--) {
342         uchar_t  * svc_major = apic->int_svc_reg + i;
343     
344         if ((*svc_major) & 0xff) {
345             for (j = 7; j >= 0; j--) {
346                 uchar_t flag = 0x1 << j;
347                 if ((*svc_major) & flag) {
348                     return ((i * 8) + j);
349                 }
350             }
351         }
352     }
353
354     return -1;
355 }
356  
357
358
359 static int get_highest_irr(struct apic_state * apic) {
360     int i = 0, j = 0;
361
362     // We iterate backwards to find the highest priority
363     for (i = 31; i >= 0; i--) {
364         uchar_t  * req_major = apic->int_req_reg + i;
365     
366         if ((*req_major) & 0xff) {
367             for (j = 7; j >= 0; j--) {
368                 uchar_t flag = 0x1 << j;
369                 if ((*req_major) & flag) {
370                     return ((i * 8) + j);
371                 }
372             }
373         }
374     }
375
376     return -1;
377 }
378  
379
380
381
382 static int apic_do_eoi(struct apic_state * apic) {
383     int isr_irq = get_highest_isr(apic);
384
385     if (isr_irq != -1) {
386         int major_offset = (isr_irq & ~0x00000007) >> 3;
387         int minor_offset = isr_irq & 0x00000007;
388         uchar_t flag = 0x1 << minor_offset;
389         uchar_t * svc_location = apic->int_svc_reg + major_offset;
390         
391         PrintDebug("apic %u: core ?: Received APIC EOI for IRQ %d\n", apic->lapic_id.val,isr_irq);
392         
393         *svc_location &= ~flag;
394
395 #ifdef CONFIG_CRAY_XT
396         
397         if ((isr_irq == 238) || 
398             (isr_irq == 239)) {
399             PrintError("apic %u: core ?: Acking IRQ %d\n", apic->lapic_id.val,isr_irq);
400         }
401         
402         if (isr_irq == 238) {
403             V3_ACK_IRQ(238);
404         }
405 #endif
406     } else {
407         //PrintError("apic %u: core ?: Spurious EOI...\n",apic->lapic_id.val);
408     }
409         
410     return 0;
411 }
412  
413
414 static int activate_internal_irq(struct apic_state * apic, apic_irq_type_t int_type) {
415     uint32_t vec_num = 0;
416     uint32_t del_mode = 0;
417     int masked = 0;
418
419
420     switch (int_type) {
421         case APIC_TMR_INT:
422             vec_num = apic->tmr_vec_tbl.vec;
423             del_mode = APIC_FIXED_DELIVERY;
424             masked = apic->tmr_vec_tbl.mask;
425             break;
426         case APIC_THERM_INT:
427             vec_num = apic->therm_loc_vec_tbl.vec;
428             del_mode = apic->therm_loc_vec_tbl.msg_type;
429             masked = apic->therm_loc_vec_tbl.mask;
430             break;
431         case APIC_PERF_INT:
432             vec_num = apic->perf_ctr_loc_vec_tbl.vec;
433             del_mode = apic->perf_ctr_loc_vec_tbl.msg_type;
434             masked = apic->perf_ctr_loc_vec_tbl.mask;
435             break;
436         case APIC_LINT0_INT:
437             vec_num = apic->lint0_vec_tbl.vec;
438             del_mode = apic->lint0_vec_tbl.msg_type;
439             masked = apic->lint0_vec_tbl.mask;
440             break;
441         case APIC_LINT1_INT:
442             vec_num = apic->lint1_vec_tbl.vec;
443             del_mode = apic->lint1_vec_tbl.msg_type;
444             masked = apic->lint1_vec_tbl.mask;
445             break;
446         case APIC_ERR_INT:
447             vec_num = apic->err_vec_tbl.vec;
448             del_mode = APIC_FIXED_DELIVERY;
449             masked = apic->err_vec_tbl.mask;
450             break;
451         default:
452             PrintError("apic %u: core ?: Invalid APIC interrupt type\n",apic->lapic_id.val);
453             return -1;
454     }
455
456     // interrupt is masked, don't send
457     if (masked == 1) {
458         PrintDebug("apic %u: core ?: Inerrupt is masked\n",apic->lapic_id.val);
459         return 0;
460     }
461
462     if (del_mode == APIC_FIXED_DELIVERY) {
463         //PrintDebug("Activating internal APIC IRQ %d\n", vec_num);
464         return activate_apic_irq(apic, vec_num);
465     } else {
466         PrintError("apic %u: core ?: Unhandled Delivery Mode\n",apic->lapic_id.val);
467         return -1;
468     }
469 }
470
471
472 static int apic_read(struct guest_info * core, addr_t guest_addr, void * dst, uint_t length, void * priv_data) {
473     struct apic_state * apic = (struct apic_state *)(priv_data);
474     addr_t reg_addr  = guest_addr - apic->base_addr;
475     struct apic_msr * msr = (struct apic_msr *)&(apic->base_addr_msr.value);
476     uint32_t val = 0;
477
478
479     PrintDebug("apic %u: core %u: at %p: Read apic address space (%p)\n",apic->lapic_id.val,core->cpu_id, apic, (void *)guest_addr);
480
481     if (msr->apic_enable == 0) {
482         PrintError("apic %u: core %u: Read from APIC address space with disabled APIC, apic msr=0x%llx\n",apic->lapic_id.val,core->cpu_id,apic->base_addr_msr.value);
483
484         return -1;
485     }
486
487
488     /* Because "May not be supported" doesn't matter to Linux developers... */
489     /*   if (length != 4) { */
490     /*     PrintError("Invalid apic read length (%d)\n", length); */
491     /*     return -1; */
492     /*   } */
493
494     switch (reg_addr & ~0x3) {
495         case EOI_OFFSET:
496             // Well, only an idiot would read from a architectural write only register
497             // Oh, Hello Linux.
498             //    PrintError("Attempting to read from write only register\n");
499             //    return -1;
500             break;
501
502             // data registers
503         case APIC_ID_OFFSET:
504             val = apic->lapic_id.val;
505             break;
506         case APIC_VERSION_OFFSET:
507             val = apic->apic_ver.val;
508             break;
509         case TPR_OFFSET:
510             val = apic->task_prio.val;
511             break;
512         case APR_OFFSET:
513             val = apic->arb_prio.val;
514             break;
515         case PPR_OFFSET:
516             val = apic->proc_prio.val;
517             break;
518         case REMOTE_READ_OFFSET:
519             val = apic->rem_rd_data;
520             break;
521         case LDR_OFFSET:
522             val = apic->log_dst.val;
523             break;
524         case DFR_OFFSET:
525             val = apic->dst_fmt.val;
526             break;
527         case SPURIOUS_INT_VEC_OFFSET:
528             val = apic->spurious_int.val;
529             break;
530         case ESR_OFFSET:
531             val = apic->err_status.val;
532             break;
533         case TMR_LOC_VEC_TBL_OFFSET:
534             val = apic->tmr_vec_tbl.val;
535             break;
536         case LINT0_VEC_TBL_OFFSET:
537             val = apic->lint0_vec_tbl.val;
538             break;
539         case LINT1_VEC_TBL_OFFSET:
540             val = apic->lint1_vec_tbl.val;
541             break;
542         case ERR_VEC_TBL_OFFSET:
543             val = apic->err_vec_tbl.val;
544             break;
545         case TMR_INIT_CNT_OFFSET:
546             val = apic->tmr_init_cnt;
547             break;
548         case TMR_DIV_CFG_OFFSET:
549             val = apic->tmr_div_cfg.val;
550             break;
551
552         case IER_OFFSET0:
553             val = *(uint32_t *)(apic->int_en_reg);
554             break;
555         case IER_OFFSET1:
556             val = *(uint32_t *)(apic->int_en_reg + 4);
557             break;
558         case IER_OFFSET2:
559             val = *(uint32_t *)(apic->int_en_reg + 8);
560             break;
561         case IER_OFFSET3:
562             val = *(uint32_t *)(apic->int_en_reg + 12);
563             break;
564         case IER_OFFSET4:
565             val = *(uint32_t *)(apic->int_en_reg + 16);
566             break;
567         case IER_OFFSET5:
568             val = *(uint32_t *)(apic->int_en_reg + 20);
569             break;
570         case IER_OFFSET6:
571             val = *(uint32_t *)(apic->int_en_reg + 24);
572             break;
573         case IER_OFFSET7:
574             val = *(uint32_t *)(apic->int_en_reg + 28);
575             break;
576
577         case ISR_OFFSET0:
578             val = *(uint32_t *)(apic->int_svc_reg);
579             break;
580         case ISR_OFFSET1:
581             val = *(uint32_t *)(apic->int_svc_reg + 4);
582             break;
583         case ISR_OFFSET2:
584             val = *(uint32_t *)(apic->int_svc_reg + 8);
585             break;
586         case ISR_OFFSET3:
587             val = *(uint32_t *)(apic->int_svc_reg + 12);
588             break;
589         case ISR_OFFSET4:
590             val = *(uint32_t *)(apic->int_svc_reg + 16);
591             break;
592         case ISR_OFFSET5:
593             val = *(uint32_t *)(apic->int_svc_reg + 20);
594             break;
595         case ISR_OFFSET6:
596             val = *(uint32_t *)(apic->int_svc_reg + 24);
597             break;
598         case ISR_OFFSET7:
599             val = *(uint32_t *)(apic->int_svc_reg + 28);
600             break;
601    
602         case TRIG_OFFSET0:
603             val = *(uint32_t *)(apic->trig_mode_reg);
604             break;
605         case TRIG_OFFSET1:
606             val = *(uint32_t *)(apic->trig_mode_reg + 4);
607             break;
608         case TRIG_OFFSET2:
609             val = *(uint32_t *)(apic->trig_mode_reg + 8);
610             break;
611         case TRIG_OFFSET3:
612             val = *(uint32_t *)(apic->trig_mode_reg + 12);
613             break;
614         case TRIG_OFFSET4:
615             val = *(uint32_t *)(apic->trig_mode_reg + 16);
616             break;
617         case TRIG_OFFSET5:
618             val = *(uint32_t *)(apic->trig_mode_reg + 20);
619             break;
620         case TRIG_OFFSET6:
621             val = *(uint32_t *)(apic->trig_mode_reg + 24);
622             break;
623         case TRIG_OFFSET7:
624             val = *(uint32_t *)(apic->trig_mode_reg + 28);
625             break;
626
627         case IRR_OFFSET0:
628             val = *(uint32_t *)(apic->int_req_reg);
629             break;
630         case IRR_OFFSET1:
631             val = *(uint32_t *)(apic->int_req_reg + 4);
632             break;
633         case IRR_OFFSET2:
634             val = *(uint32_t *)(apic->int_req_reg + 8);
635             break;
636         case IRR_OFFSET3:
637             val = *(uint32_t *)(apic->int_req_reg + 12);
638             break;
639         case IRR_OFFSET4:
640             val = *(uint32_t *)(apic->int_req_reg + 16);
641             break;
642         case IRR_OFFSET5:
643             val = *(uint32_t *)(apic->int_req_reg + 20);
644             break;
645         case IRR_OFFSET6:
646             val = *(uint32_t *)(apic->int_req_reg + 24);
647             break;
648         case IRR_OFFSET7:
649             val = *(uint32_t *)(apic->int_req_reg + 28);
650             break;
651         case TMR_CUR_CNT_OFFSET:
652             val = apic->tmr_cur_cnt;
653             break;
654
655             // We are not going to implement these....
656         case THERM_LOC_VEC_TBL_OFFSET:
657             val = apic->therm_loc_vec_tbl.val;
658             break;
659         case PERF_CTR_LOC_VEC_TBL_OFFSET:
660             val = apic->perf_ctr_loc_vec_tbl.val;
661             break;
662
663  
664
665             // handled registers
666         case INT_CMD_LO_OFFSET:    
667             val = apic->int_cmd.lo;
668             break;
669         case INT_CMD_HI_OFFSET:
670             val = apic->int_cmd.hi;
671             break;
672
673             // handle current timer count
674
675             // Unhandled Registers
676         case EXT_INT_LOC_VEC_TBL_OFFSET0:
677             val = apic->ext_intr_vec_tbl[0].val;
678             break;
679         case EXT_INT_LOC_VEC_TBL_OFFSET1:
680             val = apic->ext_intr_vec_tbl[1].val;
681             break;
682         case EXT_INT_LOC_VEC_TBL_OFFSET2:
683             val = apic->ext_intr_vec_tbl[2].val;
684             break;
685         case EXT_INT_LOC_VEC_TBL_OFFSET3:
686             val = apic->ext_intr_vec_tbl[3].val;
687             break;
688     
689
690         case EXT_APIC_FEATURE_OFFSET:
691         case EXT_APIC_CMD_OFFSET:
692         case SEOI_OFFSET:
693
694         default:
695             PrintError("apic %u: core %u: Read from Unhandled APIC Register: %x (getting zero)\n", apic->lapic_id.val,core->cpu_id, (uint32_t)reg_addr);
696             //      return -1;
697             val=0;
698     }
699
700
701     if (length == 1) {
702         uint_t byte_addr = reg_addr & 0x3;
703         uint8_t * val_ptr = (uint8_t *)dst;
704     
705         *val_ptr = *(((uint8_t *)&val) + byte_addr);
706
707     } else if ((length == 2) && 
708                ((reg_addr & 0x3) == 0x3)) {
709         uint_t byte_addr = reg_addr & 0x3;
710         uint16_t * val_ptr = (uint16_t *)dst;
711         *val_ptr = *(((uint16_t *)&val) + byte_addr);
712
713     } else if (length == 4) {
714         uint32_t * val_ptr = (uint32_t *)dst;
715         *val_ptr = val;
716
717     } else {
718         PrintError("apic %u: core %u: Invalid apic read length (%d)\n", apic->lapic_id.val,core->cpu_id, length);
719         return -1;
720     }
721
722     PrintDebug("apic %u: core %u: Read finished (val=%x)\n", apic->lapic_id.val,core->cpu_id, *(uint32_t *)dst);
723
724     return length;
725 }
726
727
728 /**
729  *
730  */
731 static int apic_write(struct guest_info * core, addr_t guest_addr, void * src, uint_t length, void * priv_data) {
732     struct apic_state * apic = (struct apic_state *)(priv_data);
733     addr_t reg_addr  = guest_addr - apic->base_addr;
734     struct apic_msr * msr = (struct apic_msr *)&(apic->base_addr_msr.value);
735     uint32_t op_val = *(uint32_t *)src;
736
737     PrintDebug("apic %u: core %u: at %p and priv_data is at %p: Write to address space (%p) (val=%x)\n", 
738                apic->lapic_id.val, core->cpu_id, apic,priv_data,
739                (void *)guest_addr, *(uint32_t *)src);
740
741     if (msr->apic_enable == 0) {
742         PrintError("apic %u: core %u: Write to APIC address space with disabled APIC, apic msr=0x%llx\n",apic->lapic_id.val,core->cpu_id,apic->base_addr_msr.value);
743         return -1;
744     }
745
746
747     if (length != 4) {
748         PrintError("apic %u: core %u: Invalid apic write length (%d)\n", apic->lapic_id.val, length,core->cpu_id);
749         return -1;
750     }
751
752     switch (reg_addr) {
753         case REMOTE_READ_OFFSET:
754         case APIC_VERSION_OFFSET:
755         case APR_OFFSET:
756         case IRR_OFFSET0:
757         case IRR_OFFSET1:
758         case IRR_OFFSET2:
759         case IRR_OFFSET3:
760         case IRR_OFFSET4:
761         case IRR_OFFSET5:
762         case IRR_OFFSET6:
763         case IRR_OFFSET7:
764         case ISR_OFFSET0:
765         case ISR_OFFSET1:
766         case ISR_OFFSET2:
767         case ISR_OFFSET3:
768         case ISR_OFFSET4:
769         case ISR_OFFSET5:
770         case ISR_OFFSET6:
771         case ISR_OFFSET7:
772         case TRIG_OFFSET0:
773         case TRIG_OFFSET1:
774         case TRIG_OFFSET2:
775         case TRIG_OFFSET3:
776         case TRIG_OFFSET4:
777         case TRIG_OFFSET5:
778         case TRIG_OFFSET6:
779         case TRIG_OFFSET7:
780         case PPR_OFFSET:
781         case EXT_APIC_FEATURE_OFFSET:
782 #if 1
783             PrintError("apic %u: core %u: Attempting to write to read only register %p (ignored)\n", apic->lapic_id.val,core->cpu_id, (void *)reg_addr);
784 #else   
785             PrintError("apic %u: core %u: Attempting to write to read only register %p (error)\n", apic->lapic_id.val,core->cpu_id, (void *)reg_addr);
786             return -1;
787 #endif
788             break;
789
790             // Data registers
791         case APIC_ID_OFFSET:
792             PrintDebug("apic %u: core %u: my id is being changed to %u\n",apic->lapic_id.val,core->cpu_id,op_val);
793             apic->lapic_id.val = op_val;
794             break;
795         case TPR_OFFSET:
796             apic->task_prio.val = op_val;
797             break;
798         case LDR_OFFSET:
799             apic->log_dst.val = op_val;
800             break;
801         case DFR_OFFSET:
802             apic->dst_fmt.val = op_val;
803             break;
804         case SPURIOUS_INT_VEC_OFFSET:
805             apic->spurious_int.val = op_val;
806             break;
807         case ESR_OFFSET:
808             apic->err_status.val = op_val;
809             break;
810         case TMR_LOC_VEC_TBL_OFFSET:
811             apic->tmr_vec_tbl.val = op_val;
812             break;
813         case THERM_LOC_VEC_TBL_OFFSET:
814             apic->therm_loc_vec_tbl.val = op_val;
815             break;
816         case PERF_CTR_LOC_VEC_TBL_OFFSET:
817             apic->perf_ctr_loc_vec_tbl.val = op_val;
818             break;
819         case LINT0_VEC_TBL_OFFSET:
820             apic->lint0_vec_tbl.val = op_val;
821             break;
822         case LINT1_VEC_TBL_OFFSET:
823             apic->lint1_vec_tbl.val = op_val;
824             break;
825         case ERR_VEC_TBL_OFFSET:
826             apic->err_vec_tbl.val = op_val;
827             break;
828         case TMR_INIT_CNT_OFFSET:
829             apic->tmr_init_cnt = op_val;
830             apic->tmr_cur_cnt = op_val;
831             break;
832         case TMR_CUR_CNT_OFFSET:
833             apic->tmr_cur_cnt = op_val;
834             break;
835         case TMR_DIV_CFG_OFFSET:
836             apic->tmr_div_cfg.val = op_val;
837             break;
838
839
840             // Enable mask (256 bits)
841         case IER_OFFSET0:
842             *(uint32_t *)(apic->int_en_reg) = op_val;
843             break;
844         case IER_OFFSET1:
845             *(uint32_t *)(apic->int_en_reg + 4) = op_val;
846             break;
847         case IER_OFFSET2:
848             *(uint32_t *)(apic->int_en_reg + 8) = op_val;
849             break;
850         case IER_OFFSET3:
851             *(uint32_t *)(apic->int_en_reg + 12) = op_val;
852             break;
853         case IER_OFFSET4:
854             *(uint32_t *)(apic->int_en_reg + 16) = op_val;
855             break;
856         case IER_OFFSET5:
857             *(uint32_t *)(apic->int_en_reg + 20) = op_val;
858             break;
859         case IER_OFFSET6:
860             *(uint32_t *)(apic->int_en_reg + 24) = op_val;
861             break;
862         case IER_OFFSET7:
863             *(uint32_t *)(apic->int_en_reg + 28) = op_val;
864             break;
865
866         case EXT_INT_LOC_VEC_TBL_OFFSET0:
867             apic->ext_intr_vec_tbl[0].val = op_val;
868             break;
869         case EXT_INT_LOC_VEC_TBL_OFFSET1:
870             apic->ext_intr_vec_tbl[1].val = op_val;
871             break;
872         case EXT_INT_LOC_VEC_TBL_OFFSET2:
873             apic->ext_intr_vec_tbl[2].val = op_val;
874             break;
875         case EXT_INT_LOC_VEC_TBL_OFFSET3:
876             apic->ext_intr_vec_tbl[3].val = op_val;
877             break;
878
879
880             // Action Registers
881         case EOI_OFFSET:
882             // do eoi
883             apic_do_eoi(apic);
884             break;
885
886         case INT_CMD_LO_OFFSET:
887             apic->int_cmd.lo = op_val;
888             // ICC???
889             PrintDebug("apic %u: core %u: sending cmd 0x%llx to apic %u\n",apic->lapic_id.val,core->cpu_id,
890                        apic->int_cmd.val, apic->int_cmd.dst);
891             v3_icc_send_ipi(apic->icc_bus, apic->lapic_id.val, apic->int_cmd.val,0);
892             break;
893         case INT_CMD_HI_OFFSET:
894             apic->int_cmd.hi = op_val;
895             break;
896             // Unhandled Registers
897
898         case EXT_APIC_CMD_OFFSET:
899         case SEOI_OFFSET:
900         default:
901             PrintError("apic %u: core %u: Write to Unhandled APIC Register: %x (ignored)\n", apic->lapic_id.val,core->cpu_id, (uint32_t)reg_addr);
902             //      return -1;
903     }
904
905     PrintDebug("apic %u: core %u: Write finished\n",apic->lapic_id.val,core->cpu_id);
906
907     return length;
908 }
909
910
911
912 /* Interrupt Controller Functions */
913
914 // returns 1 if an interrupt is pending, 0 otherwise
915 static int apic_intr_pending(struct guest_info * info, void * private_data) {
916     struct apic_state * apic = (struct apic_state *)private_data;
917     int req_irq = get_highest_irr(apic);
918     int svc_irq = get_highest_isr(apic);
919
920     if ((req_irq >= 0) && 
921         (req_irq > svc_irq)) {
922         return 1;
923     }
924
925     return 0;
926 }
927
928 static int apic_get_intr_number(struct guest_info * info, void * private_data) {
929     struct apic_state * apic = (struct apic_state *)private_data;
930     int req_irq = get_highest_irr(apic);
931     int svc_irq = get_highest_isr(apic);
932
933     if (svc_irq == -1) {
934         return req_irq;
935     } else if (svc_irq < req_irq) {
936         return req_irq;
937     }
938
939     return -1;
940 }
941
942
943 static int apic_raise_intr(struct guest_info * info, int irq, void * private_data) {
944   struct apic_state * apic = (struct apic_state *)private_data;
945
946   return activate_apic_irq(apic, irq);
947 }
948
949
950
951 static int apic_begin_irq(struct guest_info * info, void * private_data, int irq) {
952     struct apic_state * apic = (struct apic_state *)private_data;
953     int major_offset = (irq & ~0x00000007) >> 3;
954     int minor_offset = irq & 0x00000007;
955     uchar_t * req_location = apic->int_req_reg + major_offset;
956     uchar_t * svc_location = apic->int_svc_reg + major_offset;
957     uchar_t flag = 0x01 << minor_offset;
958
959     *svc_location |= flag;
960     *req_location &= ~flag;
961
962
963
964     return 0;
965 }
966
967
968
969
970 /* Timer Functions */
971 static void apic_update_time(struct guest_info * info, ullong_t cpu_cycles, ullong_t cpu_freq, void * priv_data) {
972     struct apic_state * apic = (struct apic_state *)(priv_data);
973     // The 32 bit GCC runtime is a pile of shit
974 #ifdef __V3_64BIT__
975     uint64_t tmr_ticks = 0;
976 #else 
977     uint32_t tmr_ticks = 0;
978 #endif
979
980     uchar_t tmr_div = *(uchar_t *)&(apic->tmr_div_cfg.val);
981     uint_t shift_num = 0;
982
983
984     // Check whether this is true:
985     //   -> If the Init count is zero then the timer is disabled
986     //      and doesn't just blitz interrupts to the CPU
987     if ((apic->tmr_init_cnt == 0) || 
988         ( (apic->tmr_vec_tbl.tmr_mode == APIC_TMR_ONESHOT) &&
989           (apic->tmr_cur_cnt == 0))) {
990         //PrintDebug("apic %u: core %u: APIC timer not yet initialized\n",apic->lapic_id.val,info->cpu_id);
991         return;
992     }
993
994
995     switch (tmr_div) {
996         case APIC_TMR_DIV1:
997             shift_num = 0;
998             break;
999         case APIC_TMR_DIV2:
1000             shift_num = 1;
1001             break;
1002         case APIC_TMR_DIV4:
1003             shift_num = 2;
1004             break;
1005         case APIC_TMR_DIV8:
1006             shift_num = 3;
1007             break;
1008         case APIC_TMR_DIV16:
1009             shift_num = 4;
1010             break;
1011         case APIC_TMR_DIV32:
1012             shift_num = 5;
1013             break;
1014         case APIC_TMR_DIV64:
1015             shift_num = 6;
1016             break;
1017         case APIC_TMR_DIV128:
1018             shift_num = 7;
1019             break;
1020         default:
1021             PrintError("apic %u: core %u: Invalid Timer Divider configuration\n",apic->lapic_id.val,info->cpu_id);
1022             return;
1023     }
1024
1025     tmr_ticks = cpu_cycles >> shift_num;
1026     //    PrintDebug("Timer Ticks: %p\n", (void *)tmr_ticks);
1027
1028     if (tmr_ticks < apic->tmr_cur_cnt) {
1029         apic->tmr_cur_cnt -= tmr_ticks;
1030     } else {
1031         tmr_ticks -= apic->tmr_cur_cnt;
1032         apic->tmr_cur_cnt = 0;
1033
1034         // raise irq
1035         PrintDebug("apic %u: core %u: Raising APIC Timer interrupt (periodic=%d) (icnt=%d) (div=%d)\n", apic->lapic_id.val,info->cpu_id,
1036                    apic->tmr_vec_tbl.tmr_mode, apic->tmr_init_cnt, shift_num);
1037
1038         if (apic_intr_pending(info, priv_data)) {
1039             PrintDebug("apic %u: core %u: Overriding pending IRQ %d\n", apic->lapic_id.val,info->cpu_id, apic_get_intr_number(info, priv_data));
1040         }
1041
1042         if (activate_internal_irq(apic, APIC_TMR_INT) == -1) {
1043             PrintError("apic %u: core %u: Could not raise Timer interrupt\n",apic->lapic_id.val,info->cpu_id);
1044         }
1045     
1046         if (apic->tmr_vec_tbl.tmr_mode == APIC_TMR_PERIODIC) {
1047             tmr_ticks = tmr_ticks % apic->tmr_init_cnt;
1048             apic->tmr_cur_cnt = apic->tmr_init_cnt - tmr_ticks;
1049         }
1050     }
1051
1052
1053 }
1054
1055
1056 static struct intr_ctrl_ops intr_ops = {
1057     .intr_pending = apic_intr_pending,
1058     .get_intr_number = apic_get_intr_number,
1059     .begin_irq = apic_begin_irq,
1060 };
1061
1062
1063 static struct vm_timer_ops timer_ops = {
1064     .update_time = apic_update_time,
1065 };
1066
1067
1068
1069
1070 static int apic_free(struct vm_device * dev) {
1071
1072     /* TODO: This should crosscall to force an unhook on each CPU */
1073
1074     //   struct apic_state * apic = (struct apic_state *)dev->private_data;
1075
1076     v3_unhook_msr(dev->vm, BASE_ADDR_MSR);
1077
1078     return 0;
1079 }
1080
1081
1082 static struct v3_device_ops dev_ops = {
1083     .free = apic_free,
1084     .reset = NULL,
1085     .start = NULL,
1086     .stop = NULL,
1087 };
1088
1089
1090
1091 static struct v3_icc_ops icc_ops = {
1092     .raise_intr = apic_raise_intr,
1093 };
1094
1095
1096
1097 static int apic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
1098     PrintDebug("apic: creating an APIC for each core\n");
1099     char * name = v3_cfg_val(cfg, "name");
1100     char * icc_name = v3_cfg_val(cfg,"bus");
1101     struct vm_device * icc = v3_find_dev(vm, icc_name);
1102     int i;
1103
1104     if (!icc) {
1105         PrintError("apic: Cannot find ICC Bus (%s)\n", icc_name);
1106         return -1;
1107     }
1108
1109     // We allocate one apic per core
1110     // APICs are accessed via index which correlates with the core's cpu_id 
1111     // 0..num_cores-1   at num_cores is the ioapic (one only)
1112     struct apic_state * apic = (struct apic_state *)V3_Malloc(sizeof(struct apic_state) * vm->num_cores);
1113
1114     struct vm_device * dev = v3_allocate_device(name, &dev_ops, apic);
1115
1116     if (v3_attach_device(vm, dev) == -1) {
1117         PrintError("apic: Could not attach device %s\n", name);
1118         return -1;
1119     }
1120
1121     
1122     for (i = 0; i < vm->num_cores; i++) {
1123         struct guest_info * core = &(vm->cores[i]);
1124
1125         init_apic_state(&(apic[i]),i,icc);
1126
1127         v3_register_intr_controller(core, &intr_ops, &(apic[i]));
1128
1129         v3_add_timer(core, &timer_ops, &(apic[i]));
1130
1131         v3_hook_full_mem(vm, core->cpu_id, apic->base_addr, apic->base_addr + PAGE_SIZE_4KB, apic_read, apic_write, &(apic[i]));
1132
1133         v3_icc_register_apic(core, icc, i, &icc_ops, &(apic[i]));
1134
1135         PrintDebug("apic %u: (setup device): done, my id is %u\n",i,apic[i].lapic_id.val);
1136
1137     }
1138
1139     for (i=0;i<vm->num_cores;i++) {
1140         PrintDebug("apic: sanity check: apic %u (at %p) has id %u and msr value %llx\n",
1141                    i, &(apic[i]), apic[i].lapic_id.val, apic[i].base_addr_msr.value);
1142     }
1143     PrintDebug("apic: priv_data is at %p\n", apic);
1144
1145     v3_hook_msr(vm, BASE_ADDR_MSR, read_apic_msr, write_apic_msr, dev);
1146
1147     return 0;
1148 }
1149
1150
1151
1152 device_register("LAPIC", apic_init)