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.


cosmetic changes
[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 #include <palacios/vm_guest_mem.h>
29 #include <palacios/vmm_decoder.h>
30
31 #ifndef CONFIG_DEBUG_INTERRUPTS
32 #undef PrintDebug
33 #define PrintDebug(fmt, args...)
34 #endif
35
36
37
38 struct intr_controller {
39     struct intr_ctrl_ops * ctrl_ops;
40     
41     void * priv_data;
42     struct list_head ctrl_node;
43 };
44
45
46 struct intr_router {
47     struct intr_router_ops * router_ops;
48
49     void * priv_data;
50     struct list_head router_node;
51
52 };
53
54
55
56 void v3_init_intr_controllers(struct guest_info * info) {
57     struct v3_intr_core_state * intr_state = &(info->intr_core_state);
58
59     intr_state->irq_pending = 0;
60     intr_state->irq_started = 0;
61     intr_state->irq_vector = 0;
62
63     v3_lock_init(&(intr_state->irq_lock));
64
65     INIT_LIST_HEAD(&(intr_state->controller_list));
66 }
67
68
69 void v3_deinit_intr_controllers(struct guest_info * core) {
70     struct v3_intr_core_state * intr_state = &(core->intr_core_state);
71     struct intr_controller * ctrlr;
72     struct intr_controller * tmp;
73
74     // clear out any controllers that were left around
75     list_for_each_entry_safe(ctrlr, tmp, &(intr_state->controller_list), ctrl_node) {
76         v3_remove_intr_controller(core, ctrlr);
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
101
102 void * v3_register_intr_controller(struct guest_info * info, struct intr_ctrl_ops * ops, void * priv_data) {
103     struct intr_controller * ctrlr = (struct intr_controller *)V3_Malloc(sizeof(struct intr_controller));
104
105     ctrlr->priv_data = priv_data;
106     ctrlr->ctrl_ops = ops;
107
108     list_add(&(ctrlr->ctrl_node), &(info->intr_core_state.controller_list));
109     
110     return (void *)ctrlr;
111 }
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("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
137 void * v3_register_intr_router(struct v3_vm_info * vm, struct intr_router_ops * ops, void * priv_data) {
138     struct intr_router * router = (struct intr_router *)V3_Malloc(sizeof(struct intr_router));
139
140     router->priv_data = priv_data;
141     router->router_ops = ops;
142
143     list_add(&(router->router_node), &(vm->intr_routers.router_list));
144     
145     return (void *)router;
146 }
147
148
149 void v3_remove_intr_router(struct v3_vm_info * vm, void * handle) {
150     struct intr_router * router = handle;
151     struct intr_router * tmp = NULL;
152     int found = 0;
153
154     // search for the entry in the router list
155     list_for_each_entry(tmp, &(vm->intr_routers.router_list), router_node) {
156         if (tmp == router) {
157             found = 1;
158         }
159     }
160
161     if (found == 0) {
162         PrintError("Attempted to remove invalid interrupt router\n");
163         return;
164     }
165
166     list_del(&(router->router_node));
167     V3_Free(router);
168 }
169
170
171 static inline struct v3_irq_hook * get_irq_hook(struct v3_vm_info * vm, uint8_t irq) {
172     return vm->intr_routers.hooks[irq];
173 }
174
175
176 int v3_hook_irq(struct v3_vm_info * vm,
177                 uint_t irq,
178                 int (*handler)(struct v3_vm_info * vm, struct v3_interrupt * intr, void * priv_data),
179                 void  * priv_data) 
180 {
181     struct v3_irq_hook * hook = (struct v3_irq_hook *)V3_Malloc(sizeof(struct v3_irq_hook));
182
183     if (hook == NULL) { 
184         return -1; 
185     }
186
187     if (get_irq_hook(vm, irq) != NULL) {
188         PrintError("IRQ %d already hooked\n", irq);
189         return -1;
190     }
191
192     hook->handler = handler;
193     hook->priv_data = priv_data;
194   
195     vm->intr_routers.hooks[irq] = hook;
196
197     if (V3_Hook_Interrupt(vm, irq)) { 
198         PrintError("hook_irq: failed to hook irq %d\n", irq);
199         return -1;
200     } else {
201         PrintDebug("hook_irq: hooked irq %d\n", irq);
202         return 0;
203     }
204 }
205
206
207 static int passthrough_irq_handler(struct v3_vm_info * vm, struct v3_interrupt * intr, void * priv_data) {
208     PrintDebug("[passthrough_irq_handler] raise_irq=%d (guest=0x%p)\n", 
209                intr->irq, (void *)vm);
210
211     return v3_raise_irq(vm, intr->irq);
212 }
213
214
215 int v3_hook_passthrough_irq(struct v3_vm_info * vm, uint_t irq) {
216     int rc = v3_hook_irq(vm, irq, passthrough_irq_handler, NULL);
217
218     if (rc) { 
219         PrintError("guest_irq_injection: failed to hook irq 0x%x (guest=0x%p)\n", irq, (void *)vm);
220         return -1;
221     } else {
222         PrintDebug("guest_irq_injection: hooked irq 0x%x (guest=0x%p)\n", irq, (void *)vm);
223         return 0;
224     }
225 }
226
227
228 int v3_deliver_irq(struct v3_vm_info * vm, struct v3_interrupt * intr) {
229     PrintDebug("v3_deliver_irq: irq=%d state=0x%p, \n", intr->irq, (void *)intr);
230   
231     struct v3_irq_hook * hook = get_irq_hook(vm, intr->irq);
232
233     if (hook == NULL) {
234         PrintError("Attempting to deliver interrupt to non registered hook(irq=%d)\n", intr->irq);
235         return -1;
236     }
237   
238     return hook->handler(vm, intr, hook->priv_data);
239 }
240
241
242 int v3_raise_virq(struct guest_info * info, int irq) {
243     struct v3_intr_core_state * intr_state = &(info->intr_core_state);
244     int major = irq / 8;
245     int minor = irq % 8;
246
247     intr_state->virq_map[major] |= (1 << minor);
248    
249     return 0;
250 }
251
252
253 int v3_lower_virq(struct guest_info * info, int irq) {
254     struct v3_intr_core_state * intr_state = &(info->intr_core_state);
255     int major = irq / 8;
256     int minor = irq % 8;
257
258     intr_state->virq_map[major] &= ~(1 << minor);
259
260     return 0;
261 }
262
263
264 int v3_lower_irq(struct v3_vm_info * vm, int irq) {
265     struct intr_router * router = NULL;
266     struct v3_intr_routers * routers = &(vm->intr_routers);
267
268     //    PrintDebug("[v3_lower_irq]\n");
269     addr_t irq_state = v3_lock_irqsave(routers->irq_lock);
270
271     list_for_each_entry(router, &(routers->router_list), router_node) {
272         router->router_ops->lower_intr(vm, router->priv_data, irq);
273     }
274  
275     v3_unlock_irqrestore(routers->irq_lock, irq_state);
276
277     return 0;
278 }
279
280
281 int v3_raise_irq(struct v3_vm_info * vm, int irq) {
282     struct intr_router * router = NULL;
283     struct v3_intr_routers * routers = &(vm->intr_routers);
284
285     //  PrintDebug("[v3_raise_irq (%d)]\n", irq);
286     addr_t irq_state = v3_lock_irqsave(routers->irq_lock);
287
288     list_for_each_entry(router, &(routers->router_list), router_node) {
289         router->router_ops->raise_intr(vm, router->priv_data, irq);
290     }
291
292     v3_unlock_irqrestore(routers->irq_lock, irq_state);
293
294     return 0;
295 }
296
297
298 int v3_signal_swintr(struct guest_info * core, int vector) {
299     struct v3_intr_core_state * intr_state = &(core->intr_core_state);
300
301     PrintDebug("Signaling software interrupt in vmm_intr.c\n");
302     PrintDebug("\tINT vector: %d\n", vector);
303     
304     intr_state->swintr_posted = 1;
305     intr_state->swintr_vector = vector;
306     return 0;
307 }
308
309
310 int v3_handle_swintr(struct guest_info * core) {
311
312     int ret = 0;
313     void * instr_ptr = NULL;
314     struct x86_instr instr;
315
316     if (core->mem_mode == PHYSICAL_MEM) { 
317         ret = v3_gpa_to_hva(core, get_addr_linear(core, core->rip, &(core->segments.cs)), (addr_t *)&instr_ptr);
318     } else { 
319         ret = v3_gva_to_hva(core, get_addr_linear(core, core->rip, &(core->segments.cs)), (addr_t *)&instr_ptr);
320     }
321     
322     if (ret == -1) {
323         PrintError("V3 SWintr Handler: Could not translate Instruction Address (%p)\n", (void *)core->rip);
324         return -1;
325     }
326
327     if (v3_decode(core, (addr_t)instr_ptr, &instr) == -1) {
328         PrintError("V3 SWintr Handler: Decoding Error\n");
329         return -1;
330     }
331
332     uint8_t vector = instr.dst_operand.operand;
333
334     struct v3_swintr_hook * hook = core->intr_core_state.swintr_hooks[vector];
335     if (hook == NULL) {
336 #ifdef CONFIG_SWINTR_PASSTHROUGH
337         if (v3_hook_passthrough_swintr(core, vector) == -1) {
338             PrintDebug("V3 SWintr Handler: Error hooking passthrough swintr\n");
339             return -1;
340         }
341         hook = core->intr_core_state.swintr_hooks[vector];
342 #else
343         core->rip += instr.instr_length;
344         return v3_signal_swintr(core, vector);
345 #endif
346     }
347
348     ret = hook->handler(core, vector, NULL);
349     if (ret == -1) {
350         PrintDebug("V3 SWintr Handler: Error in swintr hook\n");
351         return -1;
352     }
353
354     /* at some point we may need to prioritize swints 
355        so that they finish in time for the next
356        instruction */
357     core->rip += instr.instr_length;
358     return v3_signal_swintr(core, vector);
359 }
360
361
362 static inline struct v3_swintr_hook * get_swintr_hook(struct guest_info * core, uint8_t vector) {
363     return core->intr_core_state.swintr_hooks[vector];
364 }
365
366
367 int v3_hook_swintr(struct guest_info * core,
368         uint8_t vector,
369         int (*handler)(struct guest_info * core, uint8_t vector, void * priv_data),
370         void * priv_data) 
371 {
372
373     struct v3_swintr_hook * hook = (struct v3_swintr_hook *)V3_Malloc(sizeof(struct v3_swintr_hook));
374
375     if (hook == NULL) { 
376         return -1; 
377     }
378
379     if (get_swintr_hook(core, vector) != NULL) {
380         PrintError("SWINT %d already hooked\n", vector);
381         return -1;
382     }
383
384     hook->handler = handler;
385     hook->priv_data = priv_data;
386   
387     core->intr_core_state.swintr_hooks[vector] = hook;
388
389     return 0;
390 }
391     
392
393 static int passthrough_swintr_handler(struct guest_info * core, uint8_t vector, void * priv_data) {
394
395     PrintDebug("[passthrough_swint_handler] INT vector=%d (guest=0x%p)\n", 
396                vector, (void *)core);
397
398     return 0;
399 }
400
401
402 int v3_hook_passthrough_swintr(struct guest_info * core, uint8_t vector) {
403
404     int rc = v3_hook_swintr(core, vector, passthrough_swintr_handler, NULL);
405
406     if (rc) { 
407         PrintError("guest_swintr_injection: failed to hook swint 0x%x (guest=0x%p)\n", vector, (void *)core);
408         return -1;
409     } else {
410         PrintDebug("guest_swintr_injection: hooked swint 0x%x (guest=0x%p)\n", vector, (void *)core);
411         return 0;
412     }
413
414     /* shouldn't get here */
415     return 0;
416 }
417
418
419 void v3_clear_pending_intr(struct guest_info * core) {
420     struct v3_intr_core_state * intr_state = &(core->intr_core_state);
421
422     intr_state->irq_pending = 0;
423 }
424
425
426 v3_intr_type_t v3_intr_pending(struct guest_info * info) {
427     struct v3_intr_core_state * intr_state = &(info->intr_core_state);
428     struct intr_controller * ctrl = NULL;
429     int ret = V3_INVALID_INTR;
430     int i = 0;
431
432     //  PrintDebug("[intr_pending]\n");
433     addr_t irq_state = v3_lock_irqsave(intr_state->irq_lock);
434
435     // VIRQs have priority
436     for (i = 0; i < MAX_IRQ / 8; i++) {
437         if (intr_state->virq_map[i] != 0) {   
438             ret = V3_VIRTUAL_IRQ;
439             break;
440         }
441     }
442
443     if (ret == V3_INVALID_INTR) {
444         list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
445             if (ctrl->ctrl_ops->intr_pending(info, ctrl->priv_data) == 1) {
446                 ret = V3_EXTERNAL_IRQ;
447                 break;
448             }
449         }
450     }
451
452     // KCH: added for SWintr injection
453     if (intr_state->swintr_posted == 1) {
454         ret = V3_SOFTWARE_INTR;
455     }
456         
457     v3_unlock_irqrestore(intr_state->irq_lock, irq_state);
458
459     return ret;
460 }
461
462
463 uint32_t v3_get_intr(struct guest_info * info) {
464     struct v3_intr_core_state * intr_state = &(info->intr_core_state);
465     struct intr_controller * ctrl = NULL;
466     uint_t ret = 0;
467     int i = 0;
468     int j = 0;
469
470     addr_t irq_state = v3_lock_irqsave(intr_state->irq_lock);    
471
472     // virqs have priority
473     for (i = 0; i < MAX_IRQ / 8; i++) {
474         if (intr_state->virq_map[i] != 0) {
475             for (j = 0; j < 8; j++) {
476                 if (intr_state->virq_map[i] & (1 << j)) {
477                     ret = (i * 8) + j;
478                     break;
479                 }
480             }
481             break;
482         }
483     }
484
485     if (!ret) {
486         list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
487             if (ctrl->ctrl_ops->intr_pending(info, ctrl->priv_data)) {
488                 uint_t intr_num = ctrl->ctrl_ops->get_intr_number(info, ctrl->priv_data);
489                 
490                 //      PrintDebug("[get_intr_number] intr_number = %d\n", intr_num);
491                 ret = intr_num;
492                 break;
493             }
494         }
495     }
496
497     v3_unlock_irqrestore(intr_state->irq_lock, irq_state);
498
499     return ret;
500 }
501
502 /*
503 intr_type_t v3_get_intr_type(struct guest_info * info) {
504     struct v3_intr_state * intr_state = &(info->intr_state);
505     struct intr_controller * ctrl = NULL;
506     intr_type_t type = V3_INVALID_INTR;
507
508     addr_t irq_state = v3_lock_irqsave(intr_state->irq_lock);  
509
510     list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
511         if (ctrl->ctrl_ops->intr_pending(ctrl->priv_data) == 1) {
512             //PrintDebug("[get_intr_type] External_irq\n");
513             type = V3_EXTERNAL_IRQ;         
514             break;
515         }
516     }
517
518 #ifdef CONFIG_DEBUG_INTERRUPTS
519     if (type == V3_INVALID_INTR) {
520         PrintError("[get_intr_type] Invalid_Intr\n");
521     }
522 #endif
523
524     v3_unlock_irqrestore(intr_state->irq_lock, irq_state);
525
526     return type;
527 }
528 */
529
530
531 int v3_injecting_intr(struct guest_info * info, uint_t intr_num, v3_intr_type_t type) {
532     struct v3_intr_core_state * intr_state = &(info->intr_core_state);
533
534     if (type == V3_EXTERNAL_IRQ) {
535         struct intr_controller * ctrl = NULL;
536
537         addr_t irq_state = v3_lock_irqsave(intr_state->irq_lock); 
538
539         //      PrintDebug("[injecting_intr] External_Irq with intr_num = %x\n", intr_num);
540         list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
541             ctrl->ctrl_ops->begin_irq(info, ctrl->priv_data, intr_num);
542         }
543
544         v3_unlock_irqrestore(intr_state->irq_lock, irq_state);
545     }
546
547     return 0;
548 }