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.


Context-based output infrastructure (V3_Print, etc) and modifications to use it
[palacios.git] / palacios / src / gears / ext_sw_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) 2011, Kyle C. Hale <kh@u.norhtwestern.edu>
11  * Copyright (c) 2011, The V3VEE Project <http://www.v3vee.org> 
12  * All rights reserved.
13  *
14  * Author: Kyle C. Hale <kh@u.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 #include <palacios/vmm.h>
21 #include <palacios/vmcb.h>
22 #include <palacios/vm_guest.h>
23 #include <palacios/vm_guest_mem.h>
24 #include <palacios/vmm_decoder.h>
25 #include <palacios/vmm_extensions.h>
26 #include <palacios/vmm_intr.h>
27
28 #include <gears/sw_intr.h>
29
30 #ifdef V3_CONFIG_EXT_CODE_INJECT
31 #include <gears/code_inject.h>
32 #endif
33
34 #ifndef V3_CONFIG_DEBUG_EXT_SW_INTERRUPTS
35 #undef PrintDebug
36 #define PrintDebug(fmt, args...)
37 #endif
38
39
40 struct v3_swintr_hook {
41     int (*handler)(struct guest_info * core, uint8_t vector, void * priv_data);
42     void * priv_data;
43 };
44
45
46 static struct v3_swintr_hook * swintr_hooks[MAX_SWINTR_HOOKS];
47
48
49 static int init_swintr_intercept (struct v3_vm_info * vm, v3_cfg_tree_t * cfg, void ** priv_data) {
50     return 0;
51 }
52
53
54 static int deinit_swintr_intercept (struct v3_vm_info * vm, void * priv_data) {
55     int i = 0;
56
57     for (; i < MAX_SWINTR_HOOKS; i++) {
58         if (swintr_hooks[i])
59             V3_Free(swintr_hooks[i]);
60     }
61
62     return 0;
63 }
64
65
66 static int init_swintr_core_svm (struct guest_info * core, void * priv_data) {
67     vmcb_t * vmcb = (vmcb_t*)core->vmm_data;
68     vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA(vmcb);
69
70     ctrl_area->instrs.INTn = 1;
71     return 0;
72 }
73
74
75 static int init_swintr_core_vmx (struct guest_info * core, void * priv_data) {
76     PrintError(core->vm_info, core, "Not implemented!\n");
77     return -1;
78 }
79
80
81 static int init_swintr_intercept_core (struct guest_info * core, void * priv_data, void ** core_data) {
82     v3_cpu_arch_t cpu_type = v3_get_cpu_type(V3_Get_CPU());
83
84     switch (cpu_type) {
85         case V3_SVM_CPU:
86         case V3_SVM_REV3_CPU: {
87             if (init_swintr_core_svm(core, priv_data) == -1) {
88                 PrintError(core->vm_info, core, "Problem initializing svm software interrupt intercept\n");
89                 return -1;
90             }
91             break;
92         }
93         case V3_VMX_CPU:
94         case V3_VMX_EPT_CPU:
95         case V3_VMX_EPT_UG_CPU: {
96             if (init_swintr_core_vmx(core, priv_data) == -1) {
97                 PrintError(core->vm_info, core, "Problem initializing vmx software interrupt intercept\n");
98                 return -1;
99             }
100             break;
101         }
102         default:
103             PrintError(core->vm_info, core, "software interrupt interception not supported on this architecture\n");
104             return -1;
105     }
106     return 0;
107 }
108
109
110 static inline struct v3_swintr_hook * get_swintr_hook (struct guest_info * core, uint8_t vector) {
111     return swintr_hooks[vector];
112 }
113
114
115 static struct v3_extension_impl swintr_impl = {
116     .name = "swintr_intercept",
117     .init = init_swintr_intercept,
118     .deinit = deinit_swintr_intercept,
119     .core_init = init_swintr_intercept_core,
120     .core_deinit = NULL,
121     .on_entry = NULL,
122     .on_exit = NULL
123 };
124
125
126 register_extension(&swintr_impl);
127
128
129 int v3_handle_swintr (struct guest_info * core) {
130
131     int ret = 0;
132     void * instr_ptr = NULL;
133     struct x86_instr instr;
134
135     if (core->mem_mode == PHYSICAL_MEM) { 
136         ret = v3_gpa_to_hva(core, get_addr_linear(core, core->rip, &(core->segments.cs)), (addr_t *)&instr_ptr);
137     } else { 
138         ret = v3_gva_to_hva(core, get_addr_linear(core, core->rip, &(core->segments.cs)), (addr_t *)&instr_ptr);
139     }   
140     
141     if (ret == -1) {
142         PrintError(core->vm_info, core, "V3 SWintr Handler: Could not translate Instruction Address (%p)\n", (void *)core->rip);
143         return -1; 
144     }   
145
146     if (v3_decode(core, (addr_t)instr_ptr, &instr) == -1) {
147         PrintError(core->vm_info, core, "V3 SWintr Handler: Decoding Error\n");
148         return -1; 
149     }   
150
151     uint8_t vector = instr.dst_operand.operand;
152
153     struct v3_swintr_hook * hook = swintr_hooks[vector];
154     if (hook == NULL) {
155 #ifdef V3_CONFIG_EXT_SWINTR_PASSTHROUGH
156         if (v3_hook_passthrough_swintr(core, vector) == -1) {
157             PrintDebug(core->vm_info, core, "V3 SWintr Handler: Error hooking passthrough swintr\n");
158             return -1; 
159         }
160         hook = swintr_hooks[vector];
161 #else
162         core->rip += instr.instr_length;
163         return v3_raise_swintr(core, vector);
164 #endif
165     }   
166
167     ret = hook->handler(core, vector, NULL);
168     if (ret == -1) {
169         PrintDebug(core->vm_info, core, "V3 SWintr Handler: Error in swintr hook\n");
170         return -1; 
171     }   
172
173 #ifdef V3_CONFIG_EXT_CODE_INJECT
174 // this is for injecting page faults
175 // we don't want to increment rip or inject
176 // the swint if we need to fault a page in
177     if (ret == E_NEED_PF) {
178         return 0;
179     }
180 #endif
181     /* at some point we _may_ need to prioritize swints 
182        so that they finish in time for the next
183        instruction... */
184     core->rip += instr.instr_length;
185     return v3_raise_swintr(core, vector);
186 }
187
188
189
190 int v3_hook_swintr (struct guest_info * core,
191         uint8_t vector,
192         int (*handler)(struct guest_info * core, uint8_t vector, void * priv_data),
193         void * priv_data)
194 {
195     struct v3_swintr_hook * hook = (struct v3_swintr_hook*)V3_Malloc(sizeof(struct v3_swintr_hook));
196
197     if (hook == NULL) {
198         PrintError(core->vm_info, core, "Cannot allocate for swintr hook\n");
199         return -1;
200     }
201
202     if (get_swintr_hook(core, vector) != NULL) {
203         PrintError(core->vm_info, core, "swint %d already hooked\n", vector);
204         return -1;
205     }
206     
207     hook->handler = handler;
208     hook->priv_data = priv_data;
209
210     swintr_hooks[vector] = hook;
211
212     PrintDebug(core->vm_info, core, "Hooked Swintr #%d\n", vector);
213
214     return 0;
215 }
216     
217
218 static int passthrough_swintr_handler (struct guest_info * core, uint8_t vector, void * priv_data) {
219     PrintDebug(core->vm_info, core, "[passthrough_swint_handler] INT vector=%d (guest=0x%p)\n",
220         vector, (void*)core);
221     return 0;
222 }
223
224
225 int v3_hook_passthrough_swintr (struct guest_info * core, uint8_t vector) {
226     
227     int rc = v3_hook_swintr(core, vector, passthrough_swintr_handler, NULL);
228     
229     if (rc) {
230         PrintError(core->vm_info, core, "guest_swintr_injection: failed to hook swint 0x%x (guest=0x%p)\n", vector, (void*)core);
231         return -1;
232     } else {
233         PrintDebug(core->vm_info, core, "guest_swintr_injection: hooked swint 0x%x (guest=0x%p)\n", vector, (void*)core);
234         return 0;
235     }
236     
237     /* shouldn't get here */
238     return 0;
239 }
240
241