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.


Fixes to interrupt (IRQ and VIRQ) injection logic:
[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 V3_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
66 void v3_deinit_intr_controllers(struct guest_info * core) {
67     struct v3_intr_core_state * intr_state = &(core->intr_core_state);
68     struct intr_controller * ctrlr;
69     struct intr_controller * tmp;
70
71     // clear out any controllers that were left around
72     list_for_each_entry_safe(ctrlr, tmp, &(intr_state->controller_list), ctrl_node) {
73         v3_remove_intr_controller(core, ctrlr);
74     }
75
76     v3_lock_deinit(&(intr_state->irq_lock));
77
78 }
79
80
81 void v3_init_intr_routers(struct v3_vm_info * vm) {
82     
83     INIT_LIST_HEAD(&(vm->intr_routers.router_list));
84     
85     v3_lock_init(&(vm->intr_routers.irq_lock));
86
87     memset((uchar_t *)(vm->intr_routers.hooks), 0, sizeof(struct v3_irq_hook *) * 256);
88 }
89
90
91 void v3_deinit_intr_routers(struct v3_vm_info * vm) {
92     struct intr_router * rtr = NULL;
93     struct intr_router * tmp = NULL;
94
95     // clear out any controllers that were left around
96     list_for_each_entry_safe(rtr, tmp, &(vm->intr_routers.router_list), router_node) {
97         v3_remove_intr_router(vm, rtr);
98     }  
99
100     v3_lock_deinit(&(vm->intr_routers.irq_lock));
101 }
102
103 void * v3_register_intr_controller(struct guest_info * info, struct intr_ctrl_ops * ops, void * priv_data) {
104     struct intr_controller * ctrlr = (struct intr_controller *)V3_Malloc(sizeof(struct intr_controller));
105
106     if (!ctrlr) {
107         PrintError(info->vm_info, info, "Cannot allocate in registering an interrupt controller\n");
108         return NULL;
109     }
110
111     ctrlr->priv_data = priv_data;
112     ctrlr->ctrl_ops = ops;
113
114     list_add(&(ctrlr->ctrl_node), &(info->intr_core_state.controller_list));
115     
116     return (void *)ctrlr;
117 }
118
119 void v3_remove_intr_controller(struct guest_info * core, void * handle) {
120     struct v3_intr_core_state * intr_state = &(core->intr_core_state);
121     struct intr_controller * ctrlr = handle;
122     struct intr_controller * tmp = NULL;
123     int found = 0;
124
125     // search for the entry in the router list
126     list_for_each_entry(tmp, &(intr_state->controller_list), ctrl_node) {
127         if (tmp == ctrlr) {
128             found = 1;
129         }
130     }
131
132     if (found == 0) {
133         PrintError(core->vm_info, core, "Attempted to remove invalid interrupt controller handle\n");
134         return;
135     }
136
137     list_del(&(ctrlr->ctrl_node));
138     V3_Free(ctrlr);
139 }
140
141 void * v3_register_intr_router(struct v3_vm_info * vm, struct intr_router_ops * ops, void * priv_data) {
142     struct intr_router * router = (struct intr_router *)V3_Malloc(sizeof(struct intr_router));
143
144     if (!router) {
145         PrintError(vm, VCORE_NONE,"Cannot allocate in registering an interrupt router\n");
146         return NULL;
147     }
148
149     router->priv_data = priv_data;
150     router->router_ops = ops;
151
152     list_add(&(router->router_node), &(vm->intr_routers.router_list));
153     
154     return (void *)router;
155 }
156
157 void v3_remove_intr_router(struct v3_vm_info * vm, void * handle) {
158     struct intr_router * router = handle;
159     struct intr_router * tmp = NULL;
160     int found = 0;
161
162     // search for the entry in the router list
163     list_for_each_entry(tmp, &(vm->intr_routers.router_list), router_node) {
164         if (tmp == router) {
165             found = 1;
166         }
167     }
168
169     if (found == 0) {
170         PrintError(vm, VCORE_NONE, "Attempted to remove invalid interrupt router\n");
171         return;
172     }
173
174     list_del(&(router->router_node));
175     V3_Free(router);
176 }
177
178
179
180 static inline struct v3_irq_hook * get_irq_hook(struct v3_vm_info * vm, uint_t irq) {
181     V3_ASSERT(vm, VCORE_NONE,irq <= 256);
182     return vm->intr_routers.hooks[irq];
183 }
184
185
186 int v3_hook_irq(struct v3_vm_info * vm,
187                 uint_t irq,
188                 int (*handler)(struct v3_vm_info * vm, struct v3_interrupt * intr, void * priv_data),
189                 void  * priv_data) 
190 {
191     struct v3_irq_hook * hook = (struct v3_irq_hook *)V3_Malloc(sizeof(struct v3_irq_hook));
192
193
194     if (hook == NULL) { 
195         PrintError(vm, VCORE_NONE, "Cannot allocate when hooking an irq\n");
196         return -1; 
197     }
198
199     if (get_irq_hook(vm, irq) != NULL) {
200         PrintError(vm, VCORE_NONE, "IRQ %d already hooked\n", irq);
201         V3_Free(hook);
202         return -1;
203     }
204
205     hook->handler = handler;
206     hook->priv_data = priv_data;
207   
208     vm->intr_routers.hooks[irq] = hook;
209
210     if (V3_Hook_Interrupt(vm, irq)) { 
211         PrintError(vm, VCORE_NONE, "hook_irq: failed to hook irq %d\n", irq);
212         vm->intr_routers.hooks[irq] = NULL;
213         V3_Free(hook);
214         return -1;
215     } else {
216         PrintDebug(vm, VCORE_NONE, "hook_irq: hooked irq %d\n", irq);
217         return 0;
218     }
219 }
220
221
222
223 static int passthrough_irq_handler(struct v3_vm_info * vm, struct v3_interrupt * intr, void * priv_data) {
224     PrintDebug(vm, VCORE_NONE, "[passthrough_irq_handler] raise_irq=%d (guest=0x%p)\n", 
225                intr->irq, (void *)vm);
226
227     return v3_raise_irq(vm, intr->irq);
228 }
229
230 int v3_hook_passthrough_irq(struct v3_vm_info * vm, uint_t irq) {
231     int rc = v3_hook_irq(vm, irq, passthrough_irq_handler, NULL);
232
233     if (rc) { 
234         PrintError(vm, VCORE_NONE, "guest_irq_injection: failed to hook irq 0x%x (guest=0x%p)\n", irq, (void *)vm);
235         return -1;
236     } else {
237         PrintDebug(vm, VCORE_NONE, "guest_irq_injection: hooked irq 0x%x (guest=0x%p)\n", irq, (void *)vm);
238         return 0;
239     }
240 }
241
242
243
244
245
246 int v3_deliver_irq(struct v3_vm_info * vm, struct v3_interrupt * intr) {
247     PrintDebug(vm, VCORE_NONE, "v3_deliver_irq: irq=%d state=0x%p, \n", intr->irq, (void *)intr);
248   
249     struct v3_irq_hook * hook = get_irq_hook(vm, intr->irq);
250
251     if (hook == NULL) {
252         PrintError(vm, VCORE_NONE, "Attempting to deliver interrupt to non registered hook(irq=%d)\n", intr->irq);
253         return -1;
254     }
255   
256     return hook->handler(vm, intr, hook->priv_data);
257 }
258
259
260
261
262 int v3_raise_swintr (struct guest_info * core, uint8_t vector) {
263     struct v3_intr_core_state * intr_state = &(core->intr_core_state);
264
265     PrintDebug(core->vm_info, core, "Signaling software interrupt in v3_signal_swintr()\n");
266     PrintDebug(core->vm_info, core, "\tINT vector: %d\n", vector);
267     
268     intr_state->swintr_posted = 1;
269     intr_state->swintr_vector = vector;
270     return 0;
271 }
272
273
274
275 int v3_raise_virq(struct guest_info * info, int irq) {
276     struct v3_intr_core_state * intr_state = &(info->intr_core_state);
277     int major = irq / 8;
278     int minor = irq % 8;
279
280     intr_state->virq_map[major] |= (1 << minor);
281    
282     return 0;
283 }
284
285 int v3_lower_virq(struct guest_info * info, int irq) {
286     struct v3_intr_core_state * intr_state = &(info->intr_core_state);
287     int major = irq / 8;
288     int minor = irq % 8;
289
290     intr_state->virq_map[major] &= ~(1 << minor);
291
292     return 0;
293 }
294
295
296 int v3_lower_irq(struct v3_vm_info * vm, int irq) {
297     struct v3_irq irq_state;
298
299     irq_state.irq = irq;
300     irq_state.ack = NULL;
301     irq_state.private_data = NULL;
302
303     return v3_lower_acked_irq(vm, irq_state);
304 }
305
306 int v3_raise_irq(struct v3_vm_info * vm, int irq) {
307     struct v3_irq irq_state;
308
309     irq_state.irq = irq;
310     irq_state.ack = NULL;
311     irq_state.private_data = NULL;
312
313     return v3_raise_acked_irq(vm, irq_state);
314 }
315
316
317 int v3_raise_acked_irq(struct v3_vm_info * vm, struct v3_irq irq) {
318     struct intr_router * router = NULL;
319     struct v3_intr_routers * routers = &(vm->intr_routers);
320
321     //  PrintDebug(info->vm_info, info, "[v3_raise_irq (%d)]\n", irq);
322     addr_t irq_state = v3_lock_irqsave(routers->irq_lock);
323
324     list_for_each_entry(router, &(routers->router_list), router_node) {
325         router->router_ops->raise_intr(vm, router->priv_data, &irq);
326     }
327
328     v3_unlock_irqrestore(routers->irq_lock, irq_state);
329
330     return 0;
331 }
332
333
334 int v3_lower_acked_irq(struct v3_vm_info * vm, struct v3_irq irq) {
335     struct intr_router * router = NULL;
336     struct v3_intr_routers * routers = &(vm->intr_routers);
337
338     //    PrintDebug(info->vm_info, info, "[v3_lower_irq]\n");
339     addr_t irq_state = v3_lock_irqsave(routers->irq_lock);
340
341     list_for_each_entry(router, &(routers->router_list), router_node) {
342         router->router_ops->lower_intr(vm, router->priv_data, &irq);
343     }
344  
345     v3_unlock_irqrestore(routers->irq_lock, irq_state);
346
347     return 0;
348
349 }
350
351
352
353 void v3_clear_pending_intr(struct guest_info * core) {
354     struct v3_intr_core_state * intr_state = &(core->intr_core_state);
355
356     intr_state->irq_pending = 0;
357
358 }
359
360
361 v3_intr_type_t v3_intr_pending(struct guest_info * info) {
362     struct v3_intr_core_state * intr_state = &(info->intr_core_state);
363     struct intr_controller * ctrl = NULL;
364     int ret = V3_INVALID_INTR;
365     int i = 0;
366
367     //  PrintDebug(info->vm_info, info, "[intr_pending]\n");
368     addr_t irq_state = v3_lock_irqsave(intr_state->irq_lock);
369
370     // External IRQs have lowest priority
371     list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
372         if (ctrl->ctrl_ops->intr_pending(info, ctrl->priv_data)) {
373             ret = V3_EXTERNAL_IRQ;
374             break;
375         }
376     }   
377
378     // VIRQs have 2nd priority
379     for (i = 0; i < MAX_IRQ / 8; i++) {
380         if (intr_state->virq_map[i] != 0) {   
381             ret = V3_VIRTUAL_IRQ;
382             break;
383         }
384     }
385
386     /* SWINTRs have highest */
387     if (intr_state->swintr_posted == 1) {
388         ret = V3_SOFTWARE_INTR;
389     }
390
391     v3_unlock_irqrestore(intr_state->irq_lock, irq_state);
392
393     return ret;
394 }
395
396
397 int v3_get_intr(struct guest_info * info) {
398     struct v3_intr_core_state * intr_state = &(info->intr_core_state);
399     struct intr_controller * ctrl = NULL;
400     int ret = -1;
401     int i = 0;
402     int j = 0;
403     int found_virq=0;
404     int found_irq=0;
405
406     addr_t irq_state = v3_lock_irqsave(intr_state->irq_lock);    
407
408     // virqs have priority
409     for (i = 0; i < MAX_IRQ / 8; i++) {
410         if (intr_state->virq_map[i] != 0) {
411             for (j = 0; j < 8; j++) {
412                 if (intr_state->virq_map[i] & (1 << j)) {
413                     ret = (i * 8) + j;
414                     // need to be able to find virq 0
415                     found_virq=1;
416                     break;
417                 }
418             }
419             break;
420         }
421     }
422
423     if (!found_virq) {
424         list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
425             if (ctrl->ctrl_ops->intr_pending(info, ctrl->priv_data)) {
426                 int intr_num = ctrl->ctrl_ops->get_intr_number(info, ctrl->priv_data);
427                 
428                 if (intr_num >= 0) {
429                   //    PrintDebug(info->vm_info, info, "[get_intr_number] intr_number = %d\n", intr_num);
430                   ret = intr_num;
431                   found_irq=1;
432                   break;
433                 }
434
435             }
436         }
437     }
438
439     v3_unlock_irqrestore(intr_state->irq_lock, irq_state);
440
441     if (!found_virq && !found_irq) { 
442       PrintError(info->vm_info,info,"Strange... neither a VIRQ nor an IRQ was found...\n");
443     }
444
445     return ret;
446 }
447
448 /*
449 intr_type_t v3_get_intr_type(struct guest_info * info) {
450     struct v3_intr_state * intr_state = &(info->intr_state);
451     struct intr_controller * ctrl = NULL;
452     intr_type_t type = V3_INVALID_INTR;
453
454     addr_t irq_state = v3_lock_irqsave(intr_state->irq_lock);  
455
456     list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
457         if (ctrl->ctrl_ops->intr_pending(ctrl->priv_data) == 1) {
458             //PrintDebug(info->vm_info, info, "[get_intr_type] External_irq\n");
459             type = V3_EXTERNAL_IRQ;         
460             break;
461         }
462     }
463
464 #ifdef V3_CONFIG_DEBUG_INTERRUPTS
465     if (type == V3_INVALID_INTR) {
466         PrintError(info->vm_info, info, "[get_intr_type] Invalid_Intr\n");
467     }
468 #endif
469
470     v3_unlock_irqrestore(intr_state->irq_lock, irq_state);
471
472     return type;
473 }
474 */
475
476
477
478
479
480 int v3_injecting_intr(struct guest_info * info, uint_t intr_num, v3_intr_type_t type) {
481     struct v3_intr_core_state * intr_state = &(info->intr_core_state);
482
483     if (type == V3_EXTERNAL_IRQ) {
484         struct intr_controller * ctrl = NULL;
485
486         addr_t irq_state = v3_lock_irqsave(intr_state->irq_lock); 
487
488         //      PrintDebug(info->vm_info, info, "[injecting_intr] External_Irq with intr_num = %x\n", intr_num);
489         list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
490             ctrl->ctrl_ops->begin_irq(info, ctrl->priv_data, intr_num);
491         }
492
493         v3_unlock_irqrestore(intr_state->irq_lock, irq_state);
494     }
495
496     return 0;
497 }