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.


More detailed error handling on msr writes
[palacios.git] / palacios / src / devices / io_apic.c
1 /* 
2  * This file is part of the Palacios Virtual Machine Monitor developed
3  * by the V3VEE Project with funding from the United States National 
4  * Science Foundation and the Department of Energy.  
5  *
6  * The V3VEE Project is a joint project between Northwestern University
7  * and the University of New Mexico.  You can find out more at 
8  * http://www.v3vee.org
9  *
10  * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu> 
11  * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
12  * All rights reserved.
13  *
14  * Author: Jack Lange <jarusl@cs.northwestern.edu>
15  *
16  * This is free software.  You are permitted to use,
17  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
18  */
19
20
21 #include <palacios/vmm.h>
22 #include <palacios/vmm_dev_mgr.h>
23 #include <devices/apic.h>
24 #include <palacios/vm_guest.h>
25
26 #ifndef V3_CONFIG_DEBUG_IO_APIC
27 #undef PrintDebug
28 #define PrintDebug(fmt, args...)
29 #endif
30
31
32
33 #define IO_APIC_BASE_ADDR 0xfec00000
34
35
36 #define IOAPIC_ID_REG 0x00
37 #define IOAPIC_VER_REG 0x01
38 #define IOAPIC_ARB_REG 0x02
39
40 #define IOAPIC_REDIR_BASE_REG 0x10
41
42 #define REDIR_LO_MASK  ~0x00005000
43
44 struct ioapic_reg_sel {
45     union {
46         uint32_t val;
47         struct {
48             uint_t reg_addr     : 8;
49             uint_t rsvd         : 24;
50         } __attribute__((packed));
51     } __attribute__((packed));
52 } __attribute__((packed));
53
54 struct ioapic_id_reg {
55     union {
56         uint32_t val;
57         struct {
58             uint_t rsvd1      : 24;
59             uint_t id         : 4;
60             uint_t rsvd2      : 4;
61         } __attribute__((packed));
62     } __attribute__((packed));
63 } __attribute__((packed));
64
65 struct ioapic_ver_reg {
66     union {
67         uint32_t val;
68         struct {
69             uint_t version    : 8;
70             uint_t rsvd1      : 8;
71             uint_t max_redir  : 8;
72             uint_t rsvd2      : 8;
73         } __attribute__((packed));
74     } __attribute__((packed));
75 } __attribute__((packed));
76
77
78 struct ioapic_arb_reg {
79     union {
80         uint32_t val;
81         struct {
82             uint_t rsvd1      : 24;
83             uint_t max_redir  : 4;
84             uint_t rsvd2      : 4;
85         } __attribute__((packed));
86     } __attribute__((packed));
87 } __attribute__((packed));
88
89
90 struct redir_tbl_entry {
91     union {
92         uint64_t val;
93         struct {
94             uint32_t lo;
95             uint32_t hi;
96         } __attribute__((packed));
97         struct {
98             uint_t vec        : 8;
99
100 #define FIXED        0x0
101 #define LOWEST_PRIOR 0x1
102 #define SMI          0x2
103 #define NMI          0x4
104 #define INIT         0x5
105 #define EXTINT       0x7
106             uint_t del_mode   : 3;
107
108 #define PHSYICAL_DST_MODE 0
109 #define LOGICAL_DST_MODE 1
110             uint_t dst_mode   : 1;
111             uint_t del_status : 1;
112
113 #define HIGH_ACTIVE 0
114 #define LOW_ACTIVE 1
115             uint_t intr_pol   : 1;
116             uint_t rem_irr    : 1;
117             uint_t trig_mode  : 1;
118             uint_t mask       : 1;
119             uint64_t rsvd     : 39;
120             uint_t dst_field  : 8;
121         } __attribute__((packed));
122     } __attribute__((packed));
123 } __attribute__((packed));
124
125
126
127 struct io_apic_state {
128     addr_t base_addr;
129
130     uint32_t index_reg;
131
132     struct ioapic_id_reg ioapic_id;
133     struct ioapic_ver_reg ioapic_ver;
134     struct ioapic_arb_reg ioapic_arb_id;
135   
136     struct redir_tbl_entry redir_tbl[24];
137
138     void * apic_dev_data;
139
140     void * router_handle;
141
142     struct v3_vm_info * vm;
143   
144 };
145
146
147 static void init_ioapic_state(struct io_apic_state * ioapic, uint32_t id) {
148     int i = 0;
149     ioapic->base_addr = IO_APIC_BASE_ADDR;
150     ioapic->index_reg = 0;
151
152     ioapic->ioapic_id.id = id;
153     ioapic->ioapic_ver.val = 0x00170011;
154     ioapic->ioapic_arb_id.val = 0x00000000;
155
156     for (i = 0; i < 24; i++) {
157         ioapic->redir_tbl[i].val = 0x0001000000000000LL;
158         // Mask all interrupts until they are enabled....
159         ioapic->redir_tbl[i].mask = 1;
160     }
161     
162     // special case redir_tbl[0] for pin 0 as ExtInt for Virtual Wire Mode
163     // ioapic->redir_tbl[0].del_mode=EXTINT;
164     // ioapic->redir_tbl[0].mask=0;
165 }
166
167
168 static int ioapic_read(struct guest_info * core, addr_t guest_addr, void * dst, uint_t length, void * priv_data) {
169     struct io_apic_state * ioapic = (struct io_apic_state *)(priv_data);
170     uint32_t reg_tgt = guest_addr - ioapic->base_addr;
171     uint32_t * op_val = (uint32_t *)dst;
172
173     PrintDebug("ioapic %u: IOAPIC Read at %p\n", ioapic->ioapic_id.id, (void *)guest_addr);
174
175     if (reg_tgt == 0x00) {
176         *op_val = ioapic->index_reg;
177     } else if (reg_tgt == 0x10) {
178         // IOWIN register
179         switch (ioapic->index_reg) {
180             case IOAPIC_ID_REG:
181                 *op_val = ioapic->ioapic_id.val;
182                 break;
183             case IOAPIC_VER_REG:
184                 *op_val = ioapic->ioapic_ver.val;
185                 break;
186             case IOAPIC_ARB_REG:
187                 *op_val = ioapic->ioapic_arb_id.val;
188                 break;
189             default: {
190                 uint_t redir_index = (ioapic->index_reg - IOAPIC_REDIR_BASE_REG) >> 1;
191                 uint_t hi_val = (ioapic->index_reg - IOAPIC_REDIR_BASE_REG) & 1;
192                 
193                 if (redir_index > 0x3f) {
194                     PrintError("ioapic %u: Invalid redirection table entry %x\n", ioapic->ioapic_id.id, (uint32_t)redir_index);
195                     return -1;
196                 }
197                 
198                 if (hi_val) {
199                     *op_val = ioapic->redir_tbl[redir_index].hi;
200                 } else {
201                     *op_val = ioapic->redir_tbl[redir_index].lo;
202                 }
203             }
204         }
205     }
206
207     PrintDebug("ioapic %u: IOAPIC Read at %p gave value 0x%x\n", ioapic->ioapic_id.id, (void *)guest_addr, *op_val);
208
209     return length;
210 }
211
212
213 static int ioapic_write(struct guest_info * core, addr_t guest_addr, void * src, uint_t length, void * priv_data) {
214     struct io_apic_state * ioapic = (struct io_apic_state *)(priv_data);
215     uint32_t reg_tgt = guest_addr - ioapic->base_addr;
216     uint32_t op_val = *(uint32_t *)src;
217
218     PrintDebug("ioapic %u: IOAPIC Write at %p (val = %d)\n",  ioapic->ioapic_id.id, (void *)guest_addr, *(uint32_t *)src);
219
220     if (reg_tgt == 0x00) {
221         PrintDebug("ioapic %u: Setting ioapic index register to 0x%x.\n", ioapic->ioapic_id.id, op_val);
222         ioapic->index_reg = op_val;
223     } else if (reg_tgt == 0x10) {
224         // IOWIN register
225         switch (ioapic->index_reg) {
226             case IOAPIC_ID_REG:
227                 // What does this do to our relationship with the ICC bus?
228                 ioapic->ioapic_id.val = op_val;
229                 break;
230             case IOAPIC_VER_REG:
231                 // GPF/PageFault/Ignore?
232                 PrintError("ioapic %u: Writing to read only IOAPIC register\n", ioapic->ioapic_id.id);
233                 return -1;
234             case IOAPIC_ARB_REG:
235                 ioapic->ioapic_arb_id.val = op_val;
236                 break;
237             default:
238                 {
239                     uint_t redir_index = (ioapic->index_reg - IOAPIC_REDIR_BASE_REG) >> 1;
240                     uint_t hi_val = (ioapic->index_reg - IOAPIC_REDIR_BASE_REG) & 1;
241
242                     PrintDebug("ioapic %u: Writing value 0x%x to redirection entry %u (%s)\n",
243                                ioapic->ioapic_id.id, op_val, redir_index, hi_val ? "hi" : "low");
244
245                     if (redir_index > 0x3f) {
246                         PrintError("ioapic %u: Invalid redirection table entry %x\n", ioapic->ioapic_id.id, (uint32_t)redir_index);
247                         return -1;
248                     }
249                     if (hi_val) {
250                         PrintDebug("ioapic %u: Writing to hi of pin %d\n", ioapic->ioapic_id.id, redir_index);
251                         ioapic->redir_tbl[redir_index].hi = op_val;
252                     } else {
253                         PrintDebug("ioapic %u: Writing to lo of pin %d\n", ioapic->ioapic_id.id, redir_index);
254                         op_val &= REDIR_LO_MASK;
255                         ioapic->redir_tbl[redir_index].lo &= ~REDIR_LO_MASK;
256                         ioapic->redir_tbl[redir_index].lo |= op_val;
257                     }
258                 }
259         }
260     }
261
262     return length;
263 }
264
265
266 static int ioapic_raise_irq(struct v3_vm_info * vm, void * private_data, int irq) {
267     struct io_apic_state * ioapic = (struct io_apic_state *)(private_data);  
268     struct redir_tbl_entry * irq_entry = NULL;
269
270     if (irq==0) { 
271       // IRQ 0 being raised, in the Palacios context, means the PIT
272       // However, the convention is that it is the PIC that is connected
273       // to PIN 0 of the IOAPIC and the PIT is connected to pin 2
274       // Hence we convert this to the relvant pin.  In the future,
275       // the PIC may signal to the IOAPIC in a different path.
276       // Yes, this is kind of hideous, but it is needed to have the
277       // PIT correctly show up via the IOAPIC
278       irq=2;
279     }
280
281     if (irq > 24) {
282         PrintDebug("ioapic %u: IRQ out of range of IO APIC\n", ioapic->ioapic_id.id);
283         return -1;
284     }
285
286     irq_entry = &(ioapic->redir_tbl[irq]);
287
288     if (irq_entry->mask == 0) {
289         struct v3_gen_ipi ipi;
290
291         PrintDebug("ioapic %u: IOAPIC Signaling APIC to raise INTR %d\n", 
292                    ioapic->ioapic_id.id, irq_entry->vec);
293
294
295         ipi.vector = irq_entry->vec;
296         ipi.mode = irq_entry->del_mode;
297         ipi.logical = irq_entry->dst_mode;
298         ipi.trigger_mode = irq_entry->trig_mode;
299         ipi.dst = irq_entry->dst_field;
300         ipi.dst_shorthand = 0;
301
302
303         PrintDebug("ioapic %u: IPI: vector 0x%x, mode 0x%x, logical 0x%x, trigger 0x%x, dst 0x%x, shorthand 0x%x\n",
304                    ioapic->ioapic_id.id, ipi.vector, ipi.mode, ipi.logical, ipi.trigger_mode, ipi.dst, ipi.dst_shorthand);
305         // Need to add destination argument here...
306         if (v3_apic_send_ipi(vm, &ipi, ioapic->apic_dev_data) == -1) {
307             PrintError("Error sending IPI to apic %d\n", ipi.dst);
308             return -1;
309         }
310     }
311
312     return 0;
313 }
314
315 /* I don't know if we can do anything here.... */
316 static int ioapic_lower_irq(struct v3_vm_info * vm, void * private_data, int irq) {
317     return 0;
318 }
319
320 static struct intr_router_ops router_ops = {
321     .raise_intr = ioapic_raise_irq,
322     .lower_intr = ioapic_lower_irq, 
323 };
324
325
326
327
328 static int io_apic_free(struct io_apic_state * ioapic) {
329
330     v3_remove_intr_router(ioapic->vm, ioapic->router_handle);
331
332     // unhook memory
333
334     V3_Free(ioapic);
335
336     return 0;
337 }
338
339 #ifdef V3_CONFIG_CHECKPOINT
340 static int io_apic_save(struct v3_chkpt_ctx * ctx, void * private_data) {
341     struct io_apic_state * io_apic = (struct io_apic_state *)private_data;
342
343     V3_CHKPT_STD_SAVE(ctx, io_apic->base_addr);
344     V3_CHKPT_STD_SAVE(ctx, io_apic->index_reg);
345     V3_CHKPT_STD_SAVE(ctx, io_apic->ioapic_id);
346     V3_CHKPT_STD_SAVE(ctx, io_apic->ioapic_ver);
347     V3_CHKPT_STD_SAVE(ctx, io_apic->ioapic_arb_id);
348     V3_CHKPT_STD_SAVE(ctx, io_apic->redir_tbl);
349
350     return 0;
351 }
352
353 static int io_apic_load(struct v3_chkpt_ctx * ctx, void * private_data) {
354     struct io_apic_state * io_apic = (struct io_apic_state *)private_data;
355
356     V3_CHKPT_STD_LOAD(ctx, io_apic->base_addr);
357     V3_CHKPT_STD_LOAD(ctx, io_apic->index_reg);
358     V3_CHKPT_STD_LOAD(ctx, io_apic->ioapic_id);
359     V3_CHKPT_STD_LOAD(ctx, io_apic->ioapic_ver);
360     V3_CHKPT_STD_LOAD(ctx, io_apic->ioapic_arb_id);
361     V3_CHKPT_STD_LOAD(ctx, io_apic->redir_tbl);
362
363     return 0;
364 }
365 #endif
366
367
368
369 static struct v3_device_ops dev_ops = {
370     .free = (int (*)(void *))io_apic_free,
371 #ifdef V3_CONFIG_CHECKPOINT
372     .save = io_apic_save, 
373     .load = io_apic_load
374 #endif
375 };
376
377
378
379 static int ioapic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
380     struct vm_device * apic_dev = v3_find_dev(vm, v3_cfg_val(cfg, "apic"));
381     char * dev_id = v3_cfg_val(cfg, "ID");
382
383
384     PrintDebug("ioapic: Creating IO APIC\n");
385
386     struct io_apic_state * ioapic = (struct io_apic_state *)V3_Malloc(sizeof(struct io_apic_state));
387
388     ioapic->apic_dev_data = apic_dev;
389
390     struct vm_device * dev = v3_add_device(vm, dev_id, &dev_ops, ioapic);
391
392     if (dev == NULL) {
393         PrintError("ioapic: Could not attach device %s\n", dev_id);
394         V3_Free(ioapic);
395         return -1;
396     }
397
398     ioapic->router_handle = v3_register_intr_router(vm, &router_ops, ioapic);
399     ioapic->vm = vm;
400
401     init_ioapic_state(ioapic, vm->num_cores);
402
403     v3_hook_full_mem(vm, V3_MEM_CORE_ANY, ioapic->base_addr, ioapic->base_addr + PAGE_SIZE_4KB, 
404                      ioapic_read, ioapic_write, ioapic);
405   
406     return 0;
407 }
408
409
410 device_register("IOAPIC", ioapic_init)