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.


Lots of pedantic error checking in Palacios proper, especially for memory
[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 static int init_swintr_intercept (struct v3_vm_info * vm, v3_cfg_tree_t * cfg, void ** priv_data) {
41     return 0;
42 }
43
44
45 static int init_swintr_core_svm (struct guest_info * core, void * priv_data) {
46     vmcb_t * vmcb = (vmcb_t*)core->vmm_data;
47     vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA(vmcb);
48
49     ctrl_area->instrs.INTn = 1;
50     return 0;
51 }
52
53
54 static int init_swintr_core_vmx (struct guest_info * core, void * priv_data) {
55     PrintError("Not implemented!\n");
56     return -1;
57 }
58
59
60 static int init_swintr_intercept_core (struct guest_info * core, void * priv_data) {
61     v3_cpu_arch_t cpu_type = v3_get_cpu_type(V3_Get_CPU());
62
63     switch (cpu_type) {
64         case V3_SVM_CPU:
65         case V3_SVM_REV3_CPU: {
66             if (init_swintr_core_svm(core, priv_data) == -1) {
67                 PrintError("Problem initializing svm software interrupt intercept\n");
68                 return -1;
69             }
70             break;
71         }
72         case V3_VMX_CPU:
73         case V3_VMX_EPT_CPU:
74         case V3_VMX_EPT_UG_CPU: {
75             if (init_swintr_core_vmx(core, priv_data) == -1) {
76                 PrintError("Problem initializing vmx software interrupt intercept\n");
77                 return -1;
78             }
79             break;
80         }
81         default:
82             PrintError("software interrupt interception not supported on this architecture\n");
83             return -1;
84     }
85     return 0;
86 }
87
88
89 struct v3_swintr_hook {
90     int (*handler)(struct guest_info * core, uint8_t vector, void * priv_data);
91     void * priv_data;
92 };
93
94
95 static struct v3_swintr_hook * swintr_hooks[256];
96
97 static inline struct v3_swintr_hook * get_swintr_hook (struct guest_info * core, uint8_t vector) {
98     return swintr_hooks[vector];
99 }
100
101
102 static struct v3_extension_impl swintr_impl = {
103     .name = "swintr_intercept",
104     .init = init_swintr_intercept,
105     .deinit = NULL,
106     .core_init = init_swintr_intercept_core,
107     .core_deinit = NULL,
108     .on_entry = NULL,
109     .on_exit = NULL
110 };
111
112
113 register_extension(&swintr_impl);
114
115
116 int v3_handle_swintr (struct guest_info * core) {
117
118     int ret = 0;
119     void * instr_ptr = NULL;
120     struct x86_instr instr;
121
122     if (core->mem_mode == PHYSICAL_MEM) { 
123         ret = v3_gpa_to_hva(core, get_addr_linear(core, core->rip, &(core->segments.cs)), (addr_t *)&instr_ptr);
124     } else { 
125         ret = v3_gva_to_hva(core, get_addr_linear(core, core->rip, &(core->segments.cs)), (addr_t *)&instr_ptr);
126     }   
127     
128     if (ret == -1) {
129         PrintError("V3 SWintr Handler: Could not translate Instruction Address (%p)\n", (void *)core->rip);
130         return -1; 
131     }   
132
133     if (v3_decode(core, (addr_t)instr_ptr, &instr) == -1) {
134         PrintError("V3 SWintr Handler: Decoding Error\n");
135         return -1; 
136     }   
137
138     uint8_t vector = instr.dst_operand.operand;
139
140     struct v3_swintr_hook * hook = swintr_hooks[vector];
141     if (hook == NULL) {
142 #ifdef V3_CONFIG_EXT_SWINTR_PASSTHROUGH
143         if (v3_hook_passthrough_swintr(core, vector) == -1) {
144             PrintDebug("V3 SWintr Handler: Error hooking passthrough swintr\n");
145             return -1; 
146         }
147         hook = swintr_hooks[vector];
148 #else
149         core->rip += instr.instr_length;
150         return v3_raise_swintr(core, vector);
151 #endif
152     }   
153
154     ret = hook->handler(core, vector, NULL);
155     if (ret == -1) {
156         PrintDebug("V3 SWintr Handler: Error in swintr hook\n");
157         return -1; 
158     }   
159
160 #ifdef V3_CONFIG_EXT_CODE_INJECT
161 // this is for injecting page faults
162 // we don't want to increment rip or inject
163 // the swint if we need to fault a page in
164     if (ret == E_NEED_PF) {
165         return 0;
166     }
167 #endif
168     /* at some point we _may_ need to prioritize swints 
169        so that they finish in time for the next
170        instruction... */
171     core->rip += instr.instr_length;
172     return v3_raise_swintr(core, vector);
173 }
174
175
176
177 int v3_hook_swintr (struct guest_info * core,
178         uint8_t vector,
179         int (*handler)(struct guest_info * core, uint8_t vector, void * priv_data),
180         void * priv_data)
181 {
182     struct v3_swintr_hook * hook = (struct v3_swintr_hook*)V3_Malloc(sizeof(struct v3_swintr_hook));
183
184     if (hook == NULL) {
185         PrintError("Cannot allocate for swintr hook\n");
186         return -1;
187     }
188
189     if (get_swintr_hook(core, vector) != NULL) {
190         PrintError("swint %d already hooked\n", vector);
191         return -1;
192     }
193     
194     hook->handler = handler;
195     hook->priv_data = priv_data;
196
197     swintr_hooks[vector] = hook;
198
199     PrintDebug("Hooked Swintr #%d\n", vector);
200
201     return 0;
202 }
203     
204
205 static int passthrough_swintr_handler (struct guest_info * core, uint8_t vector, void * priv_data) {
206     PrintDebug("[passthrough_swint_handler] INT vector=%d (guest=0x%p)\n",
207         vector, (void*)core);
208     return 0;
209 }
210
211
212 int v3_hook_passthrough_swintr (struct guest_info * core, uint8_t vector) {
213     
214     int rc = v3_hook_swintr(core, vector, passthrough_swintr_handler, NULL);
215     
216     if (rc) {
217         PrintError("guest_swintr_injection: failed to hook swint 0x%x (guest=0x%p)\n", vector, (void*)core);
218         return -1;
219     } else {
220         PrintDebug("guest_swintr_injection: hooked swint 0x%x (guest=0x%p)\n", vector, (void*)core);
221         return 0;
222     }
223     
224     /* shouldn't get here */
225     return 0;
226 }
227
228