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.


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