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.


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