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.


Horrendous hack to ack seastar IRQs....
[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
26 #ifndef DEBUG_INTERRUPTS
27 #undef PrintDebug
28 #define PrintDebug(fmt, args...)
29 #endif
30
31
32
33
34 struct intr_controller {
35     struct intr_ctrl_ops * ctrl_ops;
36
37     void * priv_data;
38     struct list_head ctrl_node;
39 };
40
41
42 void v3_init_interrupt_state(struct guest_info * info) {
43     info->intr_state.excp_pending = 0;
44     info->intr_state.excp_num = 0;
45     info->intr_state.excp_error_code = 0;
46
47     INIT_LIST_HEAD(&(info->intr_state.controller_list));
48
49     memset((uchar_t *)(info->intr_state.hooks), 0, sizeof(struct v3_irq_hook *) * 256);
50 }
51
52 void v3_register_intr_controller(struct guest_info * info, struct intr_ctrl_ops * ops, void * state) {
53     struct intr_controller * ctrlr = (struct intr_controller *)V3_Malloc(sizeof(struct intr_controller));
54
55     ctrlr->priv_data = state;
56     ctrlr->ctrl_ops = ops;
57
58     list_add(&(ctrlr->ctrl_node), &(info->intr_state.controller_list));
59
60 }
61
62
63
64
65 static inline struct v3_irq_hook * get_irq_hook(struct guest_info * info, uint_t irq) {
66     V3_ASSERT(irq <= 256);
67     return info->intr_state.hooks[irq];
68 }
69
70
71 int v3_hook_irq(struct guest_info * info, 
72                 uint_t irq,
73                 int (*handler)(struct guest_info * info, struct v3_interrupt * intr, void * priv_data),
74                 void  * priv_data) 
75 {
76     struct v3_irq_hook * hook = (struct v3_irq_hook *)V3_Malloc(sizeof(struct v3_irq_hook));
77
78     if (hook == NULL) { 
79         return -1; 
80     }
81
82     if (get_irq_hook(info, irq) != NULL) {
83         PrintError("IRQ %d already hooked\n", irq);
84         return -1;
85     }
86
87     hook->handler = handler;
88     hook->priv_data = priv_data;
89   
90     info->intr_state.hooks[irq] = hook;
91
92     if (V3_Hook_Interrupt(info, irq)) { 
93         PrintError("hook_irq: failed to hook irq %d\n", irq);
94         return -1;
95     } else {
96         PrintDebug("hook_irq: hooked irq %d\n", irq);
97         return 0;
98     }
99 }
100
101
102
103 static int passthrough_irq_handler(struct guest_info * info, struct v3_interrupt * intr, void * priv_data) {
104     PrintDebug("[passthrough_irq_handler] raise_irq=%d (guest=0x%p)\n", 
105                intr->irq, (void *)info);
106
107     return v3_raise_irq(info, intr->irq);
108 }
109
110 int v3_hook_passthrough_irq(struct guest_info * info, uint_t irq) {
111     int rc = v3_hook_irq(info, irq, passthrough_irq_handler, NULL);
112
113     if (rc) { 
114         PrintError("guest_irq_injection: failed to hook irq 0x%x (guest=0x%p)\n", irq, (void *)info);
115         return -1;
116     } else {
117         PrintDebug("guest_irq_injection: hooked irq 0x%x (guest=0x%p)\n", irq, (void *)info);
118         return 0;
119     }
120 }
121
122
123
124
125
126 int v3_deliver_irq(struct guest_info * info, struct v3_interrupt * intr) {
127     PrintDebug("v3_deliver_irq: irq=%d state=0x%p, \n", intr->irq, (void *)intr);
128   
129     struct v3_irq_hook * hook = get_irq_hook(info, intr->irq);
130
131     if (hook == NULL) {
132         PrintError("Attempting to deliver interrupt to non registered hook(irq=%d)\n", intr->irq);
133         return -1;
134     }
135   
136     return hook->handler(info, intr, hook->priv_data);
137 }
138
139
140
141
142
143
144
145
146 int v3_raise_exception_with_error(struct guest_info * info, uint_t excp, uint_t error_code) {
147     struct v3_intr_state * intr_state = &(info->intr_state);
148
149     if (intr_state->excp_pending == 0) {
150         intr_state->excp_pending = 1;
151         intr_state->excp_num = excp;
152         intr_state->excp_error_code = error_code;
153         intr_state->excp_error_code_valid = 1;
154         PrintDebug("[v3_raise_exception_with_error] error code: %x\n", error_code);
155     } else {
156         PrintError("exception already pending, currently not implemented\n");
157         return -1;
158     }
159
160     return 0;
161 }
162
163 int v3_raise_exception(struct guest_info * info, uint_t excp) {
164     struct v3_intr_state * intr_state = &(info->intr_state);
165     PrintDebug("[v3_raise_exception]\n");
166     if (intr_state->excp_pending == 0) {
167         intr_state->excp_pending = 1;
168         intr_state->excp_num = excp;
169         intr_state->excp_error_code = 0;
170         intr_state->excp_error_code_valid = 0;
171     } else {
172         PrintError("exception already pending, currently not implemented\n");
173         return -1;
174     }
175
176     return 0;
177 }
178
179
180 int v3_lower_irq(struct guest_info * info, int irq) {
181     struct intr_controller * ctrl = NULL;
182     struct v3_intr_state * intr_state = &(info->intr_state);
183
184     PrintDebug("[v3_lower_irq]\n");
185
186     list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
187         ctrl->ctrl_ops->lower_intr(ctrl->priv_data, irq);
188     }
189  
190     return 0;
191 }
192
193 int v3_raise_irq(struct guest_info * info, int irq) {
194     struct intr_controller * ctrl = NULL;
195     struct v3_intr_state * intr_state = &(info->intr_state);
196
197     PrintDebug("[v3_raise_irq (%d)]\n", irq);
198
199     list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
200         ctrl->ctrl_ops->raise_intr(ctrl->priv_data, irq);
201     }
202
203     return 0;
204 }
205
206
207
208 int v3_intr_pending(struct guest_info * info) {
209     struct v3_intr_state * intr_state = &(info->intr_state);
210
211     //  PrintDebug("[intr_pending]\n");
212     if (intr_state->excp_pending == 1) {
213         return 1;
214     } else {
215         struct intr_controller * ctrl = NULL;
216
217         list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
218             if (ctrl->ctrl_ops->intr_pending(ctrl->priv_data) == 1) {
219                 return 1;
220             }
221         }
222     }
223
224     return 0;
225 }
226
227
228 uint_t v3_get_intr_number(struct guest_info * info) {
229     struct v3_intr_state * intr_state = &(info->intr_state);
230
231     if (intr_state->excp_pending == 1) {
232         return intr_state->excp_num;
233     } else {
234         struct intr_controller * ctrl = NULL;
235
236         list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
237             if (ctrl->ctrl_ops->intr_pending(ctrl->priv_data)) {
238                 uint_t intr_num = ctrl->ctrl_ops->get_intr_number(ctrl->priv_data);
239
240                 PrintDebug("[get_intr_number] intr_number = %d\n", intr_num);
241
242                 return intr_num;
243             }
244         }
245     }
246
247     return 0;
248 }
249
250
251 intr_type_t v3_get_intr_type(struct guest_info * info) {
252     struct v3_intr_state * intr_state = &(info->intr_state);
253
254     if (intr_state->excp_pending) {
255         PrintDebug("[get_intr_type] Exception\n");
256         return EXCEPTION;
257     } else {
258         struct intr_controller * ctrl = NULL;
259
260         list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
261             if (ctrl->ctrl_ops->intr_pending(ctrl->priv_data) == 1) {
262                 PrintDebug("[get_intr_type] External_irq\n");
263                 return EXTERNAL_IRQ;
264             }
265         }
266     }
267
268     PrintDebug("[get_intr_type] Invalid_Intr\n");
269     return INVALID_INTR;
270 }
271
272
273
274
275
276
277 int v3_injecting_intr(struct guest_info * info, uint_t intr_num, intr_type_t type) {
278     struct v3_intr_state * intr_state = &(info->intr_state);
279
280     if (type == EXCEPTION) {
281         PrintDebug("[injecting_intr] Exception\n");
282         intr_state->excp_pending = 0;
283         intr_state->excp_num = 0;
284         intr_state->excp_error_code = 0;
285         intr_state->excp_error_code_valid = 0;
286     
287     } else if (type == EXTERNAL_IRQ) {
288         struct intr_controller * ctrl = NULL;
289
290         PrintDebug("[injecting_intr] External_Irq with intr_num = %x\n", intr_num);
291         list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
292             ctrl->ctrl_ops->begin_irq(ctrl->priv_data, intr_num);
293         }
294     }
295
296     return 0;
297 }