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.


additions for syscall hijacking
[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 CONFIG_DEBUG_INTERRUPTS
30 #undef PrintDebug
31 #define PrintDebug(fmt, args...)
32 #endif
33
34
35
36 struct intr_controller {
37     struct intr_ctrl_ops * ctrl_ops;
38     
39     void * priv_data;
40     struct list_head ctrl_node;
41 };
42
43
44 struct intr_router {
45     struct intr_router_ops * router_ops;
46
47     void * priv_data;
48     struct list_head router_node;
49
50 };
51
52
53
54 void v3_init_intr_controllers(struct guest_info * info) {
55     struct v3_intr_core_state * intr_state = &(info->intr_core_state);
56
57     intr_state->irq_pending = 0;
58     intr_state->irq_started = 0;
59     intr_state->irq_vector = 0;
60
61     v3_lock_init(&(intr_state->irq_lock));
62
63     INIT_LIST_HEAD(&(intr_state->controller_list));
64 }
65
66
67 void v3_deinit_intr_controllers(struct guest_info * core) {
68     struct v3_intr_core_state * intr_state = &(core->intr_core_state);
69     struct intr_controller * ctrlr;
70     struct intr_controller * tmp;
71
72     // clear out any controllers that were left around
73     list_for_each_entry_safe(ctrlr, tmp, &(intr_state->controller_list), ctrl_node) {
74         v3_remove_intr_controller(core, ctrlr);
75     }
76 }
77
78
79 void v3_init_intr_routers(struct v3_vm_info * vm) {
80     
81     INIT_LIST_HEAD(&(vm->intr_routers.router_list));
82     
83     v3_lock_init(&(vm->intr_routers.irq_lock));
84
85     memset((uchar_t *)(vm->intr_routers.hooks), 0, sizeof(struct v3_irq_hook *) * 256);
86 }
87
88
89 void v3_deinit_intr_routers(struct v3_vm_info * vm) {
90     struct intr_router * rtr = NULL;
91     struct intr_router * tmp = NULL;
92
93     // clear out any controllers that were left around
94     list_for_each_entry_safe(rtr, tmp, &(vm->intr_routers.router_list), router_node) {
95         v3_remove_intr_router(vm, rtr);
96     }  
97 }
98
99
100 void * v3_register_intr_controller(struct guest_info * info, struct intr_ctrl_ops * ops, void * priv_data) {
101     struct intr_controller * ctrlr = (struct intr_controller *)V3_Malloc(sizeof(struct intr_controller));
102
103     ctrlr->priv_data = priv_data;
104     ctrlr->ctrl_ops = ops;
105
106     list_add(&(ctrlr->ctrl_node), &(info->intr_core_state.controller_list));
107     
108     return (void *)ctrlr;
109 }
110
111
112 void v3_remove_intr_controller(struct guest_info * core, void * handle) {
113     struct v3_intr_core_state * intr_state = &(core->intr_core_state);
114     struct intr_controller * ctrlr = handle;
115     struct intr_controller * tmp = NULL;
116     int found = 0;
117
118     // search for the entry in the router list
119     list_for_each_entry(tmp, &(intr_state->controller_list), ctrl_node) {
120         if (tmp == ctrlr) {
121             found = 1;
122         }
123     }
124
125     if (found == 0) {
126         PrintError("Attempted to remove invalid interrupt controller handle\n");
127         return;
128     }
129
130     list_del(&(ctrlr->ctrl_node));
131     V3_Free(ctrlr);
132 }
133
134
135 void * v3_register_intr_router(struct v3_vm_info * vm, struct intr_router_ops * ops, void * priv_data) {
136     struct intr_router * router = (struct intr_router *)V3_Malloc(sizeof(struct intr_router));
137
138     router->priv_data = priv_data;
139     router->router_ops = ops;
140
141     list_add(&(router->router_node), &(vm->intr_routers.router_list));
142     
143     return (void *)router;
144 }
145
146
147 void v3_remove_intr_router(struct v3_vm_info * vm, void * handle) {
148     struct intr_router * router = handle;
149     struct intr_router * tmp = NULL;
150     int found = 0;
151
152     // search for the entry in the router list
153     list_for_each_entry(tmp, &(vm->intr_routers.router_list), router_node) {
154         if (tmp == router) {
155             found = 1;
156         }
157     }
158
159     if (found == 0) {
160         PrintError("Attempted to remove invalid interrupt router\n");
161         return;
162     }
163
164     list_del(&(router->router_node));
165     V3_Free(router);
166 }
167
168
169 static inline struct v3_irq_hook * get_irq_hook(struct v3_vm_info * vm, uint_t irq) {
170     V3_ASSERT(irq <= 256);
171     return vm->intr_routers.hooks[irq];
172 }
173
174
175 int v3_hook_irq(struct v3_vm_info * vm,
176                 uint_t irq,
177                 int (*handler)(struct v3_vm_info * vm, struct v3_interrupt * intr, void * priv_data),
178                 void  * priv_data) 
179 {
180     struct v3_irq_hook * hook = (struct v3_irq_hook *)V3_Malloc(sizeof(struct v3_irq_hook));
181
182     if (hook == NULL) { 
183         return -1; 
184     }
185
186     if (get_irq_hook(vm, irq) != NULL) {
187         PrintError("IRQ %d already hooked\n", irq);
188         return -1;
189     }
190
191     hook->handler = handler;
192     hook->priv_data = priv_data;
193   
194     vm->intr_routers.hooks[irq] = hook;
195
196     if (V3_Hook_Interrupt(vm, irq)) { 
197         PrintError("hook_irq: failed to hook irq %d\n", irq);
198         return -1;
199     } else {
200         PrintDebug("hook_irq: hooked irq %d\n", irq);
201         return 0;
202     }
203 }
204
205
206 static int passthrough_irq_handler(struct v3_vm_info * vm, struct v3_interrupt * intr, void * priv_data) {
207     PrintDebug("[passthrough_irq_handler] raise_irq=%d (guest=0x%p)\n", 
208                intr->irq, (void *)vm);
209
210     return v3_raise_irq(vm, intr->irq);
211 }
212
213
214 int v3_hook_passthrough_irq(struct v3_vm_info * vm, uint_t irq) {
215     int rc = v3_hook_irq(vm, irq, passthrough_irq_handler, NULL);
216
217     if (rc) { 
218         PrintError("guest_irq_injection: failed to hook irq 0x%x (guest=0x%p)\n", irq, (void *)vm);
219         return -1;
220     } else {
221         PrintDebug("guest_irq_injection: hooked irq 0x%x (guest=0x%p)\n", irq, (void *)vm);
222         return 0;
223     }
224 }
225
226
227 int v3_deliver_irq(struct v3_vm_info * vm, struct v3_interrupt * intr) {
228     PrintDebug("v3_deliver_irq: irq=%d state=0x%p, \n", intr->irq, (void *)intr);
229   
230     struct v3_irq_hook * hook = get_irq_hook(vm, intr->irq);
231
232     if (hook == NULL) {
233         PrintError("Attempting to deliver interrupt to non registered hook(irq=%d)\n", intr->irq);
234         return -1;
235     }
236   
237     return hook->handler(vm, intr, hook->priv_data);
238 }
239
240
241 int v3_raise_virq(struct guest_info * info, int irq) {
242     struct v3_intr_core_state * intr_state = &(info->intr_core_state);
243     int major = irq / 8;
244     int minor = irq % 8;
245
246     intr_state->virq_map[major] |= (1 << minor);
247    
248     return 0;
249 }
250
251
252 int v3_lower_virq(struct guest_info * info, int irq) {
253     struct v3_intr_core_state * intr_state = &(info->intr_core_state);
254     int major = irq / 8;
255     int minor = irq % 8;
256
257     intr_state->virq_map[major] &= ~(1 << minor);
258
259     return 0;
260 }
261
262
263 int v3_lower_irq(struct v3_vm_info * vm, int irq) {
264     struct intr_router * router = NULL;
265     struct v3_intr_routers * routers = &(vm->intr_routers);
266
267     //    PrintDebug("[v3_lower_irq]\n");
268     addr_t irq_state = v3_lock_irqsave(routers->irq_lock);
269
270     list_for_each_entry(router, &(routers->router_list), router_node) {
271         router->router_ops->lower_intr(vm, router->priv_data, irq);
272     }
273  
274     v3_unlock_irqrestore(routers->irq_lock, irq_state);
275
276     return 0;
277 }
278
279
280 int v3_raise_irq(struct v3_vm_info * vm, int irq) {
281     struct intr_router * router = NULL;
282     struct v3_intr_routers * routers = &(vm->intr_routers);
283
284     //  PrintDebug("[v3_raise_irq (%d)]\n", irq);
285     addr_t irq_state = v3_lock_irqsave(routers->irq_lock);
286
287     list_for_each_entry(router, &(routers->router_list), router_node) {
288         router->router_ops->raise_intr(vm, router->priv_data, irq);
289     }
290
291     v3_unlock_irqrestore(routers->irq_lock, irq_state);
292
293     return 0;
294 }
295
296
297 int v3_signal_sw_intr(struct guest_info * core, int vec) {
298     struct v3_intr_core_state * intr_state = &(core->intr_core_state);
299
300     PrintDebug("KCH: Signalling a software interrupt in vmm_intr.c\n");
301     PrintDebug("\tINT vector: %d\n", vec);
302     
303     intr_state->sw_intr_pending = 1;
304     intr_state->sw_intr_vector = vec;
305     return 0;
306 }
307
308
309 void v3_clear_pending_intr(struct guest_info * core) {
310     struct v3_intr_core_state * intr_state = &(core->intr_core_state);
311
312     intr_state->irq_pending = 0;
313 }
314
315
316 v3_intr_type_t v3_intr_pending(struct guest_info * info) {
317     struct v3_intr_core_state * intr_state = &(info->intr_core_state);
318     struct intr_controller * ctrl = NULL;
319     int ret = V3_INVALID_INTR;
320     int i = 0;
321
322     //  PrintDebug("[intr_pending]\n");
323     addr_t irq_state = v3_lock_irqsave(intr_state->irq_lock);
324
325     // VIRQs have priority
326     for (i = 0; i < MAX_IRQ / 8; i++) {
327         if (intr_state->virq_map[i] != 0) {   
328             ret = V3_VIRTUAL_IRQ;
329             break;
330         }
331     }
332
333     if (ret == V3_INVALID_INTR) {
334         list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
335             if (ctrl->ctrl_ops->intr_pending(info, ctrl->priv_data) == 1) {
336                 ret = V3_EXTERNAL_IRQ;
337                 break;
338             }
339         }
340     }
341
342     // KCH: not sure about this
343     if (intr_state->sw_intr_pending == 1) {
344         ret = V3_SOFTWARE_INTR;
345     }
346         
347
348     v3_unlock_irqrestore(intr_state->irq_lock, irq_state);
349
350     return ret;
351 }
352
353
354 uint32_t v3_get_intr(struct guest_info * info) {
355     struct v3_intr_core_state * intr_state = &(info->intr_core_state);
356     struct intr_controller * ctrl = NULL;
357     uint_t ret = 0;
358     int i = 0;
359     int j = 0;
360
361     addr_t irq_state = v3_lock_irqsave(intr_state->irq_lock);    
362
363     // virqs have priority
364     for (i = 0; i < MAX_IRQ / 8; i++) {
365         if (intr_state->virq_map[i] != 0) {
366             for (j = 0; j < 8; j++) {
367                 if (intr_state->virq_map[i] & (1 << j)) {
368                     ret = (i * 8) + j;
369                     break;
370                 }
371             }
372             break;
373         }
374     }
375
376     if (!ret) {
377         list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
378             if (ctrl->ctrl_ops->intr_pending(info, ctrl->priv_data)) {
379                 uint_t intr_num = ctrl->ctrl_ops->get_intr_number(info, ctrl->priv_data);
380                 
381                 //      PrintDebug("[get_intr_number] intr_number = %d\n", intr_num);
382                 ret = intr_num;
383                 break;
384             }
385         }
386     }
387
388     v3_unlock_irqrestore(intr_state->irq_lock, irq_state);
389
390     return ret;
391 }
392
393 /*
394 intr_type_t v3_get_intr_type(struct guest_info * info) {
395     struct v3_intr_state * intr_state = &(info->intr_state);
396     struct intr_controller * ctrl = NULL;
397     intr_type_t type = V3_INVALID_INTR;
398
399     addr_t irq_state = v3_lock_irqsave(intr_state->irq_lock);  
400
401     list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
402         if (ctrl->ctrl_ops->intr_pending(ctrl->priv_data) == 1) {
403             //PrintDebug("[get_intr_type] External_irq\n");
404             type = V3_EXTERNAL_IRQ;         
405             break;
406         }
407     }
408
409 #ifdef CONFIG_DEBUG_INTERRUPTS
410     if (type == V3_INVALID_INTR) {
411         PrintError("[get_intr_type] Invalid_Intr\n");
412     }
413 #endif
414
415     v3_unlock_irqrestore(intr_state->irq_lock, irq_state);
416
417     return type;
418 }
419 */
420
421
422 int v3_injecting_intr(struct guest_info * info, uint_t intr_num, v3_intr_type_t type) {
423     struct v3_intr_core_state * intr_state = &(info->intr_core_state);
424
425     if (type == V3_EXTERNAL_IRQ) {
426         struct intr_controller * ctrl = NULL;
427
428         addr_t irq_state = v3_lock_irqsave(intr_state->irq_lock); 
429
430         //      PrintDebug("[injecting_intr] External_Irq with intr_num = %x\n", intr_num);
431         list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
432             ctrl->ctrl_ops->begin_irq(info, ctrl->priv_data, intr_num);
433         }
434
435         v3_unlock_irqrestore(intr_state->irq_lock, irq_state);
436     }
437
438     return 0;
439 }