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.


656fa1e5396f32ffdd2fc068ac19f0704fd65738
[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
204 v3_intr_type_t v3_intr_pending(struct guest_info * info) {
205     struct v3_intr_state * intr_state = &(info->intr_state);
206     struct intr_controller * ctrl = NULL;
207     int ret = V3_INVALID_INTR;
208     int i = 0;
209
210     //  PrintDebug("[intr_pending]\n");
211     addr_t irq_state = v3_lock_irqsave(intr_state->irq_lock);
212
213     // VIRQs have priority
214     for (i = 0; i < MAX_IRQ / 8; i++) {
215         if (intr_state->virq_map[i] != 0) {   
216             ret = V3_VIRTUAL_IRQ;
217             break;
218         }
219     }
220
221     if (ret == V3_INVALID_INTR) {
222         list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
223             if (ctrl->ctrl_ops->intr_pending(info, ctrl->priv_data) == 1) {
224                 ret = V3_EXTERNAL_IRQ;
225                 break;
226             }
227         }
228     }
229
230     v3_unlock_irqrestore(intr_state->irq_lock, irq_state);
231
232     return ret;
233 }
234
235
236 uint32_t v3_get_intr(struct guest_info * info) {
237     struct v3_intr_state * intr_state = &(info->intr_state);
238     struct intr_controller * ctrl = NULL;
239     uint_t ret = 0;
240     int i = 0;
241     int j = 0;
242
243     addr_t irq_state = v3_lock_irqsave(intr_state->irq_lock);    
244
245     // virqs have priority
246     for (i = 0; i < MAX_IRQ / 8; i++) {
247         if (intr_state->virq_map[i] != 0) {
248             for (j = 0; j < 8; j++) {
249                 if (intr_state->virq_map[i] & (1 << j)) {
250                     ret = (i * 8) + j;
251                     break;
252                 }
253             }
254             break;
255         }
256     }
257
258     if (!ret) {
259         list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
260             if (ctrl->ctrl_ops->intr_pending(info, ctrl->priv_data)) {
261                 uint_t intr_num = ctrl->ctrl_ops->get_intr_number(info, ctrl->priv_data);
262                 
263                 //      PrintDebug("[get_intr_number] intr_number = %d\n", intr_num);
264                 ret = intr_num;
265                 break;
266             }
267         }
268     }
269
270     v3_unlock_irqrestore(intr_state->irq_lock, irq_state);
271
272     return ret;
273 }
274
275 /*
276 intr_type_t v3_get_intr_type(struct guest_info * info) {
277     struct v3_intr_state * intr_state = &(info->intr_state);
278     struct intr_controller * ctrl = NULL;
279     intr_type_t type = V3_INVALID_INTR;
280
281     addr_t irq_state = v3_lock_irqsave(intr_state->irq_lock);  
282
283     list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
284         if (ctrl->ctrl_ops->intr_pending(ctrl->priv_data) == 1) {
285             //PrintDebug("[get_intr_type] External_irq\n");
286             type = V3_EXTERNAL_IRQ;         
287             break;
288         }
289     }
290
291 #ifdef CONFIG_DEBUG_INTERRUPTS
292     if (type == V3_INVALID_INTR) {
293         PrintError("[get_intr_type] Invalid_Intr\n");
294     }
295 #endif
296
297     v3_unlock_irqrestore(intr_state->irq_lock, irq_state);
298
299     return type;
300 }
301 */
302
303
304
305
306
307 int v3_injecting_intr(struct guest_info * info, uint_t intr_num, v3_intr_type_t type) {
308     struct v3_intr_state * intr_state = &(info->intr_state);
309
310     if (type == V3_EXTERNAL_IRQ) {
311         struct intr_controller * ctrl = NULL;
312
313         addr_t irq_state = v3_lock_irqsave(intr_state->irq_lock); 
314
315         //      PrintDebug("[injecting_intr] External_Irq with intr_num = %x\n", intr_num);
316         list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
317             ctrl->ctrl_ops->begin_irq(info, ctrl->priv_data, intr_num);
318         }
319
320         v3_unlock_irqrestore(intr_state->irq_lock, irq_state);
321     }
322
323     return 0;
324 }