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.
6 * The V3VEE Project is a joint project between Northwestern University
7 * and the University of New Mexico. You can find out more at
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.
14 * Author: Jack Lange <jarusl@cs.northwestern.edu>
16 * This is free software. You are permitted to use,
17 * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
20 #include <palacios/vm_guest.h>
21 #include <palacios/vmm_symcall.h>
22 #include <palacios/vmm_symspy.h>
23 #include <palacios/vmm_msr.h>
25 // A succesfull symcall returns via the RET_HCALL, with the return values in registers
26 // A symcall error returns via the ERR_HCALL with the error code in rbx
29 /* Notes: We use a combination of SYSCALL and SYSENTER Semantics
30 * SYSCALL just sets an EIP, CS/SS seg, and GS seg via swapgs
31 * the RSP is loaded via the structure pointed to by GS
32 * This is safe because it assumes that system calls are guaranteed to be made with an empty kernel stack.
33 * We cannot make that assumption with a symcall, so we have to have our own stack area somewhere.
34 * SYSTENTER does not really use the GS base MSRs, but we do to map to 64 bit kernels
37 #define SYMCALL_RIP_MSR 0x536
38 #define SYMCALL_RSP_MSR 0x537
39 #define SYMCALL_CS_MSR 0x538
40 #define SYMCALL_GS_MSR 0x539
41 #define SYMCALL_FS_MSR 0x540
44 static int symcall_msr_read(struct guest_info * core, uint_t msr,
45 struct v3_msr * dst, void * priv_data) {
46 struct v3_symcall_state * state = &(core->sym_core_state.symcall_state);
50 dst->value = state->sym_call_rip;
53 dst->value = state->sym_call_rsp;
56 dst->value = state->sym_call_cs;
59 dst->value = state->sym_call_gs;
62 dst->value = state->sym_call_fs;
71 static int symcall_msr_write(struct guest_info * core, uint_t msr, struct v3_msr src, void * priv_data) {
72 struct v3_symcall_state * state = &(core->sym_core_state.symcall_state);
76 state->sym_call_rip = src.value;
79 state->sym_call_rsp = src.value;
82 state->sym_call_cs = src.value;
85 state->sym_call_gs = src.value;
88 state->sym_call_fs = src.value;
91 PrintError("Invalid Symbiotic MSR write (0x%x)\n", msr);
98 static int sym_call_ret(struct guest_info * info, uint_t hcall_id, void * private_data);
99 static int sym_call_err(struct guest_info * info, uint_t hcall_id, void * private_data);
104 int v3_init_symcall_vm(struct v3_vm_info * vm) {
106 v3_hook_msr(vm, SYMCALL_RIP_MSR, symcall_msr_read, symcall_msr_write, NULL);
107 v3_hook_msr(vm, SYMCALL_RSP_MSR, symcall_msr_read, symcall_msr_write, NULL);
108 v3_hook_msr(vm, SYMCALL_CS_MSR, symcall_msr_read, symcall_msr_write, NULL);
109 v3_hook_msr(vm, SYMCALL_GS_MSR, symcall_msr_read, symcall_msr_write, NULL);
110 v3_hook_msr(vm, SYMCALL_FS_MSR, symcall_msr_read, symcall_msr_write, NULL);
112 v3_register_hypercall(vm, SYMCALL_RET_HCALL, sym_call_ret, NULL);
113 v3_register_hypercall(vm, SYMCALL_ERR_HCALL, sym_call_err, NULL);
123 static int sym_call_err(struct guest_info * core, uint_t hcall_id, void * private_data) {
124 struct v3_symcall_state * state = (struct v3_symcall_state *)&(core->sym_core_state.symcall_state);
126 PrintError("sym call error\n");
128 state->sym_call_errno = (int)core->vm_regs.rbx;
129 v3_print_guest_state(core);
130 v3_print_mem_map(core->vm_info);
133 state->sym_call_error = 1;
134 state->sym_call_returned = 1;
139 static int sym_call_ret(struct guest_info * core, uint_t hcall_id, void * private_data) {
140 struct v3_symcall_state * state = (struct v3_symcall_state *)&(core->sym_core_state.symcall_state);
142 // PrintError("Return from sym call (ID=%x)\n", hcall_id);
143 // v3_print_guest_state(info);
145 state->sym_call_returned = 1;
150 static int execute_symcall(struct guest_info * core) {
151 struct v3_symcall_state * state = (struct v3_symcall_state *)&(core->sym_core_state.symcall_state);
153 while (state->sym_call_returned == 0) {
154 if (v3_vm_enter(core) == -1) {
155 PrintError("Error in Sym call\n");
165 // We don't handle those fancy 64 bit system segments...
167 static int translate_segment(struct guest_info * info, uint16_t selector, struct v3_segment * seg) {
168 struct v3_segment * gdt = &(info->segments.gdtr);
170 uint16_t seg_offset = (selector & ~0x7);
172 struct gen_segment * gen_seg = NULL;
173 struct seg_selector sel;
175 memset(seg, 0, sizeof(struct v3_segment));
177 sel.value = selector;
180 PrintError("LDT translations not supported\n");
184 if (v3_gva_to_hva(info, gdt->base, &gdt_addr) == -1) {
185 PrintError("Unable to translate GDT address\n");
189 seg_addr = gdt_addr + seg_offset;
190 gen_seg = (struct gen_segment *)seg_addr;
193 seg->selector = selector;
195 seg->limit = gen_seg->limit_hi;
197 seg->limit += gen_seg->limit_lo;
199 seg->base = gen_seg->base_hi;
201 seg->base += gen_seg->base_lo;
203 if (gen_seg->granularity == 1) {
208 seg->type = gen_seg->type;
209 seg->system = gen_seg->system;
210 seg->dpl = gen_seg->dpl;
211 seg->present = gen_seg->present;
212 seg->avail = gen_seg->avail;
213 seg->long_mode = gen_seg->long_mode;
214 seg->db = gen_seg->db;
215 seg->granularity = gen_seg->granularity;
222 int v3_sym_call(struct guest_info * core,
223 uint64_t call_num, sym_arg_t * arg0,
224 sym_arg_t * arg1, sym_arg_t * arg2,
225 sym_arg_t * arg3, sym_arg_t * arg4) {
226 struct v3_symcall_state * state = (struct v3_symcall_state *)&(core->sym_core_state.symcall_state);
227 struct v3_symspy_local_state * symspy_state = (struct v3_symspy_local_state *)&(core->sym_core_state.symspy_state);
228 struct v3_sym_cpu_context * old_ctx = (struct v3_sym_cpu_context *)&(state->old_ctx);
229 struct v3_segment sym_cs;
230 struct v3_segment sym_ss;
231 uint64_t trash_args[5] = { [0 ... 4] = 0 };
233 // PrintDebug("Making Sym call\n");
234 // v3_print_guest_state(info);
236 if ((symspy_state->local_page->sym_call_enabled == 0) ||
237 (symspy_state->local_page->sym_call_active == 1)) {
241 if (!arg0) arg0 = &trash_args[0];
242 if (!arg1) arg1 = &trash_args[1];
243 if (!arg2) arg2 = &trash_args[2];
244 if (!arg3) arg3 = &trash_args[3];
245 if (!arg4) arg4 = &trash_args[4];
247 // Save the old context
248 memcpy(&(old_ctx->vm_regs), &(core->vm_regs), sizeof(struct v3_gprs));
249 memcpy(&(old_ctx->cs), &(core->segments.cs), sizeof(struct v3_segment));
250 memcpy(&(old_ctx->ss), &(core->segments.ss), sizeof(struct v3_segment));
251 old_ctx->gs_base = core->segments.gs.base;
252 old_ctx->fs_base = core->segments.fs.base;
253 old_ctx->rip = core->rip;
254 old_ctx->cpl = core->cpl;
255 old_ctx->flags = core->ctrl_regs.rflags;
257 // Setup the sym call context
258 core->rip = state->sym_call_rip;
259 core->vm_regs.rsp = state->sym_call_rsp; // old contest rsp is saved in vm_regs
261 translate_segment(core, state->sym_call_cs, &sym_cs);
262 memcpy(&(core->segments.cs), &sym_cs, sizeof(struct v3_segment));
264 translate_segment(core, state->sym_call_cs + 8, &sym_ss);
265 memcpy(&(core->segments.ss), &sym_ss, sizeof(struct v3_segment));
267 core->segments.gs.base = state->sym_call_gs;
268 core->segments.fs.base = state->sym_call_fs;
271 core->vm_regs.rax = call_num;
272 core->vm_regs.rbx = *arg0;
273 core->vm_regs.rcx = *arg1;
274 core->vm_regs.rdx = *arg2;
275 core->vm_regs.rsi = *arg3;
276 core->vm_regs.rdi = *arg4;
278 // Mark sym call as active
279 state->sym_call_active = 1;
280 state->sym_call_returned = 0;
282 // PrintDebug("Sym state\n");
283 // v3_print_guest_state(core);
285 // Do the sym call entry
286 if (execute_symcall(core) == -1) {
287 PrintError("SYMCALL error\n");
292 state->sym_call_active = 0;
294 *arg0 = core->vm_regs.rbx;
295 *arg1 = core->vm_regs.rcx;
296 *arg2 = core->vm_regs.rdx;
297 *arg3 = core->vm_regs.rsi;
298 *arg4 = core->vm_regs.rdi;
300 // restore guest state
301 memcpy(&(core->vm_regs), &(old_ctx->vm_regs), sizeof(struct v3_gprs));
302 memcpy(&(core->segments.cs), &(old_ctx->cs), sizeof(struct v3_segment));
303 memcpy(&(core->segments.ss), &(old_ctx->ss), sizeof(struct v3_segment));
304 core->segments.gs.base = old_ctx->gs_base;
305 core->segments.fs.base = old_ctx->fs_base;
306 core->rip = old_ctx->rip;
307 core->cpl = old_ctx->cpl;
308 core->ctrl_regs.rflags = old_ctx->flags;
312 // PrintError("restoring guest state\n");
313 // v3_print_guest_state(core);