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 ackable interrupts
[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     // VIRQs have priority
351     for (i = 0; i < MAX_IRQ / 8; i++) {
352         if (intr_state->virq_map[i] != 0) {   
353             ret = V3_VIRTUAL_IRQ;
354             break;
355         }
356     }
357
358     if (ret == V3_INVALID_INTR) {
359         list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
360             if (ctrl->ctrl_ops->intr_pending(info, ctrl->priv_data) == 1) {
361                 ret = V3_EXTERNAL_IRQ;
362                 break;
363             }
364         }
365     }
366     
367     /* for swintr injection */
368     if (intr_state->swintr_posted == 1) {
369         ret = V3_SOFTWARE_INTR;
370     }
371
372     v3_unlock_irqrestore(intr_state->irq_lock, irq_state);
373
374     return ret;
375 }
376
377
378 uint32_t v3_get_intr(struct guest_info * info) {
379     struct v3_intr_core_state * intr_state = &(info->intr_core_state);
380     struct intr_controller * ctrl = NULL;
381     uint_t ret = 0;
382     int i = 0;
383     int j = 0;
384
385     addr_t irq_state = v3_lock_irqsave(intr_state->irq_lock);    
386
387     // virqs have priority
388     for (i = 0; i < MAX_IRQ / 8; i++) {
389         if (intr_state->virq_map[i] != 0) {
390             for (j = 0; j < 8; j++) {
391                 if (intr_state->virq_map[i] & (1 << j)) {
392                     ret = (i * 8) + j;
393                     break;
394                 }
395             }
396             break;
397         }
398     }
399
400     if (!ret) {
401         list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
402             if (ctrl->ctrl_ops->intr_pending(info, ctrl->priv_data)) {
403                 uint_t intr_num = ctrl->ctrl_ops->get_intr_number(info, ctrl->priv_data);
404                 
405                 //      PrintDebug("[get_intr_number] intr_number = %d\n", intr_num);
406                 ret = intr_num;
407                 break;
408             }
409         }
410     }
411
412     v3_unlock_irqrestore(intr_state->irq_lock, irq_state);
413
414     return ret;
415 }
416
417 /*
418 intr_type_t v3_get_intr_type(struct guest_info * info) {
419     struct v3_intr_state * intr_state = &(info->intr_state);
420     struct intr_controller * ctrl = NULL;
421     intr_type_t type = V3_INVALID_INTR;
422
423     addr_t irq_state = v3_lock_irqsave(intr_state->irq_lock);  
424
425     list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
426         if (ctrl->ctrl_ops->intr_pending(ctrl->priv_data) == 1) {
427             //PrintDebug("[get_intr_type] External_irq\n");
428             type = V3_EXTERNAL_IRQ;         
429             break;
430         }
431     }
432
433 #ifdef V3_CONFIG_DEBUG_INTERRUPTS
434     if (type == V3_INVALID_INTR) {
435         PrintError("[get_intr_type] Invalid_Intr\n");
436     }
437 #endif
438
439     v3_unlock_irqrestore(intr_state->irq_lock, irq_state);
440
441     return type;
442 }
443 */
444
445
446
447
448
449 int v3_injecting_intr(struct guest_info * info, uint_t intr_num, v3_intr_type_t type) {
450     struct v3_intr_core_state * intr_state = &(info->intr_core_state);
451
452     if (type == V3_EXTERNAL_IRQ) {
453         struct intr_controller * ctrl = NULL;
454
455         addr_t irq_state = v3_lock_irqsave(intr_state->irq_lock); 
456
457         //      PrintDebug("[injecting_intr] External_Irq with intr_num = %x\n", intr_num);
458         list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
459             ctrl->ctrl_ops->begin_irq(info, ctrl->priv_data, intr_num);
460         }
461
462         v3_unlock_irqrestore(intr_state->irq_lock, irq_state);
463     }
464
465     return 0;
466 }