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.


IO APIC implementation
[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 #define IO_APIC_BASE_ADDR 0xfec00000
27
28
29 #define IOAPIC_ID_REG 0x00
30 #define IOAPIC_VER_REG 0x01
31 #define IOAPIC_ARB_REG 0x02
32
33 #define IOAPIC_REDIR_BASE_REG 0x10
34
35 #define REDIR_LO_MASK  ~0x00005000
36
37 struct ioapic_reg_sel {
38   union {
39     uint32_t val;
40     struct {
41       uint_t reg_addr     : 8;
42       uint_t rsvd         : 24;
43     } __attribute__((packed));
44   } __attribute__((packed));
45 } __attribute__((packed));
46
47 struct ioapic_id_reg {
48   union {
49     uint32_t val;
50     struct {
51       uint_t rsvd1      : 24;
52       uint_t id         : 4;
53       uint_t rsvd2      : 4;
54     } __attribute__((packed));
55   } __attribute__((packed));
56 } __attribute__((packed));
57
58 struct ioapic_ver_reg {
59   union {
60     uint32_t val;
61     struct {
62       uint_t version    : 8;
63       uint_t rsvd1      : 8;
64       uint_t max_redir  : 8;
65       uint_t rsvd2      : 8;
66     } __attribute__((packed));
67   } __attribute__((packed));
68 } __attribute__((packed));
69
70
71 struct ioapic_arb_reg {
72   union {
73     uint32_t val;
74     struct {
75       uint_t rsvd1      : 24;
76       uint_t max_redir  : 4;
77       uint_t rsvd2      : 4;
78     } __attribute__((packed));
79   } __attribute__((packed));
80 } __attribute__((packed));
81
82
83 struct redir_tbl_entry {
84   union {
85     uint64_t val;
86     struct {
87       uint32_t lo;
88       uint32_t hi;
89     } __attribute__((packed));
90     struct {
91       uint_t vec        : 8;
92
93 #define FIXED        0x0
94 #define LOWEST_PRIOR 0x1
95 #define SMI          0x2
96 #define NMI          0x4
97 #define INIT         0x5
98 #define EXTINT       0x7
99       uint_t del_mode   : 3;
100
101 #define PHSYICAL_DST_MODE 0
102 #define LOGICAL_DST_MODE 1
103       uint_t dst_mode   : 1;
104       uint_t del_status : 1;
105
106 #define HIGH_ACTIVE 0
107 #define LOW_ACTIVE 1
108       uint_t intr_pol   : 1;
109       uint_t rem_irr    : 1;
110       uint_t trig_mode  : 1;
111       uint_t mask       : 1;
112       uint64_t rsvd     : 39;
113       uint_t dst_field  : 8;
114     } __attribute__((packed));
115   } __attribute__((packed));
116 } __attribute__((packed));
117
118
119
120 struct io_apic_state {
121   addr_t base_addr;
122
123   uint32_t index_reg;
124
125   struct ioapic_id_reg ioapic_id;
126   struct ioapic_ver_reg ioapic_ver;
127   struct ioapic_arb_reg ioapic_arb_id;
128   
129   struct redir_tbl_entry redir_tbl[24];
130
131   // This is a temporary method of communication between the IOAPIC and the LAPIC
132   struct vm_device * apic;
133   
134 };
135
136
137 static void init_ioapic_state(struct io_apic_state * ioapic) {
138   int i = 0;
139   ioapic->base_addr = IO_APIC_BASE_ADDR;
140   ioapic->index_reg = 0;
141
142   ioapic->ioapic_id.val = 0x00000000;
143   ioapic->ioapic_ver.val = 0x00170011;
144   ioapic->ioapic_arb_id.val = 0x00000000;
145
146   for (i = 0; i < 24; i++) {
147     ioapic->redir_tbl[i].val = 0x0001000000000000LL;
148     // Mask all interrupts until they are enabled....
149     ioapic->redir_tbl[i].mask = 1;
150   }
151 }
152
153
154 static int ioapic_read(addr_t guest_addr, void * dst, uint_t length, void * priv_data) {
155   struct vm_device * dev = (struct vm_device *)priv_data;
156   struct io_apic_state * ioapic = (struct io_apic_state *)(dev->private_data);
157   uint32_t reg_tgt = guest_addr - ioapic->base_addr;
158   uint32_t * op_val = (uint32_t *)dst;
159
160   PrintDebug("IOAPIC Read at %p\n", (void *)guest_addr);
161
162   if (reg_tgt == 0x00) {
163     *op_val = ioapic->index_reg;
164   } else if (reg_tgt == 0x10) {
165     // IOWIN register
166     switch (ioapic->index_reg) {
167     case IOAPIC_ID_REG:
168       *op_val = ioapic->ioapic_id.val;
169       break;
170     case IOAPIC_VER_REG:
171       *op_val = ioapic->ioapic_ver.val;
172       break;
173     case IOAPIC_ARB_REG:
174       *op_val = ioapic->ioapic_arb_id.val;
175       break;
176     default:
177       {
178         uint_t redir_index = (ioapic->index_reg - IOAPIC_REDIR_BASE_REG) % 2;
179         uint_t hi_val = (ioapic->index_reg - IOAPIC_REDIR_BASE_REG) % 1;
180
181         if (redir_index > 0x3f) {
182           PrintError("Invalid redirection table entry %x\n", (uint32_t)redir_index);
183           return -1;
184         }
185         if (hi_val) {
186           *op_val = ioapic->redir_tbl[redir_index].hi;
187         } else {
188           *op_val = ioapic->redir_tbl[redir_index].lo;
189         }
190       }
191     }
192   }
193
194   return length;
195 }
196
197
198 static int ioapic_write(addr_t guest_addr, void * src, uint_t length, void * priv_data) {
199   struct vm_device * dev = (struct vm_device *)priv_data;
200   struct io_apic_state * ioapic = (struct io_apic_state *)(dev->private_data);
201   uint32_t reg_tgt = guest_addr - ioapic->base_addr;
202   uint32_t op_val = *(uint32_t *)src;
203
204   PrintDebug("IOAPIC Write at %p (val = %d)\n", (void *)guest_addr, *(uint32_t *)src);
205
206   if (reg_tgt == 0x00) {
207     ioapic->index_reg = op_val;
208   } else if (reg_tgt == 0x10) {
209     // IOWIN register
210     switch (ioapic->index_reg) {
211     case IOAPIC_ID_REG:
212       ioapic->ioapic_id.val = op_val;
213       break;
214     case IOAPIC_VER_REG:
215       // GPF/PageFault/Ignore?
216       PrintError("Writing to read only IOAPIC register\n");
217       return -1;
218     case IOAPIC_ARB_REG:
219       ioapic->ioapic_arb_id.val = op_val;
220       break;
221     default:
222       {
223         uint_t redir_index = (ioapic->index_reg - IOAPIC_REDIR_BASE_REG) % 2;
224         uint_t hi_val = (ioapic->index_reg - IOAPIC_REDIR_BASE_REG) % 1;
225
226         if (redir_index > 0x3f) {
227           PrintError("Invalid redirection table entry %x\n", (uint32_t)redir_index);
228           return -1;
229         }
230         if (hi_val) {
231           ioapic->redir_tbl[redir_index].hi = op_val;
232         } else {
233           op_val &= REDIR_LO_MASK;
234           ioapic->redir_tbl[redir_index].lo &= ~REDIR_LO_MASK;
235           ioapic->redir_tbl[redir_index].lo |= op_val;
236         }
237       }
238     }
239   }
240
241   return length;
242 }
243
244 /* Interrupt controller functions */
245 static int ioapic_intr_pending(void * private_data) {
246   return 0;
247 }
248
249
250 static int ioapic_get_intr_number(void * private_data) {
251   return 0;
252 }
253
254 static int ioapic_begin_irq(void * private_data, int irq) {
255   return 0;
256 }
257
258 static int ioapic_raise_irq(void * private_data, int irq) {
259   struct vm_device * dev = (struct vm_device *)private_data;
260   struct io_apic_state * ioapic = (struct io_apic_state *)(dev->private_data);  
261   struct redir_tbl_entry * irq_entry = NULL;
262
263   if (irq > 24) {
264     PrintError("IRQ out of range of IO APIC\n");
265     return -1;
266   }
267
268   irq_entry = &(ioapic->redir_tbl[irq]);
269
270   if (irq_entry->mask == 0) {
271     v3_apic_raise_intr(ioapic->apic, irq_entry->vec);
272   }
273
274   return 0;
275 }
276
277 /* I don't know if we can do anything here.... */
278 static int ioapic_lower_irq(void * private_data, int irq) {
279   return 0;
280 }
281
282 static struct intr_ctrl_ops intr_ops = {
283   .intr_pending = ioapic_intr_pending,
284   .get_intr_number = ioapic_get_intr_number,
285   .raise_intr = ioapic_raise_irq,
286   .begin_irq = ioapic_begin_irq,
287   .lower_intr = ioapic_lower_irq, 
288 };
289
290
291 static int io_apic_init(struct vm_device * dev) {
292   struct guest_info * info = dev->vm;
293   struct io_apic_state * ioapic = (struct io_apic_state *)(dev->private_data);
294
295   v3_register_intr_controller(dev->vm, &intr_ops, dev);
296   init_ioapic_state(ioapic);
297
298   v3_hook_full_mem(info, ioapic->base_addr, ioapic->base_addr + PAGE_SIZE_4KB, 
299                    ioapic_read, ioapic_write, dev);
300   
301   return 0;
302 }
303
304
305 static int io_apic_deinit(struct vm_device * dev) {
306   //  struct guest_info * info = dev->vm;
307
308   return 0;
309 }
310
311
312 static struct vm_device_ops dev_ops = {
313   .init = io_apic_init, 
314   .deinit = io_apic_deinit,
315   .reset = NULL,
316   .start = NULL,
317   .stop = NULL,
318 };
319
320
321
322 struct vm_device * v3_create_io_apic(struct vm_device * apic) {
323   PrintDebug("Creating IO APIC\n");
324
325   struct io_apic_state * ioapic = (struct io_apic_state *)V3_Malloc(sizeof(struct io_apic_state));
326   ioapic->apic = apic;
327
328   struct vm_device * device = v3_create_device("IOAPIC", &dev_ops, ioapic);
329
330   return device;
331 }