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.


New Gears Tools And Structure
[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         return -1;
186     }
187
188     if (get_swintr_hook(core, vector) != NULL) {
189         PrintError("swint %d already hooked\n", vector);
190         return -1;
191     }
192     
193     hook->handler = handler;
194     hook->priv_data = priv_data;
195
196     swintr_hooks[vector] = hook;
197
198     PrintDebug("Hooked Swintr #%d\n", vector);
199
200     return 0;
201 }
202     
203
204 static int passthrough_swintr_handler (struct guest_info * core, uint8_t vector, void * priv_data) {
205     PrintDebug("[passthrough_swint_handler] INT vector=%d (guest=0x%p)\n",
206         vector, (void*)core);
207     return 0;
208 }
209
210
211 int v3_hook_passthrough_swintr (struct guest_info * core, uint8_t vector) {
212     
213     int rc = v3_hook_swintr(core, vector, passthrough_swintr_handler, NULL);
214     
215     if (rc) {
216         PrintError("guest_swintr_injection: failed to hook swint 0x%x (guest=0x%p)\n", vector, (void*)core);
217         return -1;
218     } else {
219         PrintDebug("guest_swintr_injection: hooked swint 0x%x (guest=0x%p)\n", vector, (void*)core);
220         return 0;
221     }
222     
223     /* shouldn't get here */
224     return 0;
225 }
226
227