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.


Fix for option processing
[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(core->vm_info, core, "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(core->vm_info, core, "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(core->vm_info, core, "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(core->vm_info, core, "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(core->vm_info, core, "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(core->vm_info, core, "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(core->vm_info, core, "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(core->vm_info, core, "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(core->vm_info, core, "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(core->vm_info, core, "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, struct v3_irq * irq) {
267     struct io_apic_state * ioapic = (struct io_apic_state *)(private_data);  
268     struct redir_tbl_entry * irq_entry = NULL;
269     uint8_t irq_num = irq->irq;
270
271     if (irq_num == 0) { 
272       // IRQ 0 being raised, in the Palacios context, means the PIT
273       // However, the convention is that it is the PIC that is connected
274       // to PIN 0 of the IOAPIC and the PIT is connected to pin 2
275       // Hence we convert this to the relvant pin.  In the future,
276       // the PIC may signal to the IOAPIC in a different path.
277       // Yes, this is kind of hideous, but it is needed to have the
278       // PIT correctly show up via the IOAPIC
279       irq_num = 2;
280     }
281
282     if (irq_num > 24) {
283         PrintDebug(vm, VCORE_NONE, "ioapic %u: IRQ out of range of IO APIC\n", ioapic->ioapic_id.id);
284         return -1;
285     }
286
287     irq_entry = &(ioapic->redir_tbl[irq_num]);
288
289     if (irq_entry->mask == 0) {
290         struct v3_gen_ipi ipi;
291
292         PrintDebug(vm, VCORE_NONE, "ioapic %u: IOAPIC Signaling APIC to raise INTR %d\n", 
293                    ioapic->ioapic_id.id, irq_entry->vec);
294
295
296         ipi.vector = irq_entry->vec;
297         ipi.mode = irq_entry->del_mode;
298         ipi.logical = irq_entry->dst_mode;
299         ipi.trigger_mode = irq_entry->trig_mode;
300         ipi.dst = irq_entry->dst_field;
301         ipi.dst_shorthand = 0;
302
303         ipi.ack = irq->ack;
304         ipi.private_data = irq->private_data;
305
306         PrintDebug(vm, VCORE_NONE, "ioapic %u: IPI: vector 0x%x, mode 0x%x, logical 0x%x, trigger 0x%x, dst 0x%x, shorthand 0x%x\n",
307                    ioapic->ioapic_id.id, ipi.vector, ipi.mode, ipi.logical, ipi.trigger_mode, ipi.dst, ipi.dst_shorthand);
308         // Need to add destination argument here...
309         if (v3_apic_send_ipi(vm, &ipi, ioapic->apic_dev_data) == -1) {
310             PrintError(vm, VCORE_NONE, "Error sending IPI to apic %d\n", ipi.dst);
311             return -1;
312         }
313     }
314
315     return 0;
316 }
317
318 /* I don't know if we can do anything here.... */
319 static int ioapic_lower_irq(struct v3_vm_info * vm, void * private_data, struct v3_irq * irq) {
320     return 0;
321 }
322
323 static struct intr_router_ops router_ops = {
324     .raise_intr = ioapic_raise_irq,
325     .lower_intr = ioapic_lower_irq, 
326 };
327
328
329
330
331 static int io_apic_free(struct io_apic_state * ioapic) {
332
333     v3_remove_intr_router(ioapic->vm, ioapic->router_handle);
334
335     // unhook memory
336
337     V3_Free(ioapic);
338
339     return 0;
340 }
341
342 #ifdef V3_CONFIG_CHECKPOINT
343 static int io_apic_save(struct v3_chkpt_ctx * ctx, void * private_data) {
344     struct io_apic_state * io_apic = (struct io_apic_state *)private_data;
345
346
347     V3_CHKPT_SAVE(ctx, "BASE_ADDR" ,io_apic->base_addr,savefailout);
348     V3_CHKPT_SAVE(ctx, "INDEX_REG", io_apic->index_reg,savefailout);
349     V3_CHKPT_SAVE(ctx, "IOAPIC_ID", io_apic->ioapic_id,savefailout);
350     V3_CHKPT_SAVE(ctx, "IOAPIC_VER", io_apic->ioapic_ver,savefailout);
351     V3_CHKPT_SAVE(ctx, "IOAPIC_ARB_ID", io_apic->ioapic_arb_id,savefailout);
352     V3_CHKPT_SAVE(ctx, "REDIR_TABLE", io_apic->redir_tbl,savefailout);
353
354     return 0;
355
356  savefailout:
357     PrintError(VM_NONE, VCORE_NONE, "ioapic save failed\n");
358     return -1;
359 }
360
361 static int io_apic_load(struct v3_chkpt_ctx * ctx, void * private_data) {
362     struct io_apic_state * io_apic = (struct io_apic_state *)private_data;
363
364     V3_CHKPT_LOAD(ctx, "BASE_ADDR", io_apic->base_addr,loadfailout);
365     V3_CHKPT_LOAD(ctx, "INDEX_REG", io_apic->index_reg,loadfailout);
366     V3_CHKPT_LOAD(ctx, "IOAPIC_ID", io_apic->ioapic_id,loadfailout);
367     V3_CHKPT_LOAD(ctx, "IOAPIC_VER", io_apic->ioapic_ver,loadfailout);
368     V3_CHKPT_LOAD(ctx, "IOAPIC_ARB_ID", io_apic->ioapic_arb_id,loadfailout);
369     V3_CHKPT_LOAD(ctx, "REDIR_TABLE", io_apic->redir_tbl,loadfailout);
370
371     return 0;
372
373  loadfailout:
374     PrintError(VM_NONE, VCORE_NONE, "ioapic load failed\n");
375     return -1;
376     
377 }
378 #endif
379
380
381
382 static struct v3_device_ops dev_ops = {
383     .free = (int (*)(void *))io_apic_free,
384 #ifdef V3_CONFIG_CHECKPOINT
385     .save = io_apic_save, 
386     .load = io_apic_load
387 #endif
388 };
389
390
391
392 static int ioapic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
393     struct vm_device * apic_dev = v3_find_dev(vm, v3_cfg_val(cfg, "apic"));
394     char * dev_id = v3_cfg_val(cfg, "ID");
395
396
397     PrintDebug(vm, VCORE_NONE, "ioapic: Creating IO APIC\n");
398
399     struct io_apic_state * ioapic = (struct io_apic_state *)V3_Malloc(sizeof(struct io_apic_state));
400
401     if (!ioapic) {
402         PrintError(vm, VCORE_NONE, "Cannot allocate in init\n");
403         return -1;
404     }
405
406     ioapic->apic_dev_data = apic_dev;
407
408     struct vm_device * dev = v3_add_device(vm, dev_id, &dev_ops, ioapic);
409
410     if (dev == NULL) {
411         PrintError(vm, VCORE_NONE,  "ioapic: Could not attach device %s\n", dev_id);
412         V3_Free(ioapic);
413         return -1;
414     }
415
416     ioapic->router_handle = v3_register_intr_router(vm, &router_ops, ioapic);
417     ioapic->vm = vm;
418
419     init_ioapic_state(ioapic, vm->num_cores);
420
421     v3_hook_full_mem(vm, V3_MEM_CORE_ANY, ioapic->base_addr, ioapic->base_addr + PAGE_SIZE_4KB, 
422                      ioapic_read, ioapic_write, ioapic);
423   
424     return 0;
425 }
426
427
428 device_register("IOAPIC", ioapic_init)