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.


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