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.


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