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.


moved software interrupt injection to core interrupt code
[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 intr_router * router = NULL;
278     struct v3_intr_routers * routers = &(vm->intr_routers);
279
280     //    PrintDebug("[v3_lower_irq]\n");
281     addr_t irq_state = v3_lock_irqsave(routers->irq_lock);
282
283     list_for_each_entry(router, &(routers->router_list), router_node) {
284         router->router_ops->lower_intr(vm, router->priv_data, irq);
285     }
286  
287     v3_unlock_irqrestore(routers->irq_lock, irq_state);
288
289     return 0;
290 }
291
292 int v3_raise_irq(struct v3_vm_info * vm, int irq) {
293     struct intr_router * router = NULL;
294     struct v3_intr_routers * routers = &(vm->intr_routers);
295
296     //  PrintDebug("[v3_raise_irq (%d)]\n", irq);
297     addr_t irq_state = v3_lock_irqsave(routers->irq_lock);
298
299     list_for_each_entry(router, &(routers->router_list), router_node) {
300         router->router_ops->raise_intr(vm, router->priv_data, irq);
301     }
302
303     v3_unlock_irqrestore(routers->irq_lock, irq_state);
304
305     return 0;
306 }
307
308
309
310
311 void v3_clear_pending_intr(struct guest_info * core) {
312     struct v3_intr_core_state * intr_state = &(core->intr_core_state);
313
314     intr_state->irq_pending = 0;
315
316 }
317
318
319 v3_intr_type_t v3_intr_pending(struct guest_info * info) {
320     struct v3_intr_core_state * intr_state = &(info->intr_core_state);
321     struct intr_controller * ctrl = NULL;
322     int ret = V3_INVALID_INTR;
323     int i = 0;
324
325     //  PrintDebug("[intr_pending]\n");
326     addr_t irq_state = v3_lock_irqsave(intr_state->irq_lock);
327
328     // VIRQs have priority
329     for (i = 0; i < MAX_IRQ / 8; i++) {
330         if (intr_state->virq_map[i] != 0) {   
331             ret = V3_VIRTUAL_IRQ;
332             break;
333         }
334     }
335
336     if (ret == V3_INVALID_INTR) {
337         list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
338             if (ctrl->ctrl_ops->intr_pending(info, ctrl->priv_data) == 1) {
339                 ret = V3_EXTERNAL_IRQ;
340                 break;
341             }
342         }
343     }
344     
345     /* for swintr injection */
346     if (intr_state->swintr_posted == 1) {
347         ret = V3_SOFTWARE_INTR;
348     }
349
350     v3_unlock_irqrestore(intr_state->irq_lock, irq_state);
351
352     return ret;
353 }
354
355
356 uint32_t v3_get_intr(struct guest_info * info) {
357     struct v3_intr_core_state * intr_state = &(info->intr_core_state);
358     struct intr_controller * ctrl = NULL;
359     uint_t ret = 0;
360     int i = 0;
361     int j = 0;
362
363     addr_t irq_state = v3_lock_irqsave(intr_state->irq_lock);    
364
365     // virqs have priority
366     for (i = 0; i < MAX_IRQ / 8; i++) {
367         if (intr_state->virq_map[i] != 0) {
368             for (j = 0; j < 8; j++) {
369                 if (intr_state->virq_map[i] & (1 << j)) {
370                     ret = (i * 8) + j;
371                     break;
372                 }
373             }
374             break;
375         }
376     }
377
378     if (!ret) {
379         list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
380             if (ctrl->ctrl_ops->intr_pending(info, ctrl->priv_data)) {
381                 uint_t intr_num = ctrl->ctrl_ops->get_intr_number(info, ctrl->priv_data);
382                 
383                 //      PrintDebug("[get_intr_number] intr_number = %d\n", intr_num);
384                 ret = intr_num;
385                 break;
386             }
387         }
388     }
389
390     v3_unlock_irqrestore(intr_state->irq_lock, irq_state);
391
392     return ret;
393 }
394
395 /*
396 intr_type_t v3_get_intr_type(struct guest_info * info) {
397     struct v3_intr_state * intr_state = &(info->intr_state);
398     struct intr_controller * ctrl = NULL;
399     intr_type_t type = V3_INVALID_INTR;
400
401     addr_t irq_state = v3_lock_irqsave(intr_state->irq_lock);  
402
403     list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
404         if (ctrl->ctrl_ops->intr_pending(ctrl->priv_data) == 1) {
405             //PrintDebug("[get_intr_type] External_irq\n");
406             type = V3_EXTERNAL_IRQ;         
407             break;
408         }
409     }
410
411 #ifdef V3_CONFIG_DEBUG_INTERRUPTS
412     if (type == V3_INVALID_INTR) {
413         PrintError("[get_intr_type] Invalid_Intr\n");
414     }
415 #endif
416
417     v3_unlock_irqrestore(intr_state->irq_lock, irq_state);
418
419     return type;
420 }
421 */
422
423
424
425
426
427 int v3_injecting_intr(struct guest_info * info, uint_t intr_num, v3_intr_type_t type) {
428     struct v3_intr_core_state * intr_state = &(info->intr_core_state);
429
430     if (type == V3_EXTERNAL_IRQ) {
431         struct intr_controller * ctrl = NULL;
432
433         addr_t irq_state = v3_lock_irqsave(intr_state->irq_lock); 
434
435         //      PrintDebug("[injecting_intr] External_Irq with intr_num = %x\n", intr_num);
436         list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
437             ctrl->ctrl_ops->begin_irq(info, ctrl->priv_data, intr_num);
438         }
439
440         v3_unlock_irqrestore(intr_state->irq_lock, irq_state);
441     }
442
443     return 0;
444 }