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.


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