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.


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