Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


added irq queueing to APIC
[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  * Authors: Jack Lange <jarusl@cs.northwestern.edu>
15  *          Peter Dinda <pdinda@northwestern.edu> (SMP)
16  *
17  * This is free software.  You are permitted to use,
18  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
19  */
20
21
22 #include <devices/apic.h>
23 #include <devices/apic_regs.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 #include <palacios/vmm_types.h>
29
30
31 #include <palacios/vmm_queue.h>
32 #include <palacios/vmm_lock.h>
33
34 /* The locking in this file is nasty.
35  * There are 3 different locking approaches that are taken, depending on the APIC operation
36  * 1. Queue locks. Actual irq insertions are done via queueing irq ops at the dest apic. 
37  *    The destination apic's core is responsible for draining the queue, and actually 
38  *    setting the vector table. 
39  * 2. State lock. This is a standard lock taken when internal apic state is read/written. 
40  *    When an irq's destination is determined this lock is taken to examine the apic's 
41  *    addressability. 
42  * 3. VM barrier lock. This is taken when actual VM core state is changed (via SIPI). 
43  */
44
45
46
47 #ifndef V3_CONFIG_DEBUG_APIC
48 #undef PrintDebug
49 #define PrintDebug(fmt, args...)
50 #else
51
52 static char * shorthand_str[] = { 
53     "(no shorthand)",
54     "(self)",
55     "(all)",
56     "(all-but-me)",
57 };
58
59 static char * deliverymode_str[] = { 
60     "(fixed)",
61     "(lowest priority)",
62     "(SMI)",
63     "(reserved)",
64     "(NMI)",
65     "(INIT)",
66     "(Start Up)",
67     "(ExtInt)",
68 };
69
70 #endif
71
72 typedef enum { APIC_TMR_INT, APIC_THERM_INT, APIC_PERF_INT, 
73                APIC_LINT0_INT, APIC_LINT1_INT, APIC_ERR_INT } apic_irq_type_t;
74
75 #define APIC_FIXED_DELIVERY  0x0
76 #define APIC_LOWEST_DELIVERY 0x1
77 #define APIC_SMI_DELIVERY    0x2
78 #define APIC_RES1_DELIVERY   0x3
79 #define APIC_NMI_DELIVERY    0x4
80 #define APIC_INIT_DELIVERY   0x5
81 #define APIC_SIPI_DELIVERY   0x6
82 #define APIC_EXTINT_DELIVERY 0x7
83
84 #define APIC_SHORTHAND_NONE        0x0
85 #define APIC_SHORTHAND_SELF        0x1
86 #define APIC_SHORTHAND_ALL         0x2
87 #define APIC_SHORTHAND_ALL_BUT_ME  0x3
88
89 #define APIC_DEST_PHYSICAL    0x0
90 #define APIC_DEST_LOGICAL     0x1
91
92
93 #define BASE_ADDR_MSR     0x0000001B
94 #define DEFAULT_BASE_ADDR 0xfee00000
95
96 #define APIC_ID_OFFSET                    0x020
97 #define APIC_VERSION_OFFSET               0x030
98 #define TPR_OFFSET                        0x080
99 #define APR_OFFSET                        0x090
100 #define PPR_OFFSET                        0x0a0
101 #define EOI_OFFSET                        0x0b0
102 #define REMOTE_READ_OFFSET                0x0c0
103 #define LDR_OFFSET                        0x0d0
104 #define DFR_OFFSET                        0x0e0
105 #define SPURIOUS_INT_VEC_OFFSET           0x0f0
106
107 #define ISR_OFFSET0                       0x100   // 0x100 - 0x170
108 #define ISR_OFFSET1                       0x110   // 0x100 - 0x170
109 #define ISR_OFFSET2                       0x120   // 0x100 - 0x170
110 #define ISR_OFFSET3                       0x130   // 0x100 - 0x170
111 #define ISR_OFFSET4                       0x140   // 0x100 - 0x170
112 #define ISR_OFFSET5                       0x150   // 0x100 - 0x170
113 #define ISR_OFFSET6                       0x160   // 0x100 - 0x170
114 #define ISR_OFFSET7                       0x170   // 0x100 - 0x170
115
116 #define TRIG_OFFSET0                      0x180   // 0x180 - 0x1f0
117 #define TRIG_OFFSET1                      0x190   // 0x180 - 0x1f0
118 #define TRIG_OFFSET2                      0x1a0   // 0x180 - 0x1f0
119 #define TRIG_OFFSET3                      0x1b0   // 0x180 - 0x1f0
120 #define TRIG_OFFSET4                      0x1c0   // 0x180 - 0x1f0
121 #define TRIG_OFFSET5                      0x1d0   // 0x180 - 0x1f0
122 #define TRIG_OFFSET6                      0x1e0   // 0x180 - 0x1f0
123 #define TRIG_OFFSET7                      0x1f0   // 0x180 - 0x1f0
124
125
126 #define IRR_OFFSET0                       0x200   // 0x200 - 0x270
127 #define IRR_OFFSET1                       0x210   // 0x200 - 0x270
128 #define IRR_OFFSET2                       0x220   // 0x200 - 0x270
129 #define IRR_OFFSET3                       0x230   // 0x200 - 0x270
130 #define IRR_OFFSET4                       0x240   // 0x200 - 0x270
131 #define IRR_OFFSET5                       0x250   // 0x200 - 0x270
132 #define IRR_OFFSET6                       0x260   // 0x200 - 0x270
133 #define IRR_OFFSET7                       0x270   // 0x200 - 0x270
134
135
136 #define ESR_OFFSET                        0x280
137 #define INT_CMD_LO_OFFSET                 0x300
138 #define INT_CMD_HI_OFFSET                 0x310
139 #define TMR_LOC_VEC_TBL_OFFSET            0x320
140 #define THERM_LOC_VEC_TBL_OFFSET          0x330
141 #define PERF_CTR_LOC_VEC_TBL_OFFSET       0x340
142 #define LINT0_VEC_TBL_OFFSET              0x350
143 #define LINT1_VEC_TBL_OFFSET              0x360
144 #define ERR_VEC_TBL_OFFSET                0x370
145 #define TMR_INIT_CNT_OFFSET               0x380
146 #define TMR_CUR_CNT_OFFSET                0x390
147 #define TMR_DIV_CFG_OFFSET                0x3e0
148 #define EXT_APIC_FEATURE_OFFSET           0x400
149 #define EXT_APIC_CMD_OFFSET               0x410
150 #define SEOI_OFFSET                       0x420
151
152 #define IER_OFFSET0                       0x480   // 0x480 - 0x4f0
153 #define IER_OFFSET1                       0x490   // 0x480 - 0x4f0
154 #define IER_OFFSET2                       0x4a0   // 0x480 - 0x4f0
155 #define IER_OFFSET3                       0x4b0   // 0x480 - 0x4f0
156 #define IER_OFFSET4                       0x4c0   // 0x480 - 0x4f0
157 #define IER_OFFSET5                       0x4d0   // 0x480 - 0x4f0
158 #define IER_OFFSET6                       0x4e0   // 0x480 - 0x4f0
159 #define IER_OFFSET7                       0x4f0   // 0x480 - 0x4f0
160
161 #define EXT_INT_LOC_VEC_TBL_OFFSET0       0x500   // 0x500 - 0x530
162 #define EXT_INT_LOC_VEC_TBL_OFFSET1       0x510   // 0x500 - 0x530
163 #define EXT_INT_LOC_VEC_TBL_OFFSET2       0x520   // 0x500 - 0x530
164 #define EXT_INT_LOC_VEC_TBL_OFFSET3       0x530   // 0x500 - 0x530
165
166 struct apic_msr {
167     union {
168         uint64_t value;
169         struct {
170             uint8_t rsvd;
171             uint8_t bootstrap_cpu : 1;
172             uint8_t rsvd2         : 2;
173             uint8_t apic_enable   : 1;
174             uint64_t base_addr    : 40;
175             uint32_t rsvd3        : 12;
176         } __attribute__((packed));
177     } __attribute__((packed));
178 } __attribute__((packed));
179
180
181
182
183 typedef enum {INIT_ST, 
184               SIPI, 
185               STARTED} ipi_state_t; 
186
187 struct apic_dev_state;
188
189 struct apic_state {
190     addr_t base_addr;
191
192     /* MSRs */
193     struct apic_msr base_addr_msr;
194
195
196     /* memory map registers */
197
198     struct lapic_id_reg lapic_id;
199     struct apic_ver_reg apic_ver;
200     struct ext_apic_ctrl_reg ext_apic_ctrl;
201     struct local_vec_tbl_reg local_vec_tbl;
202     struct tmr_vec_tbl_reg tmr_vec_tbl;
203     struct tmr_div_cfg_reg tmr_div_cfg;
204     struct lint_vec_tbl_reg lint0_vec_tbl;
205     struct lint_vec_tbl_reg lint1_vec_tbl;
206     struct perf_ctr_loc_vec_tbl_reg perf_ctr_loc_vec_tbl;
207     struct therm_loc_vec_tbl_reg therm_loc_vec_tbl;
208     struct err_vec_tbl_reg err_vec_tbl;
209     struct err_status_reg err_status;
210     struct spurious_int_reg spurious_int;
211     struct int_cmd_reg int_cmd;
212     struct log_dst_reg log_dst;
213     struct dst_fmt_reg dst_fmt;
214     struct arb_prio_reg arb_prio;
215     struct task_prio_reg task_prio;
216     struct proc_prio_reg proc_prio;
217     struct ext_apic_feature_reg ext_apic_feature;
218     struct spec_eoi_reg spec_eoi;
219   
220
221     uint32_t tmr_cur_cnt;
222     uint32_t tmr_init_cnt;
223
224
225     struct local_vec_tbl_reg ext_intr_vec_tbl[4];
226
227     uint32_t rem_rd_data;
228
229
230     ipi_state_t ipi_state;
231
232     uint8_t int_req_reg[32];
233     uint8_t int_svc_reg[32];
234     uint8_t int_en_reg[32];
235     uint8_t trig_mode_reg[32];
236
237     struct guest_info * core;
238
239     void * controller_handle;
240
241     struct v3_timer * timer;
242
243
244     struct v3_queue irq_queue;
245
246     uint32_t eoi;
247
248
249 };
250
251
252
253
254 struct apic_dev_state {
255     int num_apics;
256   
257     v3_lock_t state_lock;
258
259     struct apic_state apics[0];
260 } __attribute__((packed));
261
262
263
264
265
266 static int apic_read(struct guest_info * core, addr_t guest_addr, void * dst, uint_t length, void * priv_data);
267 static int apic_write(struct guest_info * core, addr_t guest_addr, void * src, uint_t length, void * priv_data);
268
269 // No lcoking done
270 static void init_apic_state(struct apic_state * apic, uint32_t id) {
271     apic->base_addr = DEFAULT_BASE_ADDR;
272
273     if (id == 0) { 
274         // boot processor, enabled
275         apic->base_addr_msr.value = 0x0000000000000900LL;
276     } else {
277         // ap processor, enabled
278         apic->base_addr_msr.value = 0x0000000000000800LL;
279     }
280
281     // same base address regardless of ap or main
282     apic->base_addr_msr.value |= ((uint64_t)DEFAULT_BASE_ADDR); 
283
284     PrintDebug("apic %u: (init_apic_state): msr=0x%llx\n",id, apic->base_addr_msr.value);
285
286     PrintDebug("apic %u: (init_apic_state): Sizeof Interrupt Request Register %d, should be 32\n",
287                id, (uint_t)sizeof(apic->int_req_reg));
288
289     memset(apic->int_req_reg, 0, sizeof(apic->int_req_reg));
290     memset(apic->int_svc_reg, 0, sizeof(apic->int_svc_reg));
291     memset(apic->int_en_reg, 0xff, sizeof(apic->int_en_reg));
292     memset(apic->trig_mode_reg, 0, sizeof(apic->trig_mode_reg));
293
294     apic->eoi = 0x00000000;
295     apic->rem_rd_data = 0x00000000;
296     apic->tmr_init_cnt = 0x00000000;
297     apic->tmr_cur_cnt = 0x00000000;
298
299     apic->lapic_id.val = id;
300     
301     apic->ipi_state = INIT_ST;
302
303     // The P6 has 6 LVT entries, so we set the value to (6-1)...
304     apic->apic_ver.val = 0x80050010;
305
306     apic->task_prio.val = 0x00000000;
307     apic->arb_prio.val = 0x00000000;
308     apic->proc_prio.val = 0x00000000;
309     apic->log_dst.val = 0x00000000;
310     apic->dst_fmt.val = 0xffffffff;
311     apic->spurious_int.val = 0x000000ff;
312     apic->err_status.val = 0x00000000;
313     apic->int_cmd.val = 0x0000000000000000LL;
314     apic->tmr_vec_tbl.val = 0x00010000;
315     apic->therm_loc_vec_tbl.val = 0x00010000;
316     apic->perf_ctr_loc_vec_tbl.val = 0x00010000;
317     apic->lint0_vec_tbl.val = 0x00010000;
318     apic->lint1_vec_tbl.val = 0x00010000;
319     apic->err_vec_tbl.val = 0x00010000;
320     apic->tmr_div_cfg.val = 0x00000000;
321     //apic->ext_apic_feature.val = 0x00000007;
322     apic->ext_apic_feature.val = 0x00040007;
323     apic->ext_apic_ctrl.val = 0x00000000;
324     apic->spec_eoi.val = 0x00000000;
325
326
327     v3_init_queue(&(apic->irq_queue));
328
329
330 }
331
332
333
334
335
336 static int read_apic_msr(struct guest_info * core, uint_t msr, v3_msr_t * dst, void * priv_data) {
337     struct apic_dev_state * apic_dev = (struct apic_dev_state *)priv_data;
338     struct apic_state * apic = &(apic_dev->apics[core->vcpu_id]);
339
340     PrintDebug("apic %u: core %u: MSR read\n", apic->lapic_id.val, core->vcpu_id);
341
342     dst->value = apic->base_addr;
343
344     return 0;
345 }
346
347
348 static int write_apic_msr(struct guest_info * core, uint_t msr, v3_msr_t src, void * priv_data) {
349     struct apic_dev_state * apic_dev = (struct apic_dev_state *)priv_data;
350     struct apic_state * apic = &(apic_dev->apics[core->vcpu_id]);
351     struct v3_mem_region * old_reg = v3_get_mem_region(core->vm_info, core->vcpu_id, apic->base_addr);
352
353
354     PrintDebug("apic %u: core %u: MSR write\n", apic->lapic_id.val, core->vcpu_id);
355
356     if (old_reg == NULL) {
357         // uh oh...
358         PrintError("apic %u: core %u: APIC Base address region does not exit...\n",
359                    apic->lapic_id.val, core->vcpu_id);
360         return -1;
361     }
362     
363
364
365     v3_delete_mem_region(core->vm_info, old_reg);
366
367     apic->base_addr = src.value;
368
369     if (v3_hook_full_mem(core->vm_info, core->vcpu_id, apic->base_addr, 
370                          apic->base_addr + PAGE_SIZE_4KB, 
371                          apic_read, apic_write, apic_dev) == -1) {
372         PrintError("apic %u: core %u: Could not hook new APIC Base address\n",
373                    apic->lapic_id.val, core->vcpu_id);
374
375         return -1;
376     }
377
378
379     return 0;
380 }
381
382
383
384
385
386 // irq_num is the bit offset into a 256 bit buffer...
387 static int activate_apic_irq(struct apic_state * apic, uint32_t irq_num) {
388     int major_offset = (irq_num & ~0x00000007) >> 3;
389     int minor_offset = irq_num & 0x00000007;
390     uint8_t * req_location = apic->int_req_reg + major_offset;
391     uint8_t * en_location = apic->int_en_reg + major_offset;
392     uint8_t flag = 0x1 << minor_offset;
393
394
395     PrintDebug("apic %u: core %d: Raising APIC IRQ %d\n", apic->lapic_id.val, apic->core->vcpu_id, irq_num);
396
397     if (*req_location & flag) {
398         PrintDebug("Interrupt %d  coallescing\n", irq_num);
399         return 0;
400     }
401
402     if (*en_location & flag) {
403         *req_location |= flag;
404         return 1;
405     } else {
406         PrintDebug("apic %u: core %d: Interrupt  not enabled... %.2x\n", 
407                    apic->lapic_id.val, apic->core->vcpu_id, *en_location);
408     }
409
410     return 0;
411 }
412
413
414 static int add_apic_irq_entry(struct apic_state * apic, uint8_t irq_num) {
415
416     if (irq_num <= 15) {
417         PrintError("core %d: Attempting to raise an invalid interrupt: %d\n", 
418                     apic->core->vcpu_id, irq_num);
419         return -1;
420     }
421
422     v3_enqueue(&(apic->irq_queue), (addr_t)irq_num);
423
424     return 0;
425 }
426
427 static void drain_irq_entries(struct apic_state * apic) {
428     uint32_t irq = 0;
429
430     while ((irq = (uint32_t)v3_dequeue(&(apic->irq_queue))) != 0) {
431         activate_apic_irq(apic, irq);
432     }
433
434 }
435
436
437
438
439 static int get_highest_isr(struct apic_state * apic) {
440     int i = 0, j = 0;
441
442     // We iterate backwards to find the highest priority
443     for (i = 31; i >= 0; i--) {
444         uint8_t  * svc_major = apic->int_svc_reg + i;
445     
446         if ((*svc_major) & 0xff) {
447             for (j = 7; j >= 0; j--) {
448                 uint8_t flag = 0x1 << j;
449                 if ((*svc_major) & flag) {
450                     return ((i * 8) + j);
451                 }
452             }
453         }
454     }
455
456     return -1;
457 }
458  
459
460
461 static int get_highest_irr(struct apic_state * apic) {
462     int i = 0, j = 0;
463
464     // We iterate backwards to find the highest priority
465     for (i = 31; i >= 0; i--) {
466         uint8_t  * req_major = apic->int_req_reg + i;
467     
468         if ((*req_major) & 0xff) {
469             for (j = 7; j >= 0; j--) {
470                 uint8_t flag = 0x1 << j;
471                 if ((*req_major) & flag) {
472                     return ((i * 8) + j);
473                 }
474             }
475         }
476     }
477
478     return -1;
479 }
480  
481
482
483
484 static int apic_do_eoi(struct apic_state * apic) {
485     int isr_irq = get_highest_isr(apic);
486
487     if (isr_irq != -1) {
488         int major_offset = (isr_irq & ~0x00000007) >> 3;
489         int minor_offset = isr_irq & 0x00000007;
490         uint8_t flag = 0x1 << minor_offset;
491         uint8_t * svc_location = apic->int_svc_reg + major_offset;
492         
493         PrintDebug("apic %u: core ?: Received APIC EOI for IRQ %d\n", apic->lapic_id.val,isr_irq);
494         
495         *svc_location &= ~flag;
496
497 #ifdef V3_CONFIG_CRAY_XT
498         
499         if ((isr_irq == 238) || 
500             (isr_irq == 239)) {
501             PrintDebug("apic %u: core ?: Acking IRQ %d\n", apic->lapic_id.val,isr_irq);
502         }
503         
504         if (isr_irq == 238) {
505             V3_ACK_IRQ(238);
506         }
507 #endif
508     } else {
509         //PrintError("apic %u: core ?: Spurious EOI...\n",apic->lapic_id.val);
510     }
511         
512     return 0;
513 }
514  
515
516 static int activate_internal_irq(struct apic_state * apic, apic_irq_type_t int_type) {
517     uint32_t vec_num = 0;
518     uint32_t del_mode = 0;
519     int masked = 0;
520
521
522     switch (int_type) {
523         case APIC_TMR_INT:
524             vec_num = apic->tmr_vec_tbl.vec;
525             del_mode = APIC_FIXED_DELIVERY;
526             masked = apic->tmr_vec_tbl.mask;
527             break;
528         case APIC_THERM_INT:
529             vec_num = apic->therm_loc_vec_tbl.vec;
530             del_mode = apic->therm_loc_vec_tbl.msg_type;
531             masked = apic->therm_loc_vec_tbl.mask;
532             break;
533         case APIC_PERF_INT:
534             vec_num = apic->perf_ctr_loc_vec_tbl.vec;
535             del_mode = apic->perf_ctr_loc_vec_tbl.msg_type;
536             masked = apic->perf_ctr_loc_vec_tbl.mask;
537             break;
538         case APIC_LINT0_INT:
539             vec_num = apic->lint0_vec_tbl.vec;
540             del_mode = apic->lint0_vec_tbl.msg_type;
541             masked = apic->lint0_vec_tbl.mask;
542             break;
543         case APIC_LINT1_INT:
544             vec_num = apic->lint1_vec_tbl.vec;
545             del_mode = apic->lint1_vec_tbl.msg_type;
546             masked = apic->lint1_vec_tbl.mask;
547             break;
548         case APIC_ERR_INT:
549             vec_num = apic->err_vec_tbl.vec;
550             del_mode = APIC_FIXED_DELIVERY;
551             masked = apic->err_vec_tbl.mask;
552             break;
553         default:
554             PrintError("apic %u: core ?: Invalid APIC interrupt type\n", apic->lapic_id.val);
555             return -1;
556     }
557
558     // interrupt is masked, don't send
559     if (masked == 1) {
560         PrintDebug("apic %u: core ?: Inerrupt is masked\n", apic->lapic_id.val);
561         return 0;
562     }
563
564     if (del_mode == APIC_FIXED_DELIVERY) {
565         //PrintDebug("Activating internal APIC IRQ %d\n", vec_num);
566         return add_apic_irq_entry(apic, vec_num);
567     } else {
568         PrintError("apic %u: core ?: Unhandled Delivery Mode\n", apic->lapic_id.val);
569         return -1;
570     }
571 }
572
573
574
575 static inline int should_deliver_cluster_ipi(struct apic_dev_state * apic_dev,
576                                              struct guest_info * dst_core, 
577                                              struct apic_state * dst_apic, uint8_t mda) {
578
579     int ret = 0;
580
581
582     if  ( ((mda & 0xf0) == (dst_apic->log_dst.dst_log_id & 0xf0)) &&  /* (I am in the cluster and */
583           ((mda & 0x0f) & (dst_apic->log_dst.dst_log_id & 0x0f)) ) {  /*  I am in the set)        */
584         ret = 1;
585     } else {
586         ret = 0;
587     }
588
589
590     if (ret == 1) {
591         PrintDebug("apic %u core %u: accepting clustered IRQ (mda 0x%x == log_dst 0x%x)\n",
592                    dst_apic->lapic_id.val, dst_core->vcpu_id, mda, 
593                    dst_apic->log_dst.dst_log_id);
594     } else {
595         PrintDebug("apic %u core %u: rejecting clustered IRQ (mda 0x%x != log_dst 0x%x)\n",
596                    dst_apic->lapic_id.val, dst_core->vcpu_id, mda, 
597                    dst_apic->log_dst.dst_log_id);
598     }
599
600     return ret;
601
602 }
603
604 static inline int should_deliver_flat_ipi(struct apic_dev_state * apic_dev,
605                                           struct guest_info * dst_core,
606                                           struct apic_state * dst_apic, uint8_t mda) {
607
608     int ret = 0;
609
610
611     if ((dst_apic->log_dst.dst_log_id & mda) != 0) {  // I am in the set 
612         ret = 1;
613     } else {
614         ret = 0;
615     }
616
617
618     if (ret == 1) {
619         PrintDebug("apic %u core %u: accepting flat IRQ (mda 0x%x == log_dst 0x%x)\n",
620                    dst_apic->lapic_id.val, dst_core->vcpu_id, mda, 
621                    dst_apic->log_dst.dst_log_id);
622     } else {
623         PrintDebug("apic %u core %u: rejecting flat IRQ (mda 0x%x != log_dst 0x%x)\n",
624                    dst_apic->lapic_id.val, dst_core->vcpu_id, mda, 
625                    dst_apic->log_dst.dst_log_id);
626     }
627
628
629     return ret;
630 }
631
632
633
634 static int should_deliver_ipi(struct apic_dev_state * apic_dev, 
635                               struct guest_info * dst_core, 
636                               struct apic_state * dst_apic, uint8_t mda) {
637     addr_t flags = 0;
638     int ret = 0;
639
640     flags = v3_lock_irqsave(apic_dev->state_lock);
641
642     if (dst_apic->dst_fmt.model == 0xf) {
643
644         if (mda == 0xff) {
645             /* always deliver broadcast */
646             ret = 1;
647         } else {
648             ret = should_deliver_flat_ipi(apic_dev, dst_core, dst_apic, mda);
649         }
650     } else if (dst_apic->dst_fmt.model == 0x0) {
651
652         if (mda == 0xff) {
653             /*  always deliver broadcast */
654             ret = 1;
655         } else {
656             ret = should_deliver_cluster_ipi(apic_dev, dst_core, dst_apic, mda);
657         }
658
659     } else {
660         ret = -1;
661     }
662     
663     v3_unlock_irqrestore(apic_dev->state_lock, flags);
664
665
666     if (ret == -1) {
667         PrintError("apic %u core %u: invalid destination format register value 0x%x for logical mode delivery.\n", 
668                    dst_apic->lapic_id.val, dst_core->vcpu_id, dst_apic->dst_fmt.model);
669     }
670
671     return ret;
672 }
673
674
675
676
677 // Only the src_apic pointer is used
678 static int deliver_ipi(struct apic_state * src_apic, 
679                        struct apic_state * dst_apic, 
680                        uint32_t vector, uint8_t del_mode) {
681
682
683     struct guest_info * dst_core = dst_apic->core;
684
685
686     switch (del_mode) {
687
688         case APIC_FIXED_DELIVERY:  
689         case APIC_LOWEST_DELIVERY: {
690             // lowest priority - 
691             // caller needs to have decided which apic to deliver to!
692
693             PrintDebug("delivering IRQ %d to core %u\n", vector, dst_core->vcpu_id); 
694
695             add_apic_irq_entry(dst_apic, vector);
696             
697 #ifdef V3_CONFIG_MULTITHREAD_OS
698             if (dst_apic != src_apic) { 
699                 PrintDebug(" non-local core with new interrupt, forcing it to exit now\n"); 
700                 v3_interrupt_cpu(dst_core->vm_info, dst_core->pcpu_id, 0);
701             }
702 #endif
703
704
705             break;
706         }
707         case APIC_INIT_DELIVERY: { 
708
709             PrintDebug(" INIT delivery to core %u\n", dst_core->vcpu_id);
710
711             // TODO: any APIC reset on dest core (shouldn't be needed, but not sure...)
712
713             // Sanity check
714             if (dst_apic->ipi_state != INIT_ST) { 
715                 PrintError(" Warning: core %u is not in INIT state (mode = %d), ignored (assuming this is the deassert)\n",
716                            dst_core->vcpu_id, dst_apic->ipi_state);
717                 // Only a warning, since INIT INIT SIPI is common
718                 break;
719             }
720
721             // We transition the target core to SIPI state
722             dst_apic->ipi_state = SIPI;  // note: locking should not be needed here
723
724             // That should be it since the target core should be
725             // waiting in host on this transition
726             // either it's on another core or on a different preemptive thread
727             // in both cases, it will quickly notice this transition 
728             // in particular, we should not need to force an exit here
729
730             PrintDebug(" INIT delivery done\n");
731
732             break;                                                      
733         }
734         case APIC_SIPI_DELIVERY: { 
735
736             // Sanity check
737             if (dst_apic->ipi_state != SIPI) { 
738                 PrintError(" core %u is not in SIPI state (mode = %d), ignored!\n",
739                            dst_core->vcpu_id, dst_apic->ipi_state);
740                 break;
741             }
742
743             // Write the RIP, CS, and descriptor
744             // assume the rest is already good to go
745             //
746             // vector VV -> rip at 0
747             //              CS = VV00
748             //  This means we start executing at linear address VV000
749             //
750             // So the selector needs to be VV00
751             // and the base needs to be VV000
752             //
753             dst_core->rip = 0;
754             dst_core->segments.cs.selector = vector << 8;
755             dst_core->segments.cs.limit = 0xffff;
756             dst_core->segments.cs.base = vector << 12;
757
758             PrintDebug(" SIPI delivery (0x%x -> 0x%x:0x0) to core %u\n",
759                        vector, dst_core->segments.cs.selector, dst_core->vcpu_id);
760             // Maybe need to adjust the APIC?
761             
762             // We transition the target core to SIPI state
763             dst_core->core_run_state = CORE_RUNNING;  // note: locking should not be needed here
764             dst_apic->ipi_state = STARTED;
765             
766             // As with INIT, we should not need to do anything else
767             
768             PrintDebug(" SIPI delivery done\n");
769             
770             break;                                                      
771         }
772         case APIC_SMI_DELIVERY: 
773         case APIC_RES1_DELIVERY: // reserved                                            
774         case APIC_NMI_DELIVERY:
775         case APIC_EXTINT_DELIVERY: // ExtInt
776         default:
777             PrintError("IPI %d delivery is unsupported\n", del_mode); 
778             return -1;
779     }
780     
781     return 0;
782     
783 }
784
785 static struct apic_state * find_physical_apic(struct apic_dev_state * apic_dev, uint32_t dst_idx) {
786     struct apic_state * dst_apic = NULL;
787     addr_t flags;
788     int i;
789
790     flags = v3_lock_irqsave(apic_dev->state_lock);
791
792     if ( (dst_idx > 0) && (dst_idx < apic_dev->num_apics) ) { 
793         // see if it simply is the core id
794         if (apic_dev->apics[dst_idx].lapic_id.val == dst_idx) { 
795              dst_apic = &(apic_dev->apics[dst_idx]);
796         }
797     }
798
799     for (i = 0; i < apic_dev->num_apics; i++) { 
800         if (apic_dev->apics[i].lapic_id.val == dst_idx) { 
801             dst_apic =  &(apic_dev->apics[i]);
802         }
803     }
804
805     v3_unlock_irqrestore(apic_dev->state_lock, flags);
806
807     return dst_apic;
808
809 }
810
811
812 static int route_ipi(struct apic_dev_state * apic_dev,
813                      struct apic_state * src_apic, 
814                      struct int_cmd_reg * icr) {
815     struct apic_state * dest_apic = NULL;
816
817
818     PrintDebug("apic: IPI %s %u from apic %p to %s %s %u (icr=0x%llx)\n",
819                deliverymode_str[icr->del_mode], 
820                icr->vec, 
821                src_apic,               
822                (icr->dst_mode == 0) ? "(physical)" : "(logical)", 
823                shorthand_str[icr->dst_shorthand], 
824                icr->dst,
825                icr->val);
826
827
828     switch (icr->dst_shorthand) {
829
830         case APIC_SHORTHAND_NONE:  // no shorthand
831             if (icr->dst_mode == APIC_DEST_PHYSICAL) { 
832
833                 dest_apic = find_physical_apic(apic_dev, icr->dst);
834                 
835                 if (dest_apic == NULL) { 
836                     PrintError("apic: Attempted send to unregistered apic id=%u\n", icr->dst);
837                     return -1;
838                 }
839
840                 if (deliver_ipi(src_apic, dest_apic, 
841                                 icr->vec, icr->del_mode) == -1) {
842                     PrintError("apic: Could not deliver IPI\n");
843                     return -1;
844                 }
845
846
847                 PrintDebug("apic: done\n");
848
849             } else if (icr->dst_mode == APIC_DEST_LOGICAL) {
850                 
851                 if (icr->del_mode != APIC_LOWEST_DELIVERY) { 
852                     int i;
853                     uint8_t mda = icr->dst;
854
855                     // logical, but not lowest priority
856                     // we immediately trigger
857                     // fixed, smi, reserved, nmi, init, sipi, etc
858
859                     
860                     for (i = 0; i < apic_dev->num_apics; i++) { 
861                         int del_flag = 0;
862                         
863                         dest_apic = &(apic_dev->apics[i]);
864                         
865                         del_flag = should_deliver_ipi(apic_dev, dest_apic->core, dest_apic, mda);
866                         
867                         if (del_flag == -1) {
868
869                             PrintError("apic: Error checking delivery mode\n");
870                             return -1;
871                         } else if (del_flag == 1) {
872
873                             if (deliver_ipi(src_apic, dest_apic, 
874                                             icr->vec, icr->del_mode) == -1) {
875                                 PrintError("apic: Error: Could not deliver IPI\n");
876                                 return -1;
877                             }
878                         }
879                     }
880                 } else {  // APIC_LOWEST_DELIVERY
881                     struct apic_state * cur_best_apic = NULL;
882                     uint8_t mda = icr->dst;
883                     int i;
884
885                     // logical, lowest priority
886
887                     for (i = 0; i < apic_dev->num_apics; i++) { 
888                         int del_flag = 0;
889
890                         dest_apic = &(apic_dev->apics[i]);
891                         
892                         del_flag = should_deliver_ipi(apic_dev, dest_apic->core, dest_apic, mda);
893                         
894                         if (del_flag == -1) {
895                             PrintError("apic: Error checking delivery mode\n");
896
897                             return -1;
898                         } else if (del_flag == 1) {
899                             // update priority for lowest priority scan
900                             addr_t flags = 0;
901
902                             flags = v3_lock_irqsave(apic_dev->state_lock);
903
904                             if (cur_best_apic == 0) {
905                                 cur_best_apic = dest_apic;  
906                             } else if (dest_apic->task_prio.val < cur_best_apic->task_prio.val) {
907                                 cur_best_apic = dest_apic;
908                             } 
909
910                             v3_unlock_irqrestore(apic_dev->state_lock, flags);
911
912                         }                       
913                     }
914
915                     // now we will deliver to the best one if it exists
916                     if (!cur_best_apic) { 
917                         PrintDebug("apic: lowest priority deliver, but no destinations!\n");
918                     } else {
919                         if (deliver_ipi(src_apic, cur_best_apic, 
920                                         icr->vec, icr->del_mode) == -1) {
921                             PrintError("apic: Error: Could not deliver IPI\n");
922                             return -1;
923                         }
924                         //V3_Print("apic: logical, lowest priority delivery to apic %u\n",cur_best_apic->lapic_id.val);
925                     }
926                 }
927             }
928
929             break;
930             
931         case APIC_SHORTHAND_SELF:  // self
932
933             if (src_apic == NULL) {    /* this is not an apic, but it's trying to send to itself??? */
934                 PrintError("apic: Sending IPI to self from generic IPI sender\n");
935                 break;
936             }
937
938
939
940             if (icr->dst_mode == APIC_DEST_PHYSICAL)  {  /* physical delivery */
941                 if (deliver_ipi(src_apic, src_apic, icr->vec, icr->del_mode) == -1) {
942                     PrintError("apic: Could not deliver IPI to self (physical)\n");
943                     return -1;
944                 }
945             } else if (icr->dst_mode == APIC_DEST_LOGICAL) {  /* logical delivery */
946                 PrintError("apic: use of logical delivery in self (untested)\n");
947
948                 if (deliver_ipi(src_apic, src_apic, icr->vec, icr->del_mode) == -1) {
949                     PrintError("apic: Could not deliver IPI to self (logical)\n");
950                     return -1;
951                 }
952             }
953
954             break;
955             
956         case APIC_SHORTHAND_ALL: 
957         case APIC_SHORTHAND_ALL_BUT_ME: { /* all and all-but-me */
958             /* assuming that logical verus physical doesn't matter
959                although it is odd that both are used */
960             int i;
961
962             for (i = 0; i < apic_dev->num_apics; i++) { 
963                 dest_apic = &(apic_dev->apics[i]);
964                 
965                 if ((dest_apic != src_apic) || (icr->dst_shorthand == APIC_SHORTHAND_ALL)) { 
966                     if (deliver_ipi(src_apic, dest_apic, icr->vec, icr->del_mode) == -1) {
967                         PrintError("apic: Error: Could not deliver IPI\n");
968                         return -1;
969                     }
970                 }
971             }
972
973             break;
974         }
975         default:
976             PrintError("apic: Error routing IPI, invalid Mode (%d)\n", icr->dst_shorthand);
977             return -1;
978     }
979  
980     return 0;
981 }
982
983
984 // External function, expected to acquire lock on apic
985 static int apic_read(struct guest_info * core, addr_t guest_addr, void * dst, uint_t length, void * priv_data) {
986     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(priv_data);
987     struct apic_state * apic = &(apic_dev->apics[core->vcpu_id]);
988     addr_t reg_addr  = guest_addr - apic->base_addr;
989     struct apic_msr * msr = (struct apic_msr *)&(apic->base_addr_msr.value);
990     uint32_t val = 0;
991
992
993     PrintDebug("apic %u: core %u: at %p: Read apic address space (%p)\n",
994                apic->lapic_id.val, core->vcpu_id, apic, (void *)guest_addr);
995
996     if (msr->apic_enable == 0) {
997         PrintError("apic %u: core %u: Read from APIC address space with disabled APIC, apic msr=0x%llx\n",
998                    apic->lapic_id.val, core->vcpu_id, apic->base_addr_msr.value);
999         return -1;
1000     }
1001
1002
1003     /* Because "May not be supported" doesn't matter to Linux developers... */
1004     /*   if (length != 4) { */
1005     /*     PrintError("Invalid apic read length (%d)\n", length); */
1006     /*     return -1; */
1007     /*   } */
1008
1009     switch (reg_addr & ~0x3) {
1010         case EOI_OFFSET:
1011             // Well, only an idiot would read from a architectural write only register
1012             // Oh, Hello Linux.
1013             //    PrintError("Attempting to read from write only register\n");
1014             //    return -1;
1015             break;
1016
1017             // data registers
1018         case APIC_ID_OFFSET:
1019             val = apic->lapic_id.val;
1020             break;
1021         case APIC_VERSION_OFFSET:
1022             val = apic->apic_ver.val;
1023             break;
1024         case TPR_OFFSET:
1025             val = apic->task_prio.val;
1026             break;
1027         case APR_OFFSET:
1028             val = apic->arb_prio.val;
1029             break;
1030         case PPR_OFFSET:
1031             val = apic->proc_prio.val;
1032             break;
1033         case REMOTE_READ_OFFSET:
1034             val = apic->rem_rd_data;
1035             break;
1036         case LDR_OFFSET:
1037             val = apic->log_dst.val;
1038             break;
1039         case DFR_OFFSET:
1040             val = apic->dst_fmt.val;
1041             break;
1042         case SPURIOUS_INT_VEC_OFFSET:
1043             val = apic->spurious_int.val;
1044             break;
1045         case ESR_OFFSET:
1046             val = apic->err_status.val;
1047             break;
1048         case TMR_LOC_VEC_TBL_OFFSET:
1049             val = apic->tmr_vec_tbl.val;
1050             break;
1051         case LINT0_VEC_TBL_OFFSET:
1052             val = apic->lint0_vec_tbl.val;
1053             break;
1054         case LINT1_VEC_TBL_OFFSET:
1055             val = apic->lint1_vec_tbl.val;
1056             break;
1057         case ERR_VEC_TBL_OFFSET:
1058             val = apic->err_vec_tbl.val;
1059             break;
1060         case TMR_INIT_CNT_OFFSET:
1061             val = apic->tmr_init_cnt;
1062             break;
1063         case TMR_DIV_CFG_OFFSET:
1064             val = apic->tmr_div_cfg.val;
1065             break;
1066
1067         case IER_OFFSET0:
1068             val = *(uint32_t *)(apic->int_en_reg);
1069             break;
1070         case IER_OFFSET1:
1071             val = *(uint32_t *)(apic->int_en_reg + 4);
1072             break;
1073         case IER_OFFSET2:
1074             val = *(uint32_t *)(apic->int_en_reg + 8);
1075             break;
1076         case IER_OFFSET3:
1077             val = *(uint32_t *)(apic->int_en_reg + 12);
1078             break;
1079         case IER_OFFSET4:
1080             val = *(uint32_t *)(apic->int_en_reg + 16);
1081             break;
1082         case IER_OFFSET5:
1083             val = *(uint32_t *)(apic->int_en_reg + 20);
1084             break;
1085         case IER_OFFSET6:
1086             val = *(uint32_t *)(apic->int_en_reg + 24);
1087             break;
1088         case IER_OFFSET7:
1089             val = *(uint32_t *)(apic->int_en_reg + 28);
1090             break;
1091
1092         case ISR_OFFSET0:
1093             val = *(uint32_t *)(apic->int_svc_reg);
1094             break;
1095         case ISR_OFFSET1:
1096             val = *(uint32_t *)(apic->int_svc_reg + 4);
1097             break;
1098         case ISR_OFFSET2:
1099             val = *(uint32_t *)(apic->int_svc_reg + 8);
1100             break;
1101         case ISR_OFFSET3:
1102             val = *(uint32_t *)(apic->int_svc_reg + 12);
1103             break;
1104         case ISR_OFFSET4:
1105             val = *(uint32_t *)(apic->int_svc_reg + 16);
1106             break;
1107         case ISR_OFFSET5:
1108             val = *(uint32_t *)(apic->int_svc_reg + 20);
1109             break;
1110         case ISR_OFFSET6:
1111             val = *(uint32_t *)(apic->int_svc_reg + 24);
1112             break;
1113         case ISR_OFFSET7:
1114             val = *(uint32_t *)(apic->int_svc_reg + 28);
1115             break;
1116    
1117         case TRIG_OFFSET0:
1118             val = *(uint32_t *)(apic->trig_mode_reg);
1119             break;
1120         case TRIG_OFFSET1:
1121             val = *(uint32_t *)(apic->trig_mode_reg + 4);
1122             break;
1123         case TRIG_OFFSET2:
1124             val = *(uint32_t *)(apic->trig_mode_reg + 8);
1125             break;
1126         case TRIG_OFFSET3:
1127             val = *(uint32_t *)(apic->trig_mode_reg + 12);
1128             break;
1129         case TRIG_OFFSET4:
1130             val = *(uint32_t *)(apic->trig_mode_reg + 16);
1131             break;
1132         case TRIG_OFFSET5:
1133             val = *(uint32_t *)(apic->trig_mode_reg + 20);
1134             break;
1135         case TRIG_OFFSET6:
1136             val = *(uint32_t *)(apic->trig_mode_reg + 24);
1137             break;
1138         case TRIG_OFFSET7:
1139             val = *(uint32_t *)(apic->trig_mode_reg + 28);
1140             break;
1141
1142         case IRR_OFFSET0:
1143             val = *(uint32_t *)(apic->int_req_reg);
1144             break;
1145         case IRR_OFFSET1:
1146             val = *(uint32_t *)(apic->int_req_reg + 4);
1147             break;
1148         case IRR_OFFSET2:
1149             val = *(uint32_t *)(apic->int_req_reg + 8);
1150             break;
1151         case IRR_OFFSET3:
1152             val = *(uint32_t *)(apic->int_req_reg + 12);
1153             break;
1154         case IRR_OFFSET4:
1155             val = *(uint32_t *)(apic->int_req_reg + 16);
1156             break;
1157         case IRR_OFFSET5:
1158             val = *(uint32_t *)(apic->int_req_reg + 20);
1159             break;
1160         case IRR_OFFSET6:
1161             val = *(uint32_t *)(apic->int_req_reg + 24);
1162             break;
1163         case IRR_OFFSET7:
1164             val = *(uint32_t *)(apic->int_req_reg + 28);
1165             break;
1166         case TMR_CUR_CNT_OFFSET:
1167             val = apic->tmr_cur_cnt;
1168             break;
1169
1170             // We are not going to implement these....
1171         case THERM_LOC_VEC_TBL_OFFSET:
1172             val = apic->therm_loc_vec_tbl.val;
1173             break;
1174         case PERF_CTR_LOC_VEC_TBL_OFFSET:
1175             val = apic->perf_ctr_loc_vec_tbl.val;
1176             break;
1177
1178  
1179
1180             // handled registers
1181         case INT_CMD_LO_OFFSET:    
1182             val = apic->int_cmd.lo;
1183             break;
1184         case INT_CMD_HI_OFFSET:
1185             val = apic->int_cmd.hi;
1186             break;
1187
1188             // handle current timer count
1189
1190             // Unhandled Registers
1191         case EXT_INT_LOC_VEC_TBL_OFFSET0:
1192             val = apic->ext_intr_vec_tbl[0].val;
1193             break;
1194         case EXT_INT_LOC_VEC_TBL_OFFSET1:
1195             val = apic->ext_intr_vec_tbl[1].val;
1196             break;
1197         case EXT_INT_LOC_VEC_TBL_OFFSET2:
1198             val = apic->ext_intr_vec_tbl[2].val;
1199             break;
1200         case EXT_INT_LOC_VEC_TBL_OFFSET3:
1201             val = apic->ext_intr_vec_tbl[3].val;
1202             break;
1203     
1204
1205         case EXT_APIC_FEATURE_OFFSET:
1206         case EXT_APIC_CMD_OFFSET:
1207         case SEOI_OFFSET:
1208
1209         default:
1210             PrintError("apic %u: core %u: Read from Unhandled APIC Register: %x (getting zero)\n", 
1211                        apic->lapic_id.val, core->vcpu_id, (uint32_t)reg_addr);
1212             return -1;
1213     }
1214
1215
1216     if (length == 1) {
1217         uint_t byte_addr = reg_addr & 0x3;
1218         uint8_t * val_ptr = (uint8_t *)dst;
1219     
1220         *val_ptr = *(((uint8_t *)&val) + byte_addr);
1221
1222     } else if ((length == 2) && 
1223                ((reg_addr & 0x3) == 0x3)) {
1224         uint_t byte_addr = reg_addr & 0x3;
1225         uint16_t * val_ptr = (uint16_t *)dst;
1226         *val_ptr = *(((uint16_t *)&val) + byte_addr);
1227
1228     } else if (length == 4) {
1229         uint32_t * val_ptr = (uint32_t *)dst;
1230         *val_ptr = val;
1231
1232     } else {
1233         PrintError("apic %u: core %u: Invalid apic read length (%d)\n", 
1234                    apic->lapic_id.val, core->vcpu_id, length);
1235         return -1;
1236     }
1237
1238     PrintDebug("apic %u: core %u: Read finished (val=%x)\n", 
1239                apic->lapic_id.val, core->vcpu_id, *(uint32_t *)dst);
1240
1241     return length;
1242 }
1243
1244
1245 /**
1246  *
1247  */
1248 static int apic_write(struct guest_info * core, addr_t guest_addr, void * src, uint_t length, void * priv_data) {
1249     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(priv_data);
1250     struct apic_state * apic = &(apic_dev->apics[core->vcpu_id]); 
1251     addr_t reg_addr  = guest_addr - apic->base_addr;
1252     struct apic_msr * msr = (struct apic_msr *)&(apic->base_addr_msr.value);
1253     uint32_t op_val = *(uint32_t *)src;
1254     addr_t flags = 0;
1255
1256     PrintDebug("apic %u: core %u: at %p and priv_data is at %p\n",
1257                apic->lapic_id.val, core->vcpu_id, apic, priv_data);
1258
1259     PrintDebug("apic %u: core %u: write to address space (%p) (val=%x)\n", 
1260                apic->lapic_id.val, core->vcpu_id, (void *)guest_addr, *(uint32_t *)src);
1261
1262     if (msr->apic_enable == 0) {
1263         PrintError("apic %u: core %u: Write to APIC address space with disabled APIC, apic msr=0x%llx\n",
1264                    apic->lapic_id.val, core->vcpu_id, apic->base_addr_msr.value);
1265         return -1;
1266     }
1267
1268
1269     if (length != 4) {
1270         PrintError("apic %u: core %u: Invalid apic write length (%d)\n", 
1271                    apic->lapic_id.val, length, core->vcpu_id);
1272         return -1;
1273     }
1274
1275     switch (reg_addr) {
1276         case REMOTE_READ_OFFSET:
1277         case APIC_VERSION_OFFSET:
1278         case APR_OFFSET:
1279         case IRR_OFFSET0:
1280         case IRR_OFFSET1:
1281         case IRR_OFFSET2:
1282         case IRR_OFFSET3:
1283         case IRR_OFFSET4:
1284         case IRR_OFFSET5:
1285         case IRR_OFFSET6:
1286         case IRR_OFFSET7:
1287         case ISR_OFFSET0:
1288         case ISR_OFFSET1:
1289         case ISR_OFFSET2:
1290         case ISR_OFFSET3:
1291         case ISR_OFFSET4:
1292         case ISR_OFFSET5:
1293         case ISR_OFFSET6:
1294         case ISR_OFFSET7:
1295         case TRIG_OFFSET0:
1296         case TRIG_OFFSET1:
1297         case TRIG_OFFSET2:
1298         case TRIG_OFFSET3:
1299         case TRIG_OFFSET4:
1300         case TRIG_OFFSET5:
1301         case TRIG_OFFSET6:
1302         case TRIG_OFFSET7:
1303         case PPR_OFFSET:
1304         case EXT_APIC_FEATURE_OFFSET:
1305
1306             PrintError("apic %u: core %u: Attempting to write to read only register %p (error)\n", 
1307                        apic->lapic_id.val, core->vcpu_id, (void *)reg_addr);
1308
1309             break;
1310
1311             // Data registers
1312         case APIC_ID_OFFSET:
1313             //V3_Print("apic %u: core %u: my id is being changed to %u\n", 
1314             //       apic->lapic_id.val, core->vcpu_id, op_val);
1315
1316             apic->lapic_id.val = op_val;
1317             break;
1318         case TPR_OFFSET:
1319             apic->task_prio.val = op_val;
1320             break;
1321         case LDR_OFFSET:
1322             PrintDebug("apic %u: core %u: setting log_dst.val to 0x%x\n",
1323                        apic->lapic_id.val, core->vcpu_id, op_val);
1324             flags = v3_lock_irqsave(apic_dev->state_lock);
1325             apic->log_dst.val = op_val;
1326             v3_unlock_irqrestore(apic_dev->state_lock, flags);
1327             break;
1328         case DFR_OFFSET:
1329             flags = v3_lock_irqsave(apic_dev->state_lock);
1330             apic->dst_fmt.val = op_val;
1331             v3_unlock_irqrestore(apic_dev->state_lock, flags);
1332             break;
1333         case SPURIOUS_INT_VEC_OFFSET:
1334             apic->spurious_int.val = op_val;
1335             break;
1336         case ESR_OFFSET:
1337             apic->err_status.val = op_val;
1338             break;
1339         case TMR_LOC_VEC_TBL_OFFSET:
1340             apic->tmr_vec_tbl.val = op_val;
1341             break;
1342         case THERM_LOC_VEC_TBL_OFFSET:
1343             apic->therm_loc_vec_tbl.val = op_val;
1344             break;
1345         case PERF_CTR_LOC_VEC_TBL_OFFSET:
1346             apic->perf_ctr_loc_vec_tbl.val = op_val;
1347             break;
1348         case LINT0_VEC_TBL_OFFSET:
1349             apic->lint0_vec_tbl.val = op_val;
1350             break;
1351         case LINT1_VEC_TBL_OFFSET:
1352             apic->lint1_vec_tbl.val = op_val;
1353             break;
1354         case ERR_VEC_TBL_OFFSET:
1355             apic->err_vec_tbl.val = op_val;
1356             break;
1357         case TMR_INIT_CNT_OFFSET:
1358             apic->tmr_init_cnt = op_val;
1359             apic->tmr_cur_cnt = op_val;
1360             break;
1361         case TMR_CUR_CNT_OFFSET:
1362             apic->tmr_cur_cnt = op_val;
1363             break;
1364         case TMR_DIV_CFG_OFFSET:
1365             apic->tmr_div_cfg.val = op_val;
1366             break;
1367
1368
1369             // Enable mask (256 bits)
1370         case IER_OFFSET0:
1371             *(uint32_t *)(apic->int_en_reg) = op_val;
1372             break;
1373         case IER_OFFSET1:
1374             *(uint32_t *)(apic->int_en_reg + 4) = op_val;
1375             break;
1376         case IER_OFFSET2:
1377             *(uint32_t *)(apic->int_en_reg + 8) = op_val;
1378             break;
1379         case IER_OFFSET3:
1380             *(uint32_t *)(apic->int_en_reg + 12) = op_val;
1381             break;
1382         case IER_OFFSET4:
1383             *(uint32_t *)(apic->int_en_reg + 16) = op_val;
1384             break;
1385         case IER_OFFSET5:
1386             *(uint32_t *)(apic->int_en_reg + 20) = op_val;
1387             break;
1388         case IER_OFFSET6:
1389             *(uint32_t *)(apic->int_en_reg + 24) = op_val;
1390             break;
1391         case IER_OFFSET7:
1392             *(uint32_t *)(apic->int_en_reg + 28) = op_val;
1393             break;
1394
1395         case EXT_INT_LOC_VEC_TBL_OFFSET0:
1396             apic->ext_intr_vec_tbl[0].val = op_val;
1397             break;
1398         case EXT_INT_LOC_VEC_TBL_OFFSET1:
1399             apic->ext_intr_vec_tbl[1].val = op_val;
1400             break;
1401         case EXT_INT_LOC_VEC_TBL_OFFSET2:
1402             apic->ext_intr_vec_tbl[2].val = op_val;
1403             break;
1404         case EXT_INT_LOC_VEC_TBL_OFFSET3:
1405             apic->ext_intr_vec_tbl[3].val = op_val;
1406             break;
1407
1408
1409             // Action Registers
1410         case EOI_OFFSET:
1411             // do eoi 
1412             apic_do_eoi(apic);
1413             break;
1414
1415         case INT_CMD_LO_OFFSET: {
1416             // execute command 
1417
1418             struct int_cmd_reg tmp_icr;
1419
1420             apic->int_cmd.lo = op_val;
1421
1422             tmp_icr = apic->int_cmd;
1423
1424             //      V3_Print("apic %u: core %u: sending cmd 0x%llx to apic %u\n", 
1425             //       apic->lapic_id.val, core->vcpu_id,
1426             //       apic->int_cmd.val, apic->int_cmd.dst);
1427
1428             if (route_ipi(apic_dev, apic, &tmp_icr) == -1) { 
1429                 PrintError("IPI Routing failure\n");
1430                 return -1;
1431             }
1432
1433             break;
1434         }
1435         case INT_CMD_HI_OFFSET: {
1436             apic->int_cmd.hi = op_val;
1437             V3_Print("apic %u: core %u: writing command high=0x%x\n", apic->lapic_id.val, core->vcpu_id,apic->int_cmd.hi);
1438
1439             break;
1440         }
1441         // Unhandled Registers
1442         case EXT_APIC_CMD_OFFSET:
1443         case SEOI_OFFSET:
1444         default:
1445             PrintError("apic %u: core %u: Write to Unhandled APIC Register: %x (ignored)\n", 
1446                        apic->lapic_id.val, core->vcpu_id, (uint32_t)reg_addr);
1447
1448             return -1;
1449     }
1450
1451     PrintDebug("apic %u: core %u: Write finished\n", apic->lapic_id.val, core->vcpu_id);
1452
1453     return length;
1454
1455 }
1456
1457
1458
1459 /* Interrupt Controller Functions */
1460
1461
1462 static int apic_intr_pending(struct guest_info * core, void * private_data) {
1463     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(private_data);
1464     struct apic_state * apic = &(apic_dev->apics[core->vcpu_id]); 
1465     int req_irq = 0;    
1466     int svc_irq = 0;
1467
1468     // Activate all queued IRQ entries
1469     drain_irq_entries(apic);
1470
1471     // Check for newly activated entries
1472     req_irq = get_highest_irr(apic);
1473     svc_irq = get_highest_isr(apic);
1474
1475     //    PrintDebug("apic %u: core %u: req_irq=%d, svc_irq=%d\n",apic->lapic_id.val,info->vcpu_id,req_irq,svc_irq);
1476
1477     if ((req_irq >= 0) && 
1478         (req_irq > svc_irq)) {
1479         return 1;
1480     }
1481
1482     return 0;
1483 }
1484
1485
1486
1487 static int apic_get_intr_number(struct guest_info * core, void * private_data) {
1488     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(private_data);
1489     struct apic_state * apic = &(apic_dev->apics[core->vcpu_id]); 
1490     int req_irq = get_highest_irr(apic);
1491     int svc_irq = get_highest_isr(apic);
1492
1493     if (svc_irq == -1) {
1494         return req_irq;
1495     } else if (svc_irq < req_irq) {
1496         return req_irq;
1497     }
1498
1499     return -1;
1500 }
1501
1502
1503
1504 int v3_apic_send_ipi(struct v3_vm_info * vm, struct v3_gen_ipi * ipi, void * dev_data) {
1505     struct apic_dev_state * apic_dev = (struct apic_dev_state *)
1506         (((struct vm_device *)dev_data)->private_data);
1507     struct int_cmd_reg tmp_icr;
1508
1509     // zero out all the fields
1510     tmp_icr.val = 0;
1511
1512     tmp_icr.vec = ipi->vector;
1513     tmp_icr.del_mode = ipi->mode;
1514     tmp_icr.dst_mode = ipi->logical;
1515     tmp_icr.trig_mode = ipi->trigger_mode;
1516     tmp_icr.dst_shorthand = ipi->dst_shorthand;
1517     tmp_icr.dst = ipi->dst;
1518
1519
1520     return route_ipi(apic_dev, NULL, &tmp_icr);
1521 }
1522
1523
1524 int v3_apic_raise_intr(struct v3_vm_info * vm, uint32_t irq, uint32_t dst, void * dev_data) {
1525     struct apic_dev_state * apic_dev = (struct apic_dev_state *)
1526         (((struct vm_device*)dev_data)->private_data);
1527     struct apic_state * apic = &(apic_dev->apics[dst]); 
1528
1529     PrintDebug("apic %u core ?: raising interrupt IRQ %u (dst = %u).\n", apic->lapic_id.val, irq, dst); 
1530
1531     add_apic_irq_entry(apic, irq);
1532
1533 #ifdef V3_CONFIG_MULTITHREAD_OS   
1534     if ((V3_Get_CPU() != dst)) {
1535         v3_interrupt_cpu(vm, dst, 0);
1536     }
1537 #endif
1538
1539     return 0;
1540 }
1541
1542
1543
1544 static int apic_begin_irq(struct guest_info * core, void * private_data, int irq) {
1545     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(private_data);
1546     struct apic_state * apic = &(apic_dev->apics[core->vcpu_id]); 
1547     int major_offset = (irq & ~0x00000007) >> 3;
1548     int minor_offset = irq & 0x00000007;
1549     uint8_t *req_location = apic->int_req_reg + major_offset;
1550     uint8_t *svc_location = apic->int_svc_reg + major_offset;
1551     uint8_t flag = 0x01 << minor_offset;
1552
1553     if (*req_location & flag) {
1554         // we will only pay attention to a begin irq if we
1555         // know that we initiated it!
1556         *svc_location |= flag;
1557         *req_location &= ~flag;
1558     } else {
1559         // do nothing... 
1560         //PrintDebug("apic %u: core %u: begin irq for %d ignored since I don't own it\n",
1561         //         apic->lapic_id.val, core->vcpu_id, irq);
1562     }
1563
1564     return 0;
1565 }
1566
1567
1568
1569
1570
1571 /* Timer Functions */
1572
1573 static void apic_update_time(struct guest_info * core, 
1574                              uint64_t cpu_cycles, uint64_t cpu_freq, 
1575                              void * priv_data) {
1576     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(priv_data);
1577     struct apic_state * apic = &(apic_dev->apics[core->vcpu_id]); 
1578
1579     // The 32 bit GCC runtime is a pile of shit
1580 #ifdef __V3_64BIT__
1581     uint64_t tmr_ticks = 0;
1582 #else 
1583     uint32_t tmr_ticks = 0;
1584 #endif
1585
1586     uint8_t tmr_div = *(uint8_t *)&(apic->tmr_div_cfg.val);
1587     uint_t shift_num = 0;
1588
1589
1590     // Check whether this is true:
1591     //   -> If the Init count is zero then the timer is disabled
1592     //      and doesn't just blitz interrupts to the CPU
1593     if ((apic->tmr_init_cnt == 0) || 
1594         ( (apic->tmr_vec_tbl.tmr_mode == APIC_TMR_ONESHOT) &&
1595           (apic->tmr_cur_cnt == 0))) {
1596         //PrintDebug("apic %u: core %u: APIC timer not yet initialized\n",apic->lapic_id.val,info->vcpu_id);
1597         return;
1598     }
1599
1600
1601     switch (tmr_div) {
1602         case APIC_TMR_DIV1:
1603             shift_num = 0;
1604             break;
1605         case APIC_TMR_DIV2:
1606             shift_num = 1;
1607             break;
1608         case APIC_TMR_DIV4:
1609             shift_num = 2;
1610             break;
1611         case APIC_TMR_DIV8:
1612             shift_num = 3;
1613             break;
1614         case APIC_TMR_DIV16:
1615             shift_num = 4;
1616             break;
1617         case APIC_TMR_DIV32:
1618             shift_num = 5;
1619             break;
1620         case APIC_TMR_DIV64:
1621             shift_num = 6;
1622             break;
1623         case APIC_TMR_DIV128:
1624             shift_num = 7;
1625             break;
1626         default:
1627             PrintError("apic %u: core %u: Invalid Timer Divider configuration\n",
1628                        apic->lapic_id.val, core->vcpu_id);
1629             return;
1630     }
1631
1632     tmr_ticks = cpu_cycles >> shift_num;
1633     //    PrintDebug("Timer Ticks: %p\n", (void *)tmr_ticks);
1634
1635     if (tmr_ticks < apic->tmr_cur_cnt) {
1636         apic->tmr_cur_cnt -= tmr_ticks;
1637     } else {
1638         tmr_ticks -= apic->tmr_cur_cnt;
1639         apic->tmr_cur_cnt = 0;
1640
1641         // raise irq
1642         PrintDebug("apic %u: core %u: Raising APIC Timer interrupt (periodic=%d) (icnt=%d) (div=%d)\n",
1643                    apic->lapic_id.val, core->vcpu_id,
1644                    apic->tmr_vec_tbl.tmr_mode, apic->tmr_init_cnt, shift_num);
1645
1646         if (apic_intr_pending(core, priv_data)) {
1647             PrintDebug("apic %u: core %u: Overriding pending IRQ %d\n", 
1648                        apic->lapic_id.val, core->vcpu_id, 
1649                        apic_get_intr_number(core, priv_data));
1650         }
1651
1652         if (activate_internal_irq(apic, APIC_TMR_INT) == -1) {
1653             PrintError("apic %u: core %u: Could not raise Timer interrupt\n",
1654                        apic->lapic_id.val, core->vcpu_id);
1655         }
1656     
1657         if (apic->tmr_vec_tbl.tmr_mode == APIC_TMR_PERIODIC) {
1658             tmr_ticks = tmr_ticks % apic->tmr_init_cnt;
1659             apic->tmr_cur_cnt = apic->tmr_init_cnt - tmr_ticks;
1660         }
1661     }
1662
1663     return;
1664 }
1665
1666
1667 static struct intr_ctrl_ops intr_ops = {
1668     .intr_pending = apic_intr_pending,
1669     .get_intr_number = apic_get_intr_number,
1670     .begin_irq = apic_begin_irq,
1671 };
1672
1673
1674 static struct v3_timer_ops timer_ops = {
1675     .update_timer = apic_update_time,
1676 };
1677
1678
1679
1680
1681 static int apic_free(struct apic_dev_state * apic_dev) {
1682     int i = 0;
1683     struct v3_vm_info * vm = NULL;
1684
1685     for (i = 0; i < apic_dev->num_apics; i++) {
1686         struct apic_state * apic = &(apic_dev->apics[i]);
1687         struct guest_info * core = apic->core;
1688         
1689         vm = core->vm_info;
1690
1691         v3_remove_intr_controller(core, apic->controller_handle);
1692
1693         if (apic->timer) {
1694             v3_remove_timer(core, apic->timer);
1695         }
1696
1697         // unhook memory
1698
1699     }
1700
1701     v3_unhook_msr(vm, BASE_ADDR_MSR);
1702
1703     V3_Free(apic_dev);
1704     return 0;
1705 }
1706
1707
1708 static struct v3_device_ops dev_ops = {
1709     .free = (int (*)(void *))apic_free,
1710 };
1711
1712
1713
1714 static int apic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
1715     char * dev_id = v3_cfg_val(cfg, "ID");
1716     struct apic_dev_state * apic_dev = NULL;
1717     int i = 0;
1718
1719     PrintDebug("apic: creating an APIC for each core\n");
1720
1721     apic_dev = (struct apic_dev_state *)V3_Malloc(sizeof(struct apic_dev_state) + 
1722                                                   sizeof(struct apic_state) * vm->num_cores);
1723
1724     apic_dev->num_apics = vm->num_cores;
1725     v3_lock_init(&(apic_dev->state_lock));
1726
1727     struct vm_device * dev = v3_add_device(vm, dev_id, &dev_ops, apic_dev);
1728
1729     if (dev == NULL) {
1730         PrintError("apic: Could not attach device %s\n", dev_id);
1731         V3_Free(apic_dev);
1732         return -1;
1733     }
1734
1735     
1736     for (i = 0; i < vm->num_cores; i++) {
1737         struct apic_state * apic = &(apic_dev->apics[i]);
1738         struct guest_info * core = &(vm->cores[i]);
1739
1740         apic->core = core;
1741
1742         init_apic_state(apic, i);
1743
1744         apic->controller_handle = v3_register_intr_controller(core, &intr_ops, apic_dev);
1745
1746         apic->timer = v3_add_timer(core, &timer_ops, apic_dev);
1747
1748         if (apic->timer == NULL) {
1749             PrintError("APIC: Failed to attach timer to core %d\n", i);
1750             v3_remove_device(dev);
1751             return -1;
1752         }
1753
1754         v3_hook_full_mem(vm, core->vcpu_id, apic->base_addr, apic->base_addr + PAGE_SIZE_4KB, apic_read, apic_write, apic_dev);
1755
1756         PrintDebug("apic %u: (setup device): done, my id is %u\n", i, apic->lapic_id.val);
1757     }
1758
1759 #ifdef V3_CONFIG_DEBUG_APIC
1760     for (i = 0; i < vm->num_cores; i++) {
1761         struct apic_state * apic = &(apic_dev->apics[i]);
1762         PrintDebug("apic: sanity check: apic %u (at %p) has id %u and msr value %llx and core at %p\n",
1763                    i, apic, apic->lapic_id.val, apic->base_addr_msr.value,apic->core);
1764     }
1765 #endif
1766
1767
1768     PrintDebug("apic: priv_data is at %p\n", apic_dev);
1769
1770     v3_hook_msr(vm, BASE_ADDR_MSR, read_apic_msr, write_apic_msr, apic_dev);
1771
1772     return 0;
1773 }
1774
1775
1776
1777 device_register("LAPIC", apic_init)