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.


8c4e1c27a7f0a973e15c47ba4e05314af7eb152a
[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
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 int v3_lower_virq(struct guest_info * info, int irq) {
254     struct v3_intr_core_state * intr_state = &(info->intr_core_state);
255     int major = irq / 8;
256     int minor = irq % 8;
257
258     intr_state->virq_map[major] &= ~(1 << minor);
259
260     return 0;
261 }
262
263
264 int v3_lower_irq(struct v3_vm_info * vm, int irq) {
265     struct intr_router * router = NULL;
266     struct v3_intr_routers * routers = &(vm->intr_routers);
267
268     //    PrintDebug("[v3_lower_irq]\n");
269     addr_t irq_state = v3_lock_irqsave(routers->irq_lock);
270
271     list_for_each_entry(router, &(routers->router_list), router_node) {
272         router->router_ops->lower_intr(vm, router->priv_data, irq);
273     }
274  
275     v3_unlock_irqrestore(routers->irq_lock, irq_state);
276
277     return 0;
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 void v3_clear_pending_intr(struct guest_info * core) {
298     struct v3_intr_core_state * intr_state = &(core->intr_core_state);
299
300     intr_state->irq_pending = 0;
301
302 }
303
304
305 v3_intr_type_t v3_intr_pending(struct guest_info * info) {
306     struct v3_intr_core_state * intr_state = &(info->intr_core_state);
307     struct intr_controller * ctrl = NULL;
308     int ret = V3_INVALID_INTR;
309     int i = 0;
310
311     //  PrintDebug("[intr_pending]\n");
312     addr_t irq_state = v3_lock_irqsave(intr_state->irq_lock);
313
314     // VIRQs have priority
315     for (i = 0; i < MAX_IRQ / 8; i++) {
316         if (intr_state->virq_map[i] != 0) {   
317             ret = V3_VIRTUAL_IRQ;
318             break;
319         }
320     }
321
322     if (ret == V3_INVALID_INTR) {
323         list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
324             if (ctrl->ctrl_ops->intr_pending(info, ctrl->priv_data) == 1) {
325                 ret = V3_EXTERNAL_IRQ;
326                 break;
327             }
328         }
329     }
330
331     v3_unlock_irqrestore(intr_state->irq_lock, irq_state);
332
333     return ret;
334 }
335
336
337 uint32_t v3_get_intr(struct guest_info * info) {
338     struct v3_intr_core_state * intr_state = &(info->intr_core_state);
339     struct intr_controller * ctrl = NULL;
340     uint_t ret = 0;
341     int i = 0;
342     int j = 0;
343
344     addr_t irq_state = v3_lock_irqsave(intr_state->irq_lock);    
345
346     // virqs have priority
347     for (i = 0; i < MAX_IRQ / 8; i++) {
348         if (intr_state->virq_map[i] != 0) {
349             for (j = 0; j < 8; j++) {
350                 if (intr_state->virq_map[i] & (1 << j)) {
351                     ret = (i * 8) + j;
352                     break;
353                 }
354             }
355             break;
356         }
357     }
358
359     if (!ret) {
360         list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
361             if (ctrl->ctrl_ops->intr_pending(info, ctrl->priv_data)) {
362                 uint_t intr_num = ctrl->ctrl_ops->get_intr_number(info, ctrl->priv_data);
363                 
364                 //      PrintDebug("[get_intr_number] intr_number = %d\n", intr_num);
365                 ret = intr_num;
366                 break;
367             }
368         }
369     }
370
371     v3_unlock_irqrestore(intr_state->irq_lock, irq_state);
372
373     return ret;
374 }
375
376 /*
377 intr_type_t v3_get_intr_type(struct guest_info * info) {
378     struct v3_intr_state * intr_state = &(info->intr_state);
379     struct intr_controller * ctrl = NULL;
380     intr_type_t type = V3_INVALID_INTR;
381
382     addr_t irq_state = v3_lock_irqsave(intr_state->irq_lock);  
383
384     list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
385         if (ctrl->ctrl_ops->intr_pending(ctrl->priv_data) == 1) {
386             //PrintDebug("[get_intr_type] External_irq\n");
387             type = V3_EXTERNAL_IRQ;         
388             break;
389         }
390     }
391
392 #ifdef V3_CONFIG_DEBUG_INTERRUPTS
393     if (type == V3_INVALID_INTR) {
394         PrintError("[get_intr_type] Invalid_Intr\n");
395     }
396 #endif
397
398     v3_unlock_irqrestore(intr_state->irq_lock, irq_state);
399
400     return type;
401 }
402 */
403
404
405
406
407
408 int v3_injecting_intr(struct guest_info * info, uint_t intr_num, v3_intr_type_t type) {
409     struct v3_intr_core_state * intr_state = &(info->intr_core_state);
410
411     if (type == V3_EXTERNAL_IRQ) {
412         struct intr_controller * ctrl = NULL;
413
414         addr_t irq_state = v3_lock_irqsave(intr_state->irq_lock); 
415
416         //      PrintDebug("[injecting_intr] External_Irq with intr_num = %x\n", intr_num);
417         list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
418             ctrl->ctrl_ops->begin_irq(info, ctrl->priv_data, intr_num);
419         }
420
421         v3_unlock_irqrestore(intr_state->irq_lock, irq_state);
422     }
423
424     return 0;
425 }