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.


deallocation of devices
[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 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 };
141
142
143 static void init_ioapic_state(struct io_apic_state * ioapic, uint32_t id) {
144     int i = 0;
145     ioapic->base_addr = IO_APIC_BASE_ADDR;
146     ioapic->index_reg = 0;
147
148     ioapic->ioapic_id.id = id;
149     ioapic->ioapic_ver.val = 0x00170011;
150     ioapic->ioapic_arb_id.val = 0x00000000;
151
152     for (i = 0; i < 24; i++) {
153         ioapic->redir_tbl[i].val = 0x0001000000000000LL;
154         // Mask all interrupts until they are enabled....
155         ioapic->redir_tbl[i].mask = 1;
156     }
157     
158     // special case redir_tbl[0] for pin 0 as ExtInt for Virtual Wire Mode
159     // ioapic->redir_tbl[0].del_mode=EXTINT;
160     // ioapic->redir_tbl[0].mask=0;
161 }
162
163
164 static int ioapic_read(struct guest_info * core, addr_t guest_addr, void * dst, uint_t length, void * priv_data) {
165     struct io_apic_state * ioapic = (struct io_apic_state *)(priv_data);
166     uint32_t reg_tgt = guest_addr - ioapic->base_addr;
167     uint32_t * op_val = (uint32_t *)dst;
168
169     PrintDebug("ioapic %u: IOAPIC Read at %p\n", ioapic->ioapic_id.id, (void *)guest_addr);
170
171     if (reg_tgt == 0x00) {
172         *op_val = ioapic->index_reg;
173     } else if (reg_tgt == 0x10) {
174         // IOWIN register
175         switch (ioapic->index_reg) {
176             case IOAPIC_ID_REG:
177                 *op_val = ioapic->ioapic_id.val;
178                 break;
179             case IOAPIC_VER_REG:
180                 *op_val = ioapic->ioapic_ver.val;
181                 break;
182             case IOAPIC_ARB_REG:
183                 *op_val = ioapic->ioapic_arb_id.val;
184                 break;
185             default: {
186                 uint_t redir_index = (ioapic->index_reg - IOAPIC_REDIR_BASE_REG) >> 1;
187                 uint_t hi_val = (ioapic->index_reg - IOAPIC_REDIR_BASE_REG) & 1;
188                 
189                 if (redir_index > 0x3f) {
190                     PrintError("ioapic %u: Invalid redirection table entry %x\n", ioapic->ioapic_id.id, (uint32_t)redir_index);
191                     return -1;
192                 }
193                 
194                 if (hi_val) {
195                     *op_val = ioapic->redir_tbl[redir_index].hi;
196                 } else {
197                     *op_val = ioapic->redir_tbl[redir_index].lo;
198                 }
199             }
200         }
201     }
202
203     PrintDebug("ioapic %u: IOAPIC Read at %p gave value 0x%x\n", ioapic->ioapic_id.id, (void *)guest_addr, *op_val);
204
205     return length;
206 }
207
208
209 static int ioapic_write(struct guest_info * core, addr_t guest_addr, void * src, uint_t length, void * priv_data) {
210     struct io_apic_state * ioapic = (struct io_apic_state *)(priv_data);
211     uint32_t reg_tgt = guest_addr - ioapic->base_addr;
212     uint32_t op_val = *(uint32_t *)src;
213
214     PrintDebug("ioapic %u: IOAPIC Write at %p (val = %d)\n",  ioapic->ioapic_id.id, (void *)guest_addr, *(uint32_t *)src);
215
216     if (reg_tgt == 0x00) {
217         PrintDebug("ioapic %u: Setting ioapic index register to 0x%x.\n", ioapic->ioapic_id.id, op_val);
218         ioapic->index_reg = op_val;
219     } else if (reg_tgt == 0x10) {
220         // IOWIN register
221         switch (ioapic->index_reg) {
222             case IOAPIC_ID_REG:
223                 // What does this do to our relationship with the ICC bus?
224                 ioapic->ioapic_id.val = op_val;
225                 break;
226             case IOAPIC_VER_REG:
227                 // GPF/PageFault/Ignore?
228                 PrintError("ioapic %u: Writing to read only IOAPIC register\n", ioapic->ioapic_id.id);
229                 return -1;
230             case IOAPIC_ARB_REG:
231                 ioapic->ioapic_arb_id.val = op_val;
232                 break;
233             default:
234                 {
235                     uint_t redir_index = (ioapic->index_reg - IOAPIC_REDIR_BASE_REG) >> 1;
236                     uint_t hi_val = (ioapic->index_reg - IOAPIC_REDIR_BASE_REG) & 1;
237
238                     PrintDebug("ioapic %u: Writing value 0x%x to redirection entry %u (%s)\n",
239                                ioapic->ioapic_id.id, op_val, redir_index, hi_val ? "hi" : "low");
240
241                     if (redir_index > 0x3f) {
242                         PrintError("ioapic %u: Invalid redirection table entry %x\n", ioapic->ioapic_id.id, (uint32_t)redir_index);
243                         return -1;
244                     }
245                     if (hi_val) {
246                         PrintDebug("ioapic %u: Writing to hi of pin %d\n", ioapic->ioapic_id.id, redir_index);
247                         ioapic->redir_tbl[redir_index].hi = op_val;
248                     } else {
249                         PrintDebug("ioapic %u: Writing to lo of pin %d\n", ioapic->ioapic_id.id, redir_index);
250                         op_val &= REDIR_LO_MASK;
251                         ioapic->redir_tbl[redir_index].lo &= ~REDIR_LO_MASK;
252                         ioapic->redir_tbl[redir_index].lo |= op_val;
253                     }
254                 }
255         }
256     }
257
258     return length;
259 }
260
261
262 static int ioapic_raise_irq(struct v3_vm_info * vm, void * private_data, int irq) {
263     struct io_apic_state * ioapic = (struct io_apic_state *)(private_data);  
264     struct redir_tbl_entry * irq_entry = NULL;
265
266     if (irq > 24) {
267         PrintDebug("ioapic %u: IRQ out of range of IO APIC\n", ioapic->ioapic_id.id);
268         return -1;
269     }
270
271     irq_entry = &(ioapic->redir_tbl[irq]);
272
273     if (irq_entry->mask == 0) {
274         struct v3_gen_ipi ipi;
275
276         PrintDebug("ioapic %u: IOAPIC Signalling APIC to raise INTR %d\n", 
277                    ioapic->ioapic_id.id, irq_entry->vec);
278
279
280         ipi.vector = irq_entry->vec;
281         ipi.mode = irq_entry->del_mode;
282         ipi.logical = irq_entry->dst_mode;
283         ipi.trigger_mode = irq_entry->trig_mode;
284         ipi.dst = irq_entry->dst_field;
285         ipi.dst_shorthand = 0;
286
287         // Need to add destination argument here...
288         if (v3_apic_send_ipi(vm, &ipi, ioapic->apic_dev_data) == -1) {
289             PrintError("Error sending IPI to apic %d\n", ipi.dst);
290             return -1;
291         }
292     }
293
294     return 0;
295 }
296
297 /* I don't know if we can do anything here.... */
298 static int ioapic_lower_irq(struct v3_vm_info * vm, void * private_data, int irq) {
299     return 0;
300 }
301
302 static struct intr_router_ops router_ops = {
303     .raise_intr = ioapic_raise_irq,
304     .lower_intr = ioapic_lower_irq, 
305 };
306
307
308
309
310 static int io_apic_free(struct io_apic_state * ioapic) {
311
312     // unregister intr router
313
314     // unhook memory
315
316     V3_Free(ioapic);
317
318     return 0;
319 }
320
321
322 static struct v3_device_ops dev_ops = {
323     .free = (int (*)(void *))io_apic_free,
324
325 };
326
327
328
329 static int ioapic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
330     struct vm_device * apic_dev = v3_find_dev(vm, v3_cfg_val(cfg, "apic"));
331     char * dev_id = v3_cfg_val(cfg, "ID");
332
333
334     PrintDebug("ioapic: Creating IO APIC\n");
335
336     struct io_apic_state * ioapic = (struct io_apic_state *)V3_Malloc(sizeof(struct io_apic_state));
337
338     ioapic->apic_dev_data = apic_dev;
339
340     struct vm_device * dev = v3_add_device(vm, dev_id, &dev_ops, ioapic);
341
342     if (dev == NULL) {
343         PrintError("ioapic: Could not attach device %s\n", dev_id);
344         V3_Free(ioapic);
345         return -1;
346     }
347
348     v3_register_intr_router(vm, &router_ops, ioapic);
349
350     init_ioapic_state(ioapic, vm->num_cores);
351
352     v3_hook_full_mem(vm, V3_MEM_CORE_ANY, ioapic->base_addr, ioapic->base_addr + PAGE_SIZE_4KB, 
353                      ioapic_read, ioapic_write, ioapic);
354   
355     return 0;
356 }
357
358
359 device_register("IOAPIC", ioapic_init)