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.


added irq acking
[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
105     if (intr->should_ack == 1) {
106         V3_ACK_IRQ(intr->irq);
107     }
108
109     PrintDebug("[passthrough_irq_handler] raise_irq=%d (guest=0x%p)\n", 
110                intr->irq, (void *)info);
111
112     return v3_raise_irq(info, intr->irq);
113 }
114
115 int v3_hook_passthrough_irq(struct guest_info * info, uint_t irq) {
116     int rc = v3_hook_irq(info, irq, passthrough_irq_handler, NULL);
117
118     if (rc) { 
119         PrintError("guest_irq_injection: failed to hook irq 0x%x (guest=0x%p)\n", irq, (void *)info);
120         return -1;
121     } else {
122         PrintDebug("guest_irq_injection: hooked irq 0x%x (guest=0x%p)\n", irq, (void *)info);
123         return 0;
124     }
125 }
126
127
128
129
130
131 int v3_deliver_irq(struct guest_info * info, struct v3_interrupt * intr) {
132     PrintDebug("v3_deliver_irq: irq=%d state=0x%p, \n", intr->irq, (void *)intr);
133   
134     struct v3_irq_hook * hook = get_irq_hook(info, intr->irq);
135
136     if (hook == NULL) {
137         PrintError("Attempting to deliver interrupt to non registered hook(irq=%d)\n", intr->irq);
138         return -1;
139     }
140   
141     return hook->handler(info, intr, hook->priv_data);
142 }
143
144
145
146
147
148
149
150
151 int v3_raise_exception_with_error(struct guest_info * info, uint_t excp, uint_t error_code) {
152     struct v3_intr_state * intr_state = &(info->intr_state);
153
154     if (intr_state->excp_pending == 0) {
155         intr_state->excp_pending = 1;
156         intr_state->excp_num = excp;
157         intr_state->excp_error_code = error_code;
158         intr_state->excp_error_code_valid = 1;
159         PrintDebug("[v3_raise_exception_with_error] error code: %x\n", error_code);
160     } else {
161         PrintError("exception already pending, currently not implemented\n");
162         return -1;
163     }
164
165     return 0;
166 }
167
168 int v3_raise_exception(struct guest_info * info, uint_t excp) {
169     struct v3_intr_state * intr_state = &(info->intr_state);
170     PrintDebug("[v3_raise_exception]\n");
171     if (intr_state->excp_pending == 0) {
172         intr_state->excp_pending = 1;
173         intr_state->excp_num = excp;
174         intr_state->excp_error_code = 0;
175         intr_state->excp_error_code_valid = 0;
176     } else {
177         PrintError("exception already pending, currently not implemented\n");
178         return -1;
179     }
180
181     return 0;
182 }
183
184
185 int v3_lower_irq(struct guest_info * info, int irq) {
186     struct intr_controller * ctrl = NULL;
187     struct v3_intr_state * intr_state = &(info->intr_state);
188
189     PrintDebug("[v3_lower_irq]\n");
190
191     list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
192         ctrl->ctrl_ops->lower_intr(ctrl->priv_data, irq);
193     }
194  
195     return 0;
196 }
197
198 int v3_raise_irq(struct guest_info * info, int irq) {
199     struct intr_controller * ctrl = NULL;
200     struct v3_intr_state * intr_state = &(info->intr_state);
201
202     PrintDebug("[v3_raise_irq (%d)]\n", irq);
203
204     list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
205         ctrl->ctrl_ops->raise_intr(ctrl->priv_data, irq);
206     }
207
208     return 0;
209 }
210
211
212
213 int v3_intr_pending(struct guest_info * info) {
214     struct v3_intr_state * intr_state = &(info->intr_state);
215
216     //  PrintDebug("[intr_pending]\n");
217     if (intr_state->excp_pending == 1) {
218         return 1;
219     } else {
220         struct intr_controller * ctrl = NULL;
221
222         list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
223             if (ctrl->ctrl_ops->intr_pending(ctrl->priv_data) == 1) {
224                 return 1;
225             }
226         }
227     }
228
229     return 0;
230 }
231
232
233 uint_t v3_get_intr_number(struct guest_info * info) {
234     struct v3_intr_state * intr_state = &(info->intr_state);
235
236     if (intr_state->excp_pending == 1) {
237         return intr_state->excp_num;
238     } else {
239         struct intr_controller * ctrl = NULL;
240
241         list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
242             if (ctrl->ctrl_ops->intr_pending(ctrl->priv_data)) {
243                 uint_t intr_num = ctrl->ctrl_ops->get_intr_number(ctrl->priv_data);
244
245                 PrintDebug("[get_intr_number] intr_number = %d\n", intr_num);
246
247                 return intr_num;
248             }
249         }
250     }
251
252     return 0;
253 }
254
255
256 intr_type_t v3_get_intr_type(struct guest_info * info) {
257     struct v3_intr_state * intr_state = &(info->intr_state);
258
259     if (intr_state->excp_pending) {
260         PrintDebug("[get_intr_type] Exception\n");
261         return EXCEPTION;
262     } else {
263         struct intr_controller * ctrl = NULL;
264
265         list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
266             if (ctrl->ctrl_ops->intr_pending(ctrl->priv_data) == 1) {
267                 PrintDebug("[get_intr_type] External_irq\n");
268                 return EXTERNAL_IRQ;
269             }
270         }
271     }
272
273     PrintDebug("[get_intr_type] Invalid_Intr\n");
274     return INVALID_INTR;
275 }
276
277
278
279
280
281
282 int v3_injecting_intr(struct guest_info * info, uint_t intr_num, intr_type_t type) {
283     struct v3_intr_state * intr_state = &(info->intr_state);
284
285     if (type == EXCEPTION) {
286         PrintDebug("[injecting_intr] Exception\n");
287         intr_state->excp_pending = 0;
288         intr_state->excp_num = 0;
289         intr_state->excp_error_code = 0;
290         intr_state->excp_error_code_valid = 0;
291     
292     } else if (type == EXTERNAL_IRQ) {
293         struct intr_controller * ctrl = NULL;
294
295         PrintDebug("[injecting_intr] External_Irq with intr_num = %x\n", intr_num);
296         list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
297             ctrl->ctrl_ops->begin_irq(ctrl->priv_data, intr_num);
298         }
299     }
300
301     return 0;
302 }