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.


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