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.


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