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 locking to interrupt subsystem
[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 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
150
151
152
153 int v3_lower_irq(struct guest_info * info, int irq) {
154     struct intr_controller * ctrl = NULL;
155     struct v3_intr_state * intr_state = &(info->intr_state);
156
157     //    PrintDebug("[v3_lower_irq]\n");
158     addr_t irq_state = v3_lock_irqsave(intr_state->irq_lock);
159
160     list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
161         ctrl->ctrl_ops->lower_intr(ctrl->priv_data, irq);
162     }
163  
164     v3_unlock_irqrestore(intr_state->irq_lock, irq_state);
165
166     return 0;
167 }
168
169 int v3_raise_irq(struct guest_info * info, int irq) {
170     struct intr_controller * ctrl = NULL;
171     struct v3_intr_state * intr_state = &(info->intr_state);
172
173     //  PrintDebug("[v3_raise_irq (%d)]\n", irq);
174     addr_t irq_state = v3_lock_irqsave(intr_state->irq_lock);
175
176     list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
177         ctrl->ctrl_ops->raise_intr(ctrl->priv_data, irq);
178     }
179
180     v3_unlock_irqrestore(intr_state->irq_lock, irq_state);
181
182     return 0;
183 }
184
185
186
187 int v3_intr_pending(struct guest_info * info) {
188     struct v3_intr_state * intr_state = &(info->intr_state);
189     struct intr_controller * ctrl = NULL;
190     int ret = 0;
191
192     //  PrintDebug("[intr_pending]\n");
193     addr_t irq_state = v3_lock_irqsave(intr_state->irq_lock);    
194
195     list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
196         if (ctrl->ctrl_ops->intr_pending(ctrl->priv_data) == 1) {
197             ret = 1;
198             break;
199         }
200     }
201
202     v3_unlock_irqrestore(intr_state->irq_lock, irq_state);
203
204     return ret;
205 }
206
207
208 uint_t v3_get_intr_number(struct guest_info * info) {
209     struct v3_intr_state * intr_state = &(info->intr_state);
210     struct intr_controller * ctrl = NULL;
211     uint_t ret = 0;
212
213     addr_t irq_state = v3_lock_irqsave(intr_state->irq_lock);    
214
215     list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
216         if (ctrl->ctrl_ops->intr_pending(ctrl->priv_data)) {
217             uint_t intr_num = ctrl->ctrl_ops->get_intr_number(ctrl->priv_data);
218             
219             //  PrintDebug("[get_intr_number] intr_number = %d\n", intr_num);
220             ret = intr_num;
221             break;
222         }
223     }
224
225     v3_unlock_irqrestore(intr_state->irq_lock, irq_state);
226
227
228     return ret;
229 }
230
231
232 intr_type_t v3_get_intr_type(struct guest_info * info) {
233     struct v3_intr_state * intr_state = &(info->intr_state);
234     struct intr_controller * ctrl = NULL;
235     intr_type_t type = INVALID_INTR;
236
237     addr_t irq_state = v3_lock_irqsave(intr_state->irq_lock);  
238
239     list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
240         if (ctrl->ctrl_ops->intr_pending(ctrl->priv_data) == 1) {
241             //PrintDebug("[get_intr_type] External_irq\n");
242             type = EXTERNAL_IRQ;
243             break;
244         }
245     }
246
247 #ifdef DEBUG_INTERRUPTS
248     if (type == INVALID_INTR) {
249         PrintError("[get_intr_type] Invalid_Intr\n");
250     }
251 #endif
252
253     v3_unlock_irqrestore(intr_state->irq_lock, irq_state);
254
255     return type;
256 }
257
258
259
260
261
262
263 int v3_injecting_intr(struct guest_info * info, uint_t intr_num, intr_type_t type) {
264     struct v3_intr_state * intr_state = &(info->intr_state);
265
266     if (type == EXTERNAL_IRQ) {
267         struct intr_controller * ctrl = NULL;
268
269         addr_t irq_state = v3_lock_irqsave(intr_state->irq_lock); 
270
271         //      PrintDebug("[injecting_intr] External_Irq with intr_num = %x\n", intr_num);
272         list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
273             ctrl->ctrl_ops->begin_irq(ctrl->priv_data, intr_num);
274         }
275
276         v3_unlock_irqrestore(intr_state->irq_lock, irq_state);
277     }
278
279     return 0;
280 }