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.


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