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.


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