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.


7188f26b8e87f268ef8de744b240eb5a78f612f3
[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 #include <devices/io_apic.h>
21 #include <palacios/vmm.h>
22
23 #include <devices/apic.h>
24
25 /*
26 #ifndef 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) & 0xfffffffe;
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) & 0xfffffffe;
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(void * private_data) {
258   return 0;
259 }
260
261
262 static int ioapic_get_intr_number(void * private_data) {
263   return 0;
264 }
265
266 static int ioapic_begin_irq(void * private_data, int irq) {
267   return 0;
268 }
269
270 static int ioapic_raise_irq(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     PrintError("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(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(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 static int io_apic_init(struct vm_device * dev) {
305   struct guest_info * info = dev->vm;
306   struct io_apic_state * ioapic = (struct io_apic_state *)(dev->private_data);
307
308   v3_register_intr_controller(dev->vm, &intr_ops, dev);
309   init_ioapic_state(ioapic);
310
311   v3_hook_full_mem(info, ioapic->base_addr, ioapic->base_addr + PAGE_SIZE_4KB, 
312                    ioapic_read, ioapic_write, dev);
313   
314   return 0;
315 }
316
317
318 static int io_apic_deinit(struct vm_device * dev) {
319   //  struct guest_info * info = dev->vm;
320
321   return 0;
322 }
323
324
325 static struct vm_device_ops dev_ops = {
326   .init = io_apic_init, 
327   .deinit = io_apic_deinit,
328   .reset = NULL,
329   .start = NULL,
330   .stop = NULL,
331 };
332
333
334
335 struct vm_device * v3_create_io_apic(struct vm_device * apic) {
336   PrintDebug("Creating IO APIC\n");
337
338   struct io_apic_state * ioapic = (struct io_apic_state *)V3_Malloc(sizeof(struct io_apic_state));
339   ioapic->apic = apic;
340
341   struct vm_device * device = v3_create_device("IOAPIC", &dev_ops, ioapic);
342
343   return device;
344 }