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.


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