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.


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