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.


Partially functional icc_bus (works for UP)
[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.val = 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
160
161 static int ioapic_read(struct guest_info * core, addr_t guest_addr, void * dst, uint_t length, void * priv_data) {
162     struct vm_device * dev = (struct vm_device *)priv_data;
163     struct io_apic_state * ioapic = (struct io_apic_state *)(dev->private_data);
164     uint32_t reg_tgt = guest_addr - ioapic->base_addr;
165     uint32_t * op_val = (uint32_t *)dst;
166
167     PrintDebug("ioapic %u: IOAPIC Read at %p\n", ioapic->ioapic_id.val, (void *)guest_addr);
168
169     if (reg_tgt == 0x00) {
170         *op_val = ioapic->index_reg;
171     } else if (reg_tgt == 0x10) {
172         // IOWIN register
173         switch (ioapic->index_reg) {
174             case IOAPIC_ID_REG:
175                 *op_val = ioapic->ioapic_id.val;
176                 break;
177             case IOAPIC_VER_REG:
178                 *op_val = ioapic->ioapic_ver.val;
179                 break;
180             case IOAPIC_ARB_REG:
181                 *op_val = ioapic->ioapic_arb_id.val;
182                 break;
183             default:
184                 {
185                     uint_t redir_index = (ioapic->index_reg - IOAPIC_REDIR_BASE_REG) >> 1;
186                     uint_t hi_val = (ioapic->index_reg - IOAPIC_REDIR_BASE_REG) % 1;
187
188                     if (redir_index > 0x3f) {
189                         PrintError("ioapic %u: Invalid redirection table entry %x\n", ioapic->ioapic_id.val, (uint32_t)redir_index);
190                         return -1;
191                     }
192                     if (hi_val) {
193                         *op_val = ioapic->redir_tbl[redir_index].hi;
194                     } else {
195                         *op_val = ioapic->redir_tbl[redir_index].lo;
196                     }
197                 }
198         }
199     }
200
201     return length;
202 }
203
204
205 static int ioapic_write(struct guest_info * core, addr_t guest_addr, void * src, uint_t length, void * priv_data) {
206     struct vm_device * dev = (struct vm_device *)priv_data;
207     struct io_apic_state * ioapic = (struct io_apic_state *)(dev->private_data);
208     uint32_t reg_tgt = guest_addr - ioapic->base_addr;
209     uint32_t op_val = *(uint32_t *)src;
210
211     PrintDebug("ioapic %u: IOAPIC Write at %p (val = %d)\n",  ioapic->ioapic_id.val, (void *)guest_addr, *(uint32_t *)src);
212
213     if (reg_tgt == 0x00) {
214         ioapic->index_reg = op_val;
215     } else if (reg_tgt == 0x10) {
216         // IOWIN register
217         switch (ioapic->index_reg) {
218             case IOAPIC_ID_REG:
219                 ioapic->ioapic_id.val = op_val;
220                 break;
221             case IOAPIC_VER_REG:
222                 // GPF/PageFault/Ignore?
223                 PrintError("ioapic %u: Writing to read only IOAPIC register\n", ioapic->ioapic_id.val);
224                 return -1;
225             case IOAPIC_ARB_REG:
226                 ioapic->ioapic_arb_id.val = op_val;
227                 break;
228             default:
229                 {
230                     uint_t redir_index = (ioapic->index_reg - IOAPIC_REDIR_BASE_REG) >> 1;
231                     uint_t hi_val = (ioapic->index_reg - IOAPIC_REDIR_BASE_REG) % 1;
232
233
234
235
236                     if (redir_index > 0x3f) {
237                         PrintError("ioapic %u: Invalid redirection table entry %x\n", ioapic->ioapic_id.val, (uint32_t)redir_index);
238                         return -1;
239                     }
240                     if (hi_val) {
241                         PrintDebug("ioapic %u: Writing to hi of pin %d\n", ioapic->ioapic_id.val, redir_index);
242                         ioapic->redir_tbl[redir_index].hi = op_val;
243                     } else {
244                         PrintDebug("ioapic %u: Writing to lo of pin %d\n", ioapic->ioapic_id.val, redir_index);
245                         op_val &= REDIR_LO_MASK;
246                         ioapic->redir_tbl[redir_index].lo &= ~REDIR_LO_MASK;
247                         ioapic->redir_tbl[redir_index].lo |= op_val;
248                     }
249                 }
250         }
251     }
252
253     return length;
254 }
255
256
257 static int ioapic_raise_irq(struct v3_vm_info * vm, void * private_data, int irq) {
258     struct vm_device * dev = (struct vm_device *)private_data;
259     struct io_apic_state * ioapic = (struct io_apic_state *)(dev->private_data);  
260     struct redir_tbl_entry * irq_entry = NULL;
261
262     if (irq > 24) {
263         PrintDebug("ioapic %u: IRQ out of range of IO APIC\n", ioapic->ioapic_id.val);
264         return -1;
265     }
266
267     irq_entry = &(ioapic->redir_tbl[irq]);
268
269     if (irq_entry->mask == 0) {
270         PrintDebug("ioapic %u: IOAPIC Signalling APIC to raise INTR %d\n", ioapic->ioapic_id.val, irq_entry->vec);
271
272         // the format of the redirection table entry is just slightly 
273         // different than that of the lapic's cmd register, which is the other
274         // way an IPI is initiated.   So we will translate
275         //
276         struct int_cmd_reg icr;
277         
278         icr.val = irq_entry->val;
279         icr.rsvd1=0;
280         icr.lvl=1;
281         icr.trig_mode=irq_entry->trig_mode;
282         icr.rem_rd_status=0;
283         icr.dst_shorthand=0; // no shorthand
284         icr.rsvd2=0;
285
286         v3_icc_send_ipi(ioapic->icc_bus, ioapic->ioapic_id.val,icr.val);
287     }
288
289     return 0;
290 }
291
292 /* I don't know if we can do anything here.... */
293 static int ioapic_lower_irq(struct v3_vm_info * vm, void * private_data, int irq) {
294     return 0;
295 }
296
297 static struct intr_router_ops router_ops = {
298     .raise_intr = ioapic_raise_irq,
299     .lower_intr = ioapic_lower_irq, 
300 };
301
302
303
304
305 static int io_apic_free(struct vm_device * dev) {
306     //  struct guest_info * info = dev->vm;
307
308     return 0;
309 }
310
311
312 static struct v3_device_ops dev_ops = {
313     .free = io_apic_free,
314     .reset = NULL,
315     .start = NULL,
316     .stop = NULL,
317 };
318
319
320
321 static int ioapic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
322     struct vm_device * icc_bus = v3_find_dev(vm, v3_cfg_val(cfg, "bus"));
323     char * name = v3_cfg_val(cfg, "name");
324
325     if (!icc_bus) {
326         PrintError("ioapic: Could not locate ICC BUS device (%s)\n", v3_cfg_val(cfg, "bus"));
327         return -1;
328     }
329
330     PrintDebug("ioapic: Creating IO APIC\n");
331
332     struct io_apic_state * ioapic = (struct io_apic_state *)V3_Malloc(sizeof(struct io_apic_state));
333
334     ioapic->icc_bus = icc_bus;
335
336     struct vm_device * dev = v3_allocate_device(name, &dev_ops, ioapic);
337
338
339     if (v3_attach_device(vm, dev) == -1) {
340         PrintError("ioapic: Could not attach device %s\n", name);
341         return -1;
342     }
343
344
345     v3_register_intr_router(vm, &router_ops, dev);
346
347     init_ioapic_state(ioapic,vm->num_cores);
348
349     v3_icc_register_ioapic(vm,icc_bus,ioapic->ioapic_id.val);
350
351     v3_hook_full_mem(vm, V3_MEM_CORE_ANY, ioapic->base_addr, ioapic->base_addr + PAGE_SIZE_4KB, 
352                      ioapic_read, ioapic_write, dev);
353   
354     return 0;
355 }
356
357
358 device_register("IOAPIC", ioapic_init)