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.


updated IO and MSRs to allow hooking/unhooking dynamic at runtime
[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     //  PrintDebug("[intr_pending]\n");
181     
182     list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
183         if (ctrl->ctrl_ops->intr_pending(ctrl->priv_data) == 1) {
184             return 1;
185         }
186     }
187
188     return 0;
189 }
190
191
192 uint_t v3_get_intr_number(struct guest_info * info) {
193     struct v3_intr_state * intr_state = &(info->intr_state);
194     struct intr_controller * ctrl = NULL;
195
196     list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
197         if (ctrl->ctrl_ops->intr_pending(ctrl->priv_data)) {
198             uint_t intr_num = ctrl->ctrl_ops->get_intr_number(ctrl->priv_data);
199             
200             //  PrintDebug("[get_intr_number] intr_number = %d\n", intr_num);
201             
202             return intr_num;
203         }
204     }
205     return 0;
206 }
207
208
209 intr_type_t v3_get_intr_type(struct guest_info * info) {
210     struct v3_intr_state * intr_state = &(info->intr_state);
211     struct intr_controller * ctrl = NULL;
212
213     list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
214         if (ctrl->ctrl_ops->intr_pending(ctrl->priv_data) == 1) {
215             //PrintDebug("[get_intr_type] External_irq\n");
216             return EXTERNAL_IRQ;
217         }
218     }
219
220     PrintError("[get_intr_type] Invalid_Intr\n");
221     return INVALID_INTR;
222 }
223
224
225
226
227
228
229 int v3_injecting_intr(struct guest_info * info, uint_t intr_num, intr_type_t type) {
230     struct v3_intr_state * intr_state = &(info->intr_state);
231
232     if (type == EXTERNAL_IRQ) {
233         struct intr_controller * ctrl = NULL;
234
235         //      PrintDebug("[injecting_intr] External_Irq with intr_num = %x\n", intr_num);
236         list_for_each_entry(ctrl, &(intr_state->controller_list), ctrl_node) {
237             ctrl->ctrl_ops->begin_irq(ctrl->priv_data, intr_num);
238         }
239     }
240
241     return 0;
242 }