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.


Fix interrupt injection bug due to caching irq vectors after vector mappings have...
[palacios.git] / palacios / src / palacios / vmm_intr.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_intr.h>
22 #include <palacios/vmm.h>
23
24 #include <palacios/vm_guest.h>
25 #include <palacios/vmm_ctrl_regs.h>
26
27 #include <palacios/vmm_lock.h>
28
29 #ifndef CONFIG_DEBUG_INTERRUPTS
30 #undef PrintDebug
31 #define PrintDebug(fmt, args...)
32 #endif
33
34
35
36
37 struct intr_controller {
38     struct intr_ctrl_ops * ctrl_ops;
39     
40     void * priv_data;
41     struct list_head ctrl_node;
42 };
43
44
45 struct intr_router {
46     struct intr_router_ops * router_ops;
47
48     void * priv_data;
49     struct list_head router_node;
50
51 };
52
53 void v3_init_intr_controllers(struct guest_info * info) {
54     struct v3_intr_core_state * intr_state = &(info->intr_core_state);
55
56     intr_state->irq_pending = 0;
57     intr_state->irq_started = 0;
58     intr_state->irq_vector = 0;
59
60     v3_lock_init(&(intr_state->irq_lock));
61
62     INIT_LIST_HEAD(&(intr_state->controller_list));
63 }
64
65 void v3_init_intr_routers(struct v3_vm_info * vm) {
66     
67     INIT_LIST_HEAD(&(vm->intr_routers.router_list));
68     
69     v3_lock_init(&(vm->intr_routers.irq_lock));
70
71     memset((uchar_t *)(vm->intr_routers.hooks), 0, sizeof(struct v3_irq_hook *) * 256);
72 }
73
74
75 int v3_register_intr_controller(struct guest_info * info, struct intr_ctrl_ops * ops, void * priv_data) {
76     struct intr_controller * ctrlr = (struct intr_controller *)V3_Malloc(sizeof(struct intr_controller));
77
78     ctrlr->priv_data = priv_data;
79     ctrlr->ctrl_ops = ops;
80
81     list_add(&(ctrlr->ctrl_node), &(info->intr_core_state.controller_list));
82     
83     return 0;
84 }
85
86 int v3_register_intr_router(struct v3_vm_info * vm, struct intr_router_ops * ops, void * priv_data) {
87     struct intr_router * router = (struct intr_router *)V3_Malloc(sizeof(struct intr_router));
88
89     router->priv_data = priv_data;
90     router->router_ops = ops;
91
92     list_add(&(router->router_node), &(vm->intr_routers.router_list));
93     
94     return 0;
95 }
96
97
98
99 static inline struct v3_irq_hook * get_irq_hook(struct v3_vm_info * vm, uint_t irq) {
100     V3_ASSERT(irq <= 256);
101     return vm->intr_routers.hooks[irq];
102 }
103
104
105 int v3_hook_irq(struct v3_vm_info * vm,
106                 uint_t irq,
107                 int (*handler)(struct v3_vm_info * vm, struct v3_interrupt * intr, void * priv_data),
108                 void  * priv_data) 
109 {
110     struct v3_irq_hook * hook = (struct v3_irq_hook *)V3_Malloc(sizeof(struct v3_irq_hook));
111
112     if (hook == NULL) { 
113         return -1; 
114     }
115
116     if (get_irq_hook(vm, irq) != NULL) {
117         PrintError("IRQ %d already hooked\n", irq);
118         return -1;
119     }
120
121     hook->handler = handler;
122     hook->priv_data = priv_data;
123   
124     vm->intr_routers.hooks[irq] = hook;
125
126     if (V3_Hook_Interrupt(vm, irq)) { 
127         PrintError("hook_irq: failed to hook irq %d\n", irq);
128         return -1;
129     } else {
130         PrintDebug("hook_irq: hooked irq %d\n", irq);
131         return 0;
132     }
133 }
134
135
136
137 static int passthrough_irq_handler(struct v3_vm_info * vm, struct v3_interrupt * intr, void * priv_data) {
138     PrintDebug("[passthrough_irq_handler] raise_irq=%d (guest=0x%p)\n", 
139                intr->irq, (void *)vm);
140
141     return v3_raise_irq(vm, intr->irq);
142 }
143
144 int v3_hook_passthrough_irq(struct v3_vm_info * vm, uint_t irq) {
145     int rc = v3_hook_irq(vm, irq, passthrough_irq_handler, NULL);
146
147     if (rc) { 
148         PrintError("guest_irq_injection: failed to hook irq 0x%x (guest=0x%p)\n", irq, (void *)vm);
149         return -1;
150     } else {
151         PrintDebug("guest_irq_injection: hooked irq 0x%x (guest=0x%p)\n", irq, (void *)vm);
152         return 0;
153     }
154 }
155
156
157
158
159
160 int v3_deliver_irq(struct v3_vm_info * vm, struct v3_interrupt * intr) {
161     PrintDebug("v3_deliver_irq: irq=%d state=0x%p, \n", intr->irq, (void *)intr);
162   
163     struct v3_irq_hook * hook = get_irq_hook(vm, intr->irq);
164
165     if (hook == NULL) {
166         PrintError("Attempting to deliver interrupt to non registered hook(irq=%d)\n", intr->irq);
167         return -1;
168     }
169   
170     return hook->handler(vm, intr, hook->priv_data);
171 }
172
173
174
175
176
177 int v3_raise_virq(struct guest_info * info, int irq) {
178     struct v3_intr_core_state * intr_state = &(info->intr_core_state);
179     int major = irq / 8;
180     int minor = irq % 8;
181
182     intr_state->virq_map[major] |= (1 << minor);
183    
184     return 0;
185 }
186
187 int v3_lower_virq(struct guest_info * info, int irq) {
188     struct v3_intr_core_state * intr_state = &(info->intr_core_state);
189     int major = irq / 8;
190     int minor = irq % 8;
191
192     intr_state->virq_map[major] &= ~(1 << minor);
193
194     return 0;
195 }
196
197
198 int v3_lower_irq(struct v3_vm_info * vm, int irq) {
199     struct intr_router * router = NULL;
200     struct v3_intr_routers * routers = &(vm->intr_routers);
201
202     //    PrintDebug("[v3_lower_irq]\n");
203     addr_t irq_state = v3_lock_irqsave(routers->irq_lock);
204
205     list_for_each_entry(router, &(routers->router_list), router_node) {
206         router->router_ops->lower_intr(vm, router->priv_data, irq);
207     }
208  
209     v3_unlock_irqrestore(routers->irq_lock, irq_state);
210
211     return 0;
212 }
213
214 int v3_raise_irq(struct v3_vm_info * vm, int irq) {
215     struct intr_router * router = NULL;
216     struct v3_intr_routers * routers = &(vm->intr_routers);
217
218     //  PrintDebug("[v3_raise_irq (%d)]\n", irq);
219     addr_t irq_state = v3_lock_irqsave(routers->irq_lock);
220
221     list_for_each_entry(router, &(routers->router_list), router_node) {
222         router->router_ops->raise_intr(vm, router->priv_data, irq);
223     }
224
225     v3_unlock_irqrestore(routers->irq_lock, irq_state);
226
227     return 0;
228 }
229
230
231 void v3_clear_pending_intr(struct guest_info * core) {
232     struct v3_intr_core_state * intr_state = &(core->intr_core_state);
233
234     intr_state->irq_pending = 0;
235
236 }
237
238
239 v3_intr_type_t v3_intr_pending(struct guest_info * info) {
240     struct v3_intr_core_state * intr_state = &(info->intr_core_state);
241     struct intr_controller * ctrl = NULL;
242     int ret = V3_INVALID_INTR;
243     int i = 0;
244
245     //  PrintDebug("[intr_pending]\n");
246     addr_t irq_state = v3_lock_irqsave(intr_state->irq_lock);
247
248     // VIRQs have priority
249     for (i = 0; i < MAX_IRQ / 8; i++) {
250         if (intr_state->virq_map[i] != 0) {   
251             ret = V3_VIRTUAL_IRQ;
252             break;
253         }
254     }
255
256     if (ret == V3_INVALID_INTR) {
257         list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
258             if (ctrl->ctrl_ops->intr_pending(info, ctrl->priv_data) == 1) {
259                 ret = V3_EXTERNAL_IRQ;
260                 break;
261             }
262         }
263     }
264
265     v3_unlock_irqrestore(intr_state->irq_lock, irq_state);
266
267     return ret;
268 }
269
270
271 uint32_t v3_get_intr(struct guest_info * info) {
272     struct v3_intr_core_state * intr_state = &(info->intr_core_state);
273     struct intr_controller * ctrl = NULL;
274     uint_t ret = 0;
275     int i = 0;
276     int j = 0;
277
278     addr_t irq_state = v3_lock_irqsave(intr_state->irq_lock);    
279
280     // virqs have priority
281     for (i = 0; i < MAX_IRQ / 8; i++) {
282         if (intr_state->virq_map[i] != 0) {
283             for (j = 0; j < 8; j++) {
284                 if (intr_state->virq_map[i] & (1 << j)) {
285                     ret = (i * 8) + j;
286                     break;
287                 }
288             }
289             break;
290         }
291     }
292
293     if (!ret) {
294         list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
295             if (ctrl->ctrl_ops->intr_pending(info, ctrl->priv_data)) {
296                 uint_t intr_num = ctrl->ctrl_ops->get_intr_number(info, ctrl->priv_data);
297                 
298                 //      PrintDebug("[get_intr_number] intr_number = %d\n", intr_num);
299                 ret = intr_num;
300                 break;
301             }
302         }
303     }
304
305     v3_unlock_irqrestore(intr_state->irq_lock, irq_state);
306
307     return ret;
308 }
309
310 /*
311 intr_type_t v3_get_intr_type(struct guest_info * info) {
312     struct v3_intr_state * intr_state = &(info->intr_state);
313     struct intr_controller * ctrl = NULL;
314     intr_type_t type = V3_INVALID_INTR;
315
316     addr_t irq_state = v3_lock_irqsave(intr_state->irq_lock);  
317
318     list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
319         if (ctrl->ctrl_ops->intr_pending(ctrl->priv_data) == 1) {
320             //PrintDebug("[get_intr_type] External_irq\n");
321             type = V3_EXTERNAL_IRQ;         
322             break;
323         }
324     }
325
326 #ifdef CONFIG_DEBUG_INTERRUPTS
327     if (type == V3_INVALID_INTR) {
328         PrintError("[get_intr_type] Invalid_Intr\n");
329     }
330 #endif
331
332     v3_unlock_irqrestore(intr_state->irq_lock, irq_state);
333
334     return type;
335 }
336 */
337
338
339
340
341
342 int v3_injecting_intr(struct guest_info * info, uint_t intr_num, v3_intr_type_t type) {
343     struct v3_intr_core_state * intr_state = &(info->intr_core_state);
344
345     if (type == V3_EXTERNAL_IRQ) {
346         struct intr_controller * ctrl = NULL;
347
348         addr_t irq_state = v3_lock_irqsave(intr_state->irq_lock); 
349
350         //      PrintDebug("[injecting_intr] External_Irq with intr_num = %x\n", intr_num);
351         list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
352             ctrl->ctrl_ops->begin_irq(info, ctrl->priv_data, intr_num);
353         }
354
355         v3_unlock_irqrestore(intr_state->irq_lock, irq_state);
356     }
357
358     return 0;
359 }