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.


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