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.


87b6802a5313448dcc61bc27fa97ec50d5fac72a
[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
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 void v3_init_intr_routers(struct v3_vm_info * vm) {
66     
67     INIT_LIST_HEAD(&(vm->intr_routers.router_list));
68     
69     v3_lock_init(&(vm->intr_routers.irq_lock));
70
71     memset((uchar_t *)(vm->intr_routers.hooks), 0, sizeof(struct v3_irq_hook *) * 256);
72 }
73
74
75 int v3_register_intr_controller(struct guest_info * info, struct intr_ctrl_ops * ops, void * priv_data) {
76     struct intr_controller * ctrlr = (struct intr_controller *)V3_Malloc(sizeof(struct intr_controller));
77
78     ctrlr->priv_data = priv_data;
79     ctrlr->ctrl_ops = ops;
80
81     list_add(&(ctrlr->ctrl_node), &(info->intr_core_state.controller_list));
82     
83     return 0;
84 }
85
86 int v3_register_intr_router(struct v3_vm_info * vm, struct intr_router_ops * ops, void * priv_data) {
87     struct intr_router * router = (struct intr_router *)V3_Malloc(sizeof(struct intr_router));
88
89     router->priv_data = priv_data;
90     router->router_ops = ops;
91
92     list_add(&(router->router_node), &(vm->intr_routers.router_list));
93     
94     return 0;
95 }
96
97
98
99 static inline struct v3_irq_hook * get_irq_hook(struct v3_vm_info * vm, uint_t irq) {
100     V3_ASSERT(irq <= 256);
101     return vm->intr_routers.hooks[irq];
102 }
103
104
105 int v3_hook_irq(struct v3_vm_info * vm,
106                 uint_t irq,
107                 int (*handler)(struct v3_vm_info * vm, struct v3_interrupt * intr, void * priv_data),
108                 void  * priv_data) 
109 {
110     struct v3_irq_hook * hook = (struct v3_irq_hook *)V3_Malloc(sizeof(struct v3_irq_hook));
111
112     if (hook == NULL) { 
113         return -1; 
114     }
115
116     if (get_irq_hook(vm, irq) != NULL) {
117         PrintError("IRQ %d already hooked\n", irq);
118         return -1;
119     }
120
121     hook->handler = handler;
122     hook->priv_data = priv_data;
123   
124     vm->intr_routers.hooks[irq] = hook;
125
126     if (V3_Hook_Interrupt(vm, irq)) { 
127         PrintError("hook_irq: failed to hook irq %d\n", irq);
128         return -1;
129     } else {
130         PrintDebug("hook_irq: hooked irq %d\n", irq);
131         return 0;
132     }
133 }
134
135
136
137 static int passthrough_irq_handler(struct v3_vm_info * vm, struct v3_interrupt * intr, void * priv_data) {
138     PrintDebug("[passthrough_irq_handler] raise_irq=%d (guest=0x%p)\n", 
139                intr->irq, (void *)vm);
140
141     return v3_raise_irq(vm, intr->irq);
142 }
143
144 int v3_hook_passthrough_irq(struct v3_vm_info * vm, uint_t irq) {
145     int rc = v3_hook_irq(vm, irq, passthrough_irq_handler, NULL);
146
147     if (rc) { 
148         PrintError("guest_irq_injection: failed to hook irq 0x%x (guest=0x%p)\n", irq, (void *)vm);
149         return -1;
150     } else {
151         PrintDebug("guest_irq_injection: hooked irq 0x%x (guest=0x%p)\n", irq, (void *)vm);
152         return 0;
153     }
154 }
155
156
157
158
159
160 int v3_deliver_irq(struct v3_vm_info * vm, struct v3_interrupt * intr) {
161     PrintDebug("v3_deliver_irq: irq=%d state=0x%p, \n", intr->irq, (void *)intr);
162   
163     struct v3_irq_hook * hook = get_irq_hook(vm, intr->irq);
164
165     if (hook == NULL) {
166         PrintError("Attempting to deliver interrupt to non registered hook(irq=%d)\n", intr->irq);
167         return -1;
168     }
169   
170     return hook->handler(vm, intr, hook->priv_data);
171 }
172
173
174
175
176
177 int v3_raise_virq(struct guest_info * info, int irq) {
178     struct v3_intr_core_state * intr_state = &(info->intr_core_state);
179     int major = irq / 8;
180     int minor = irq % 8;
181
182     intr_state->virq_map[major] |= (1 << minor);
183    
184     return 0;
185 }
186
187 int v3_lower_virq(struct guest_info * info, int irq) {
188     struct v3_intr_core_state * intr_state = &(info->intr_core_state);
189     int major = irq / 8;
190     int minor = irq % 8;
191
192     intr_state->virq_map[major] &= ~(1 << minor);
193
194     return 0;
195 }
196
197
198 int v3_lower_irq(struct v3_vm_info * vm, int irq) {
199     struct intr_router * router = NULL;
200     struct v3_intr_routers * routers = &(vm->intr_routers);
201
202     //    PrintDebug("[v3_lower_irq]\n");
203     addr_t irq_state = v3_lock_irqsave(routers->irq_lock);
204
205     list_for_each_entry(router, &(routers->router_list), router_node) {
206         router->router_ops->lower_intr(vm, router->priv_data, irq);
207     }
208  
209     v3_unlock_irqrestore(routers->irq_lock, irq_state);
210
211     return 0;
212 }
213
214 int v3_raise_irq(struct v3_vm_info * vm, int irq) {
215     struct intr_router * router = NULL;
216     struct v3_intr_routers * routers = &(vm->intr_routers);
217
218     //  PrintDebug("[v3_raise_irq (%d)]\n", irq);
219     addr_t irq_state = v3_lock_irqsave(routers->irq_lock);
220
221     list_for_each_entry(router, &(routers->router_list), router_node) {
222         router->router_ops->raise_intr(vm, router->priv_data, irq);
223     }
224
225     v3_unlock_irqrestore(routers->irq_lock, irq_state);
226
227     return 0;
228 }
229
230
231
232 v3_intr_type_t v3_intr_pending(struct guest_info * info) {
233     struct v3_intr_core_state * intr_state = &(info->intr_core_state);
234     struct intr_controller * ctrl = NULL;
235     int ret = V3_INVALID_INTR;
236     int i = 0;
237
238     //  PrintDebug("[intr_pending]\n");
239     addr_t irq_state = v3_lock_irqsave(intr_state->irq_lock);
240
241     // VIRQs have priority
242     for (i = 0; i < MAX_IRQ / 8; i++) {
243         if (intr_state->virq_map[i] != 0) {   
244             ret = V3_VIRTUAL_IRQ;
245             break;
246         }
247     }
248
249     if (ret == V3_INVALID_INTR) {
250         list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
251             if (ctrl->ctrl_ops->intr_pending(info, ctrl->priv_data) == 1) {
252                 ret = V3_EXTERNAL_IRQ;
253                 break;
254             }
255         }
256     }
257
258     v3_unlock_irqrestore(intr_state->irq_lock, irq_state);
259
260     return ret;
261 }
262
263
264 uint32_t v3_get_intr(struct guest_info * info) {
265     struct v3_intr_core_state * intr_state = &(info->intr_core_state);
266     struct intr_controller * ctrl = NULL;
267     uint_t ret = 0;
268     int i = 0;
269     int j = 0;
270
271     addr_t irq_state = v3_lock_irqsave(intr_state->irq_lock);    
272
273     // virqs have priority
274     for (i = 0; i < MAX_IRQ / 8; i++) {
275         if (intr_state->virq_map[i] != 0) {
276             for (j = 0; j < 8; j++) {
277                 if (intr_state->virq_map[i] & (1 << j)) {
278                     ret = (i * 8) + j;
279                     break;
280                 }
281             }
282             break;
283         }
284     }
285
286     if (!ret) {
287         list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
288             if (ctrl->ctrl_ops->intr_pending(info, ctrl->priv_data)) {
289                 uint_t intr_num = ctrl->ctrl_ops->get_intr_number(info, ctrl->priv_data);
290                 
291                 //      PrintDebug("[get_intr_number] intr_number = %d\n", intr_num);
292                 ret = intr_num;
293                 break;
294             }
295         }
296     }
297
298     v3_unlock_irqrestore(intr_state->irq_lock, irq_state);
299
300     return ret;
301 }
302
303 /*
304 intr_type_t v3_get_intr_type(struct guest_info * info) {
305     struct v3_intr_state * intr_state = &(info->intr_state);
306     struct intr_controller * ctrl = NULL;
307     intr_type_t type = V3_INVALID_INTR;
308
309     addr_t irq_state = v3_lock_irqsave(intr_state->irq_lock);  
310
311     list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
312         if (ctrl->ctrl_ops->intr_pending(ctrl->priv_data) == 1) {
313             //PrintDebug("[get_intr_type] External_irq\n");
314             type = V3_EXTERNAL_IRQ;         
315             break;
316         }
317     }
318
319 #ifdef CONFIG_DEBUG_INTERRUPTS
320     if (type == V3_INVALID_INTR) {
321         PrintError("[get_intr_type] Invalid_Intr\n");
322     }
323 #endif
324
325     v3_unlock_irqrestore(intr_state->irq_lock, irq_state);
326
327     return type;
328 }
329 */
330
331
332
333
334
335 int v3_injecting_intr(struct guest_info * info, uint_t intr_num, v3_intr_type_t type) {
336     struct v3_intr_core_state * intr_state = &(info->intr_core_state);
337
338     if (type == V3_EXTERNAL_IRQ) {
339         struct intr_controller * ctrl = NULL;
340
341         addr_t irq_state = v3_lock_irqsave(intr_state->irq_lock); 
342
343         //      PrintDebug("[injecting_intr] External_Irq with intr_num = %x\n", intr_num);
344         list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
345             ctrl->ctrl_ops->begin_irq(info, ctrl->priv_data, intr_num);
346         }
347
348         v3_unlock_irqrestore(intr_state->irq_lock, irq_state);
349     }
350
351     return 0;
352 }