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.


added ability to inject an env variable into guest user process
[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, uint_t irq) {
172     V3_ASSERT(irq <= 255);
173     return vm->intr_routers.hooks[irq];
174 }
175
176
177 int v3_hook_irq(struct v3_vm_info * vm,
178                 uint_t irq,
179                 int (*handler)(struct v3_vm_info * vm, struct v3_interrupt * intr, void * priv_data),
180                 void  * priv_data) 
181 {
182     struct v3_irq_hook * hook = (struct v3_irq_hook *)V3_Malloc(sizeof(struct v3_irq_hook));
183
184     if (hook == NULL) { 
185         return -1; 
186     }
187
188     if (get_irq_hook(vm, irq) != NULL) {
189         PrintError("IRQ %d already hooked\n", irq);
190         return -1;
191     }
192
193     hook->handler = handler;
194     hook->priv_data = priv_data;
195   
196     vm->intr_routers.hooks[irq] = hook;
197
198     if (V3_Hook_Interrupt(vm, irq)) { 
199         PrintError("hook_irq: failed to hook irq %d\n", irq);
200         return -1;
201     } else {
202         PrintDebug("hook_irq: hooked irq %d\n", irq);
203         return 0;
204     }
205 }
206
207
208 static int passthrough_irq_handler(struct v3_vm_info * vm, struct v3_interrupt * intr, void * priv_data) {
209     PrintDebug("[passthrough_irq_handler] raise_irq=%d (guest=0x%p)\n", 
210                intr->irq, (void *)vm);
211
212     return v3_raise_irq(vm, intr->irq);
213 }
214
215
216 int v3_hook_passthrough_irq(struct v3_vm_info * vm, uint_t irq) {
217     int rc = v3_hook_irq(vm, irq, passthrough_irq_handler, NULL);
218
219     if (rc) { 
220         PrintError("guest_irq_injection: failed to hook irq 0x%x (guest=0x%p)\n", irq, (void *)vm);
221         return -1;
222     } else {
223         PrintDebug("guest_irq_injection: hooked irq 0x%x (guest=0x%p)\n", irq, (void *)vm);
224         return 0;
225     }
226 }
227
228
229 int v3_deliver_irq(struct v3_vm_info * vm, struct v3_interrupt * intr) {
230     PrintDebug("v3_deliver_irq: irq=%d state=0x%p, \n", intr->irq, (void *)intr);
231   
232     struct v3_irq_hook * hook = get_irq_hook(vm, intr->irq);
233
234     if (hook == NULL) {
235         PrintError("Attempting to deliver interrupt to non registered hook(irq=%d)\n", intr->irq);
236         return -1;
237     }
238   
239     return hook->handler(vm, intr, hook->priv_data);
240 }
241
242
243 int v3_raise_virq(struct guest_info * info, int irq) {
244     struct v3_intr_core_state * intr_state = &(info->intr_core_state);
245     int major = irq / 8;
246     int minor = irq % 8;
247
248     intr_state->virq_map[major] |= (1 << minor);
249    
250     return 0;
251 }
252
253
254 int v3_lower_virq(struct guest_info * info, int irq) {
255     struct v3_intr_core_state * intr_state = &(info->intr_core_state);
256     int major = irq / 8;
257     int minor = irq % 8;
258
259     intr_state->virq_map[major] &= ~(1 << minor);
260
261     return 0;
262 }
263
264
265 int v3_lower_irq(struct v3_vm_info * vm, int irq) {
266     struct intr_router * router = NULL;
267     struct v3_intr_routers * routers = &(vm->intr_routers);
268
269     //    PrintDebug("[v3_lower_irq]\n");
270     addr_t irq_state = v3_lock_irqsave(routers->irq_lock);
271
272     list_for_each_entry(router, &(routers->router_list), router_node) {
273         router->router_ops->lower_intr(vm, router->priv_data, irq);
274     }
275  
276     v3_unlock_irqrestore(routers->irq_lock, irq_state);
277
278     return 0;
279 }
280
281
282 int v3_raise_irq(struct v3_vm_info * vm, int irq) {
283     struct intr_router * router = NULL;
284     struct v3_intr_routers * routers = &(vm->intr_routers);
285
286     //  PrintDebug("[v3_raise_irq (%d)]\n", irq);
287     addr_t irq_state = v3_lock_irqsave(routers->irq_lock);
288
289     list_for_each_entry(router, &(routers->router_list), router_node) {
290         router->router_ops->raise_intr(vm, router->priv_data, irq);
291     }
292
293     v3_unlock_irqrestore(routers->irq_lock, irq_state);
294
295     return 0;
296 }
297
298
299 int v3_signal_swintr(struct guest_info * core, int vector) {
300     struct v3_intr_core_state * intr_state = &(core->intr_core_state);
301
302     PrintDebug("Signaling software interrupt in vmm_intr.c\n");
303     PrintDebug("\tINT vector: %d\n", vector);
304     
305     intr_state->swintr_posted = 1;
306     intr_state->swintr_vector = vector;
307     return 0;
308 }
309
310
311 int v3_handle_swintr(struct guest_info * core) {
312
313     int ret = 0;
314     void * instr_ptr = NULL;
315     struct x86_instr instr;
316
317     if (core->mem_mode == PHYSICAL_MEM) { 
318         ret = v3_gpa_to_hva(core, get_addr_linear(core, core->rip, &(core->segments.cs)), (addr_t *)&instr_ptr);
319     } else { 
320         ret = v3_gva_to_hva(core, get_addr_linear(core, core->rip, &(core->segments.cs)), (addr_t *)&instr_ptr);
321     }
322     
323     if (ret == -1) {
324         PrintError("V3 Syscall Hijack: Could not translate Instruction Address (%p)\n", (void *)core->rip);
325         return -1;
326     }
327
328     if (v3_decode(core, (addr_t)instr_ptr, &instr) == -1) {
329         PrintError("V3 Syscall Hijack: Decoding Error\n");
330         return -1;
331     }
332
333     uint8_t vector = instr.dst_operand.operand;
334
335     //PrintDebug("KCH: SWINT\n");
336     //PrintDebug("KCH: Data - %x\n",*((uint32_t*)instr_ptr));
337     //PrintDebug("\t RIP: %llx CS: %x\n", core->rip, core->segments.cs.selector);
338     //PrintDebug("KCH: Disassembling\n\t");
339     //addr_t rip = (addr_t) core->rip;
340     //v3_disasm(core, instr_ptr, &rip, 1); 
341     
342     //v3_print_instr(&instr);
343     // only consider system calls
344
345     /*
346     if (vector == 0x80) {
347         print_syscall(0, core);
348     }
349     */
350
351     struct v3_swintr_hook * hook = core->intr_core_state.swintr_hooks[vector];
352     if (hook == NULL) {
353 #ifdef CONFIG_SWINTR_PASSTHROUGH
354         if (v3_hook_passthrough_swintr(core, vector) == -1) {
355             PrintDebug("Error hooking passthrough swintr\n");
356             return -1;
357         }
358         hook = core->intr_core_state.swintr_hooks[vector];
359 #else
360         core->rip += instr.instr_length;
361         return v3_signal_swintr(core, vector);
362 #endif
363     }
364
365     ret = hook->handler(core, vector, NULL);
366     if (ret == -1) {
367         PrintDebug("V3 SWINT Handler: Error in swint hook\n");
368         return -1;
369     }
370
371     /* make software interrupts prioritized so they finish in time for the next
372         instruction?? */
373     core->rip += instr.instr_length;
374     return v3_signal_swintr(core, vector);
375 }
376
377
378 static inline struct v3_swintr_hook * get_swintr_hook(struct guest_info * core, uint8_t vector) {
379     return core->intr_core_state.swintr_hooks[vector];
380 }
381
382
383 int v3_hook_swintr(struct guest_info * core,
384         uint8_t vector,
385         int (*handler)(struct guest_info * core, uint8_t vector, void * priv_data),
386         void * priv_data) 
387 {
388
389     struct v3_swintr_hook * hook = (struct v3_swintr_hook *)V3_Malloc(sizeof(struct v3_swintr_hook));
390
391     if (hook == NULL) { 
392         return -1; 
393     }
394
395     if (get_swintr_hook(core, vector) != NULL) {
396         PrintError("SWINT %d already hooked\n", vector);
397         return -1;
398     }
399
400     hook->handler = handler;
401     hook->priv_data = priv_data;
402   
403     core->intr_core_state.swintr_hooks[vector] = hook;
404
405     return 0;
406 }
407     
408
409 static int passthrough_swintr_handler(struct guest_info * core, uint8_t vector, void * priv_data) {
410
411     PrintDebug("[passthrough_swint_handler] INT vector=%d (guest=0x%p)\n", 
412                vector, (void *)core);
413
414     return 0;
415 }
416
417
418 int v3_hook_passthrough_swintr(struct guest_info * core, uint8_t vector) {
419
420     int rc = v3_hook_swintr(core, vector, passthrough_swintr_handler, NULL);
421
422     if (rc) { 
423         PrintError("guest_swintr_injection: failed to hook swint 0x%x (guest=0x%p)\n", vector, (void *)core);
424         return -1;
425     } else {
426         PrintDebug("guest_swintr_injection: hooked swint 0x%x (guest=0x%p)\n", vector, (void *)core);
427         return 0;
428     }
429
430     /* shouldn't get here */
431     return 0;
432 }
433
434
435 void v3_clear_pending_intr(struct guest_info * core) {
436     struct v3_intr_core_state * intr_state = &(core->intr_core_state);
437
438     intr_state->irq_pending = 0;
439 }
440
441
442 v3_intr_type_t v3_intr_pending(struct guest_info * info) {
443     struct v3_intr_core_state * intr_state = &(info->intr_core_state);
444     struct intr_controller * ctrl = NULL;
445     int ret = V3_INVALID_INTR;
446     int i = 0;
447
448     //  PrintDebug("[intr_pending]\n");
449     addr_t irq_state = v3_lock_irqsave(intr_state->irq_lock);
450
451     // VIRQs have priority
452     for (i = 0; i < MAX_IRQ / 8; i++) {
453         if (intr_state->virq_map[i] != 0) {   
454             ret = V3_VIRTUAL_IRQ;
455             break;
456         }
457     }
458
459     if (ret == V3_INVALID_INTR) {
460         list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
461             if (ctrl->ctrl_ops->intr_pending(info, ctrl->priv_data) == 1) {
462                 ret = V3_EXTERNAL_IRQ;
463                 break;
464             }
465         }
466     }
467
468     // KCH
469     if (intr_state->swintr_posted == 1) {
470         ret = V3_SOFTWARE_INTR;
471     }
472         
473     v3_unlock_irqrestore(intr_state->irq_lock, irq_state);
474
475     return ret;
476 }
477
478
479 uint32_t v3_get_intr(struct guest_info * info) {
480     struct v3_intr_core_state * intr_state = &(info->intr_core_state);
481     struct intr_controller * ctrl = NULL;
482     uint_t ret = 0;
483     int i = 0;
484     int j = 0;
485
486     addr_t irq_state = v3_lock_irqsave(intr_state->irq_lock);    
487
488     // virqs have priority
489     for (i = 0; i < MAX_IRQ / 8; i++) {
490         if (intr_state->virq_map[i] != 0) {
491             for (j = 0; j < 8; j++) {
492                 if (intr_state->virq_map[i] & (1 << j)) {
493                     ret = (i * 8) + j;
494                     break;
495                 }
496             }
497             break;
498         }
499     }
500
501     if (!ret) {
502         list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
503             if (ctrl->ctrl_ops->intr_pending(info, ctrl->priv_data)) {
504                 uint_t intr_num = ctrl->ctrl_ops->get_intr_number(info, ctrl->priv_data);
505                 
506                 //      PrintDebug("[get_intr_number] intr_number = %d\n", intr_num);
507                 ret = intr_num;
508                 break;
509             }
510         }
511     }
512
513     v3_unlock_irqrestore(intr_state->irq_lock, irq_state);
514
515     return ret;
516 }
517
518 /*
519 intr_type_t v3_get_intr_type(struct guest_info * info) {
520     struct v3_intr_state * intr_state = &(info->intr_state);
521     struct intr_controller * ctrl = NULL;
522     intr_type_t type = V3_INVALID_INTR;
523
524     addr_t irq_state = v3_lock_irqsave(intr_state->irq_lock);  
525
526     list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
527         if (ctrl->ctrl_ops->intr_pending(ctrl->priv_data) == 1) {
528             //PrintDebug("[get_intr_type] External_irq\n");
529             type = V3_EXTERNAL_IRQ;         
530             break;
531         }
532     }
533
534 #ifdef CONFIG_DEBUG_INTERRUPTS
535     if (type == V3_INVALID_INTR) {
536         PrintError("[get_intr_type] Invalid_Intr\n");
537     }
538 #endif
539
540     v3_unlock_irqrestore(intr_state->irq_lock, irq_state);
541
542     return type;
543 }
544 */
545
546
547 int v3_injecting_intr(struct guest_info * info, uint_t intr_num, v3_intr_type_t type) {
548     struct v3_intr_core_state * intr_state = &(info->intr_core_state);
549
550     if (type == V3_EXTERNAL_IRQ) {
551         struct intr_controller * ctrl = NULL;
552
553         addr_t irq_state = v3_lock_irqsave(intr_state->irq_lock); 
554
555         //      PrintDebug("[injecting_intr] External_Irq with intr_num = %x\n", intr_num);
556         list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
557             ctrl->ctrl_ops->begin_irq(info, ctrl->priv_data, intr_num);
558         }
559
560         v3_unlock_irqrestore(intr_state->irq_lock, irq_state);
561     }
562
563     return 0;
564 }