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.


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