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.


Fixed ioapic bug that caused interrupt routing entries to be stored incorrectly and...
[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/icc_bus.h>
24 #include <devices/apic_regs.h>
25 #include <palacios/vm_guest.h>
26
27 #ifndef CONFIG_DEBUG_IO_APIC
28 #undef PrintDebug
29 #define PrintDebug(fmt, args...)
30 #endif
31
32
33
34 #define IO_APIC_BASE_ADDR 0xfec00000
35
36
37 #define IOAPIC_ID_REG 0x00
38 #define IOAPIC_VER_REG 0x01
39 #define IOAPIC_ARB_REG 0x02
40
41 #define IOAPIC_REDIR_BASE_REG 0x10
42
43 #define REDIR_LO_MASK  ~0x00005000
44
45 struct ioapic_reg_sel {
46     union {
47         uint32_t val;
48         struct {
49             uint_t reg_addr     : 8;
50             uint_t rsvd         : 24;
51         } __attribute__((packed));
52     } __attribute__((packed));
53 } __attribute__((packed));
54
55 struct ioapic_id_reg {
56     union {
57         uint32_t val;
58         struct {
59             uint_t rsvd1      : 24;
60             uint_t id         : 4;
61             uint_t rsvd2      : 4;
62         } __attribute__((packed));
63     } __attribute__((packed));
64 } __attribute__((packed));
65
66 struct ioapic_ver_reg {
67     union {
68         uint32_t val;
69         struct {
70             uint_t version    : 8;
71             uint_t rsvd1      : 8;
72             uint_t max_redir  : 8;
73             uint_t rsvd2      : 8;
74         } __attribute__((packed));
75     } __attribute__((packed));
76 } __attribute__((packed));
77
78
79 struct ioapic_arb_reg {
80     union {
81         uint32_t val;
82         struct {
83             uint_t rsvd1      : 24;
84             uint_t max_redir  : 4;
85             uint_t rsvd2      : 4;
86         } __attribute__((packed));
87     } __attribute__((packed));
88 } __attribute__((packed));
89
90
91 struct redir_tbl_entry {
92     union {
93         uint64_t val;
94         struct {
95             uint32_t lo;
96             uint32_t hi;
97         } __attribute__((packed));
98         struct {
99             uint_t vec        : 8;
100
101 #define FIXED        0x0
102 #define LOWEST_PRIOR 0x1
103 #define SMI          0x2
104 #define NMI          0x4
105 #define INIT         0x5
106 #define EXTINT       0x7
107             uint_t del_mode   : 3;
108
109 #define PHSYICAL_DST_MODE 0
110 #define LOGICAL_DST_MODE 1
111             uint_t dst_mode   : 1;
112             uint_t del_status : 1;
113
114 #define HIGH_ACTIVE 0
115 #define LOW_ACTIVE 1
116             uint_t intr_pol   : 1;
117             uint_t rem_irr    : 1;
118             uint_t trig_mode  : 1;
119             uint_t mask       : 1;
120             uint64_t rsvd     : 39;
121             uint_t dst_field  : 8;
122         } __attribute__((packed));
123     } __attribute__((packed));
124 } __attribute__((packed));
125
126
127
128 struct io_apic_state {
129     addr_t base_addr;
130
131     uint32_t index_reg;
132
133     struct ioapic_id_reg ioapic_id;
134     struct ioapic_ver_reg ioapic_ver;
135     struct ioapic_arb_reg ioapic_arb_id;
136   
137     struct redir_tbl_entry redir_tbl[24];
138
139     struct vm_device * icc_bus;
140   
141 };
142
143
144 static void init_ioapic_state(struct io_apic_state * ioapic, uint32_t id) {
145     int i = 0;
146     ioapic->base_addr = IO_APIC_BASE_ADDR;
147     ioapic->index_reg = 0;
148
149     ioapic->ioapic_id.id = id;
150     ioapic->ioapic_ver.val = 0x00170011;
151     ioapic->ioapic_arb_id.val = 0x00000000;
152
153     for (i = 0; i < 24; i++) {
154         ioapic->redir_tbl[i].val = 0x0001000000000000LL;
155         // Mask all interrupts until they are enabled....
156         ioapic->redir_tbl[i].mask = 1;
157     }
158     
159     // special case redir_tbl[0] for pin 0 as ExtInt for Virtual Wire Mode
160     // ioapic->redir_tbl[0].del_mode=EXTINT;
161     // ioapic->redir_tbl[0].mask=0;
162 }
163
164
165 static int ioapic_read(struct guest_info * core, addr_t guest_addr, void * dst, uint_t length, void * priv_data) {
166     struct vm_device * dev = (struct vm_device *)priv_data;
167     struct io_apic_state * ioapic = (struct io_apic_state *)(dev->private_data);
168     uint32_t reg_tgt = guest_addr - ioapic->base_addr;
169     uint32_t * op_val = (uint32_t *)dst;
170
171     PrintDebug("ioapic %u: IOAPIC Read at %p\n", ioapic->ioapic_id.id, (void *)guest_addr);
172
173     if (reg_tgt == 0x00) {
174         *op_val = ioapic->index_reg;
175     } else if (reg_tgt == 0x10) {
176         // IOWIN register
177         switch (ioapic->index_reg) {
178             case IOAPIC_ID_REG:
179                 *op_val = ioapic->ioapic_id.val;
180                 break;
181             case IOAPIC_VER_REG:
182                 *op_val = ioapic->ioapic_ver.val;
183                 break;
184             case IOAPIC_ARB_REG:
185                 *op_val = ioapic->ioapic_arb_id.val;
186                 break;
187             default: {
188                 uint_t redir_index = (ioapic->index_reg - IOAPIC_REDIR_BASE_REG) >> 1;
189                 uint_t hi_val = (ioapic->index_reg - IOAPIC_REDIR_BASE_REG) & 1;
190                 
191                 if (redir_index > 0x3f) {
192                     PrintError("ioapic %u: Invalid redirection table entry %x\n", ioapic->ioapic_id.id, (uint32_t)redir_index);
193                     return -1;
194                 }
195                 
196                 if (hi_val) {
197                     *op_val = ioapic->redir_tbl[redir_index].hi;
198                 } else {
199                     *op_val = ioapic->redir_tbl[redir_index].lo;
200                 }
201             }
202         }
203     }
204
205     PrintDebug("ioapic %u: IOAPIC Read at %p gave value 0x%x\n", ioapic->ioapic_id.id, (void *)guest_addr, *op_val);
206
207     return length;
208 }
209
210
211 static int ioapic_write(struct guest_info * core, addr_t guest_addr, void * src, uint_t length, void * priv_data) {
212     struct vm_device * dev = (struct vm_device *)priv_data;
213     struct io_apic_state * ioapic = (struct io_apic_state *)(dev->private_data);
214     uint32_t reg_tgt = guest_addr - ioapic->base_addr;
215     uint32_t op_val = *(uint32_t *)src;
216
217     PrintDebug("ioapic %u: IOAPIC Write at %p (val = %d)\n",  ioapic->ioapic_id.id, (void *)guest_addr, *(uint32_t *)src);
218
219     if (reg_tgt == 0x00) {
220         PrintDebug("ioapic %u: Setting ioapic index register to 0x%x.\n", ioapic->ioapic_id.id, op_val);
221         ioapic->index_reg = op_val;
222     } else if (reg_tgt == 0x10) {
223         // IOWIN register
224         switch (ioapic->index_reg) {
225             case IOAPIC_ID_REG:
226                 // What does this do to our relationship with the ICC bus?
227                 ioapic->ioapic_id.val = op_val;
228                 break;
229             case IOAPIC_VER_REG:
230                 // GPF/PageFault/Ignore?
231                 PrintError("ioapic %u: Writing to read only IOAPIC register\n", ioapic->ioapic_id.id);
232                 return -1;
233             case IOAPIC_ARB_REG:
234                 ioapic->ioapic_arb_id.val = op_val;
235                 break;
236             default:
237                 {
238                     uint_t redir_index = (ioapic->index_reg - IOAPIC_REDIR_BASE_REG) >> 1;
239                     uint_t hi_val = (ioapic->index_reg - IOAPIC_REDIR_BASE_REG) & 1;
240
241                     PrintDebug("ioapic %u: Writing value 0x%x to redirection entry %u (%s)\n",
242                                ioapic->ioapic_id.id, op_val, redir_index, hi_val ? "hi" : "low");
243
244                     if (redir_index > 0x3f) {
245                         PrintError("ioapic %u: Invalid redirection table entry %x\n", ioapic->ioapic_id.id, (uint32_t)redir_index);
246                         return -1;
247                     }
248                     if (hi_val) {
249                         PrintDebug("ioapic %u: Writing to hi of pin %d\n", ioapic->ioapic_id.val, redir_index);
250                         ioapic->redir_tbl[redir_index].hi = op_val;
251                     } else {
252                         PrintDebug("ioapic %u: Writing to lo of pin %d\n", ioapic->ioapic_id.id, redir_index);
253                         op_val &= REDIR_LO_MASK;
254                         ioapic->redir_tbl[redir_index].lo &= ~REDIR_LO_MASK;
255                         ioapic->redir_tbl[redir_index].lo |= op_val;
256                     }
257                 }
258         }
259     }
260
261     return length;
262 }
263
264
265 static int ioapic_raise_irq(struct v3_vm_info * vm, void * private_data, int irq) {
266     struct vm_device * dev = (struct vm_device *)private_data;
267     struct io_apic_state * ioapic = (struct io_apic_state *)(dev->private_data);  
268     struct redir_tbl_entry * irq_entry = NULL;
269
270     if (irq > 24) {
271         PrintDebug("ioapic %u: IRQ out of range of IO APIC\n", ioapic->ioapic_id.id);
272         return -1;
273     }
274
275     irq_entry = &(ioapic->redir_tbl[irq]);
276
277     if (irq_entry->mask == 0) {
278
279         PrintDebug("ioapic %u: IOAPIC Signalling APIC to raise INTR %d\n", ioapic->ioapic_id.id, irq_entry->vec);
280
281
282         // the format of the redirection table entry is just slightly 
283         // different than that of the lapic's cmd register, which is the other
284         // way an IPI is initiated.   So we will translate
285         //
286         struct int_cmd_reg icr;
287         
288         icr.val = irq_entry->val;
289         icr.rsvd1=0;
290         icr.lvl=1;
291         icr.trig_mode=irq_entry->trig_mode;
292         icr.rem_rd_status=0;
293         icr.dst_shorthand=0; // no shorthand
294         icr.rsvd2=0;
295
296         // Note: 0 yhere is "cluster model", but it should be irrelevant
297         // since we are sending this as a physical destination
298         PrintDebug("io apic %u: raising irq %u on ICC bus.\n",
299                    ioapic->ioapic_id.id, irq);
300         v3_icc_send_ipi(ioapic->icc_bus, ioapic->ioapic_id.id,icr.val, 0, irq);
301     }
302
303     return 0;
304 }
305
306 /* I don't know if we can do anything here.... */
307 static int ioapic_lower_irq(struct v3_vm_info * vm, void * private_data, int irq) {
308     return 0;
309 }
310
311 static struct intr_router_ops router_ops = {
312     .raise_intr = ioapic_raise_irq,
313     .lower_intr = ioapic_lower_irq, 
314 };
315
316
317
318
319 static int io_apic_free(struct vm_device * dev) {
320     //  struct guest_info * info = dev->vm;
321
322     return 0;
323 }
324
325
326 static struct v3_device_ops dev_ops = {
327     .free = io_apic_free,
328     .reset = NULL,
329     .start = NULL,
330     .stop = NULL,
331 };
332
333
334
335 static int ioapic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
336     struct vm_device * icc_bus = v3_find_dev(vm, v3_cfg_val(cfg, "bus"));
337     char * dev_id = v3_cfg_val(cfg, "ID");
338
339     if (!icc_bus) {
340         PrintError("ioapic: Could not locate ICC BUS device (%s)\n", v3_cfg_val(cfg, "bus"));
341         return -1;
342     }
343
344     PrintDebug("ioapic: Creating IO APIC\n");
345
346     struct io_apic_state * ioapic = (struct io_apic_state *)V3_Malloc(sizeof(struct io_apic_state));
347
348     ioapic->icc_bus = icc_bus;
349
350     struct vm_device * dev = v3_allocate_device(dev_id, &dev_ops, ioapic);
351
352
353     if (v3_attach_device(vm, dev) == -1) {
354         PrintError("ioapic: Could not attach device %s\n", dev_id);
355         return -1;
356     }
357
358
359     v3_register_intr_router(vm, &router_ops, dev);
360
361     init_ioapic_state(ioapic,vm->num_cores);
362
363     v3_icc_register_ioapic(vm,icc_bus,ioapic->ioapic_id.id);
364
365     v3_hook_full_mem(vm, V3_MEM_CORE_ANY, ioapic->base_addr, ioapic->base_addr + PAGE_SIZE_4KB, 
366                      ioapic_read, ioapic_write, dev);
367   
368     return 0;
369 }
370
371
372 device_register("IOAPIC", ioapic_init)