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.


I think I might have fixed the SHUTDOWN bug...
[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 #ifndef DEBUG_INTERRUPTS
28 #undef PrintDebug
29 #define PrintDebug(fmt, args...)
30 #endif
31
32
33
34
35 struct intr_controller {
36     struct intr_ctrl_ops * ctrl_ops;
37
38     void * priv_data;
39     struct list_head ctrl_node;
40 };
41
42
43 void v3_init_interrupt_state(struct guest_info * info) {
44
45     info->intr_state.irq_pending = 0;
46     info->intr_state.irq_vector = 0;
47
48     INIT_LIST_HEAD(&(info->intr_state.controller_list));
49
50     memset((uchar_t *)(info->intr_state.hooks), 0, sizeof(struct v3_irq_hook *) * 256);
51 }
52
53 void v3_register_intr_controller(struct guest_info * info, struct intr_ctrl_ops * ops, void * state) {
54     struct intr_controller * ctrlr = (struct intr_controller *)V3_Malloc(sizeof(struct intr_controller));
55
56     ctrlr->priv_data = state;
57     ctrlr->ctrl_ops = ops;
58
59     list_add(&(ctrlr->ctrl_node), &(info->intr_state.controller_list));
60
61 }
62
63
64
65
66 static inline struct v3_irq_hook * get_irq_hook(struct guest_info * info, uint_t irq) {
67     V3_ASSERT(irq <= 256);
68     return info->intr_state.hooks[irq];
69 }
70
71
72 int v3_hook_irq(struct guest_info * info, 
73                 uint_t irq,
74                 int (*handler)(struct guest_info * info, struct v3_interrupt * intr, void * priv_data),
75                 void  * priv_data) 
76 {
77     struct v3_irq_hook * hook = (struct v3_irq_hook *)V3_Malloc(sizeof(struct v3_irq_hook));
78
79     if (hook == NULL) { 
80         return -1; 
81     }
82
83     if (get_irq_hook(info, irq) != NULL) {
84         PrintError("IRQ %d already hooked\n", irq);
85         return -1;
86     }
87
88     hook->handler = handler;
89     hook->priv_data = priv_data;
90   
91     info->intr_state.hooks[irq] = hook;
92
93     if (V3_Hook_Interrupt(info, irq)) { 
94         PrintError("hook_irq: failed to hook irq %d\n", irq);
95         return -1;
96     } else {
97         PrintDebug("hook_irq: hooked irq %d\n", irq);
98         return 0;
99     }
100 }
101
102
103
104 static int passthrough_irq_handler(struct guest_info * info, struct v3_interrupt * intr, void * priv_data) {
105     PrintDebug("[passthrough_irq_handler] raise_irq=%d (guest=0x%p)\n", 
106                intr->irq, (void *)info);
107
108     return v3_raise_irq(info, intr->irq);
109 }
110
111 int v3_hook_passthrough_irq(struct guest_info * info, uint_t irq) {
112     int rc = v3_hook_irq(info, irq, passthrough_irq_handler, NULL);
113
114     if (rc) { 
115         PrintError("guest_irq_injection: failed to hook irq 0x%x (guest=0x%p)\n", irq, (void *)info);
116         return -1;
117     } else {
118         PrintDebug("guest_irq_injection: hooked irq 0x%x (guest=0x%p)\n", irq, (void *)info);
119         return 0;
120     }
121 }
122
123
124
125
126
127 int v3_deliver_irq(struct guest_info * info, struct v3_interrupt * intr) {
128     PrintDebug("v3_deliver_irq: irq=%d state=0x%p, \n", intr->irq, (void *)intr);
129   
130     struct v3_irq_hook * hook = get_irq_hook(info, intr->irq);
131
132     if (hook == NULL) {
133         PrintError("Attempting to deliver interrupt to non registered hook(irq=%d)\n", intr->irq);
134         return -1;
135     }
136   
137     return hook->handler(info, intr, hook->priv_data);
138 }
139
140
141
142
143
144
145
146
147
148 int v3_lower_irq(struct guest_info * info, int irq) {
149     struct intr_controller * ctrl = NULL;
150     struct v3_intr_state * intr_state = &(info->intr_state);
151
152     //    PrintDebug("[v3_lower_irq]\n");
153
154     list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
155         ctrl->ctrl_ops->lower_intr(ctrl->priv_data, irq);
156     }
157  
158     return 0;
159 }
160
161 int v3_raise_irq(struct guest_info * info, int irq) {
162     struct intr_controller * ctrl = NULL;
163     struct v3_intr_state * intr_state = &(info->intr_state);
164
165     //  PrintDebug("[v3_raise_irq (%d)]\n", irq);
166
167     list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
168         ctrl->ctrl_ops->raise_intr(ctrl->priv_data, irq);
169     }
170
171     return 0;
172 }
173
174
175
176 int v3_intr_pending(struct guest_info * info) {
177     struct v3_intr_state * intr_state = &(info->intr_state);
178     struct intr_controller * ctrl = NULL;
179     struct rflags * flags = (struct rflags *)&(info->ctrl_regs.rflags);
180     //  PrintDebug("[intr_pending]\n");
181     
182     // Check if the guest has interrupts enabled
183     if (flags->intr == 0) {
184         return 0;
185     }
186
187     list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
188         if (ctrl->ctrl_ops->intr_pending(ctrl->priv_data) == 1) {
189             return 1;
190         }
191     }
192
193
194     return 0;
195 }
196
197
198 uint_t v3_get_intr_number(struct guest_info * info) {
199     struct v3_intr_state * intr_state = &(info->intr_state);
200     struct intr_controller * ctrl = NULL;
201
202     list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
203         if (ctrl->ctrl_ops->intr_pending(ctrl->priv_data)) {
204             uint_t intr_num = ctrl->ctrl_ops->get_intr_number(ctrl->priv_data);
205             
206             //  PrintDebug("[get_intr_number] intr_number = %d\n", intr_num);
207             
208             return intr_num;
209         }
210     }
211     return 0;
212 }
213
214
215 intr_type_t v3_get_intr_type(struct guest_info * info) {
216     struct v3_intr_state * intr_state = &(info->intr_state);
217     struct intr_controller * ctrl = NULL;
218
219     list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
220         if (ctrl->ctrl_ops->intr_pending(ctrl->priv_data) == 1) {
221             //PrintDebug("[get_intr_type] External_irq\n");
222             return EXTERNAL_IRQ;
223         }
224     }
225
226     PrintError("[get_intr_type] Invalid_Intr\n");
227     return INVALID_INTR;
228 }
229
230
231
232
233
234
235 int v3_injecting_intr(struct guest_info * info, uint_t intr_num, intr_type_t type) {
236     struct v3_intr_state * intr_state = &(info->intr_state);
237
238     if (type == EXTERNAL_IRQ) {
239         struct intr_controller * ctrl = NULL;
240
241         //      PrintDebug("[injecting_intr] External_Irq with intr_num = %x\n", intr_num);
242         list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
243             ctrl->ctrl_ops->begin_irq(ctrl->priv_data, intr_num);
244         }
245     }
246
247     return 0;
248 }