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.


3579fdecbdf1755ae159ed58963cee290888d275
[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("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("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("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("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("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("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("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("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("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("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, int irq) {
267     struct io_apic_state * ioapic = (struct io_apic_state *)(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         struct v3_gen_ipi ipi;
279
280         PrintDebug("ioapic %u: IOAPIC Signaling APIC to raise INTR %d\n", 
281                    ioapic->ioapic_id.id, irq_entry->vec);
282
283
284         ipi.vector = irq_entry->vec;
285         ipi.mode = irq_entry->del_mode;
286         ipi.logical = irq_entry->dst_mode;
287         ipi.trigger_mode = irq_entry->trig_mode;
288         ipi.dst = irq_entry->dst_field;
289         ipi.dst_shorthand = 0;
290
291
292         PrintDebug("ioapic %u: IPI: vector 0x%x, mode 0x%x, logical 0x%x, trigger 0x%x, dst 0x%x, shorthand 0x%x\n",
293                    ioapic->ioapic_id.id, ipi.vector, ipi.mode, ipi.logical, ipi.trigger_mode, ipi.dst, ipi.dst_shorthand);
294         // Need to add destination argument here...
295         if (v3_apic_send_ipi(vm, &ipi, ioapic->apic_dev_data) == -1) {
296             PrintError("Error sending IPI to apic %d\n", ipi.dst);
297             return -1;
298         }
299     }
300
301     return 0;
302 }
303
304 /* I don't know if we can do anything here.... */
305 static int ioapic_lower_irq(struct v3_vm_info * vm, void * private_data, int irq) {
306     return 0;
307 }
308
309 static struct intr_router_ops router_ops = {
310     .raise_intr = ioapic_raise_irq,
311     .lower_intr = ioapic_lower_irq, 
312 };
313
314
315
316
317 static int io_apic_free(struct io_apic_state * ioapic) {
318
319     v3_remove_intr_router(ioapic->vm, ioapic->router_handle);
320
321     // unhook memory
322
323     V3_Free(ioapic);
324
325     return 0;
326 }
327
328
329 static struct v3_device_ops dev_ops = {
330     .free = (int (*)(void *))io_apic_free,
331
332 };
333
334
335
336 static int ioapic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
337     struct vm_device * apic_dev = v3_find_dev(vm, v3_cfg_val(cfg, "apic"));
338     char * dev_id = v3_cfg_val(cfg, "ID");
339
340
341     PrintDebug("ioapic: Creating IO APIC\n");
342
343     struct io_apic_state * ioapic = (struct io_apic_state *)V3_Malloc(sizeof(struct io_apic_state));
344
345     ioapic->apic_dev_data = apic_dev;
346
347     struct vm_device * dev = v3_add_device(vm, dev_id, &dev_ops, ioapic);
348
349     if (dev == NULL) {
350         PrintError("ioapic: Could not attach device %s\n", dev_id);
351         V3_Free(ioapic);
352         return -1;
353     }
354
355     ioapic->router_handle = v3_register_intr_router(vm, &router_ops, ioapic);
356     ioapic->vm = vm;
357
358     init_ioapic_state(ioapic, vm->num_cores);
359
360     v3_hook_full_mem(vm, V3_MEM_CORE_ANY, ioapic->base_addr, ioapic->base_addr + PAGE_SIZE_4KB, 
361                      ioapic_read, ioapic_write, ioapic);
362   
363     return 0;
364 }
365
366
367 device_register("IOAPIC", ioapic_init)