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");
164 int v3_sym_call(struct guest_info * core,
165 uint64_t call_num, sym_arg_t * arg0,
166 sym_arg_t * arg1, sym_arg_t * arg2,
167 sym_arg_t * arg3, sym_arg_t * arg4) {
168 struct v3_symcall_state * state = (struct v3_symcall_state *)&(core->sym_core_state.symcall_state);
169 struct v3_symspy_local_state * symspy_state = (struct v3_symspy_local_state *)&(core->sym_core_state.symspy_state);
170 struct v3_sym_cpu_context * old_ctx = (struct v3_sym_cpu_context *)&(state->old_ctx);
171 struct v3_segment sym_cs;
172 struct v3_segment sym_ss;
173 uint64_t trash_args[5] = { [0 ... 4] = 0 };
175 // PrintDebug("Making Sym call\n");
176 // v3_print_guest_state(info);
178 if ((symspy_state->local_page->sym_call_enabled == 0) ||
179 (symspy_state->local_page->sym_call_active == 1)) {
183 if (!arg0) arg0 = &trash_args[0];
184 if (!arg1) arg1 = &trash_args[1];
185 if (!arg2) arg2 = &trash_args[2];
186 if (!arg3) arg3 = &trash_args[3];
187 if (!arg4) arg4 = &trash_args[4];
189 // Save the old context
190 memcpy(&(old_ctx->vm_regs), &(core->vm_regs), sizeof(struct v3_gprs));
191 memcpy(&(old_ctx->cs), &(core->segments.cs), sizeof(struct v3_segment));
192 memcpy(&(old_ctx->ss), &(core->segments.ss), sizeof(struct v3_segment));
193 old_ctx->gs_base = core->segments.gs.base;
194 old_ctx->fs_base = core->segments.fs.base;
195 old_ctx->rip = core->rip;
196 old_ctx->cpl = core->cpl;
197 old_ctx->flags = core->ctrl_regs.rflags;
199 // Setup the sym call context
200 core->rip = state->sym_call_rip;
201 core->vm_regs.rsp = state->sym_call_rsp; // old contest rsp is saved in vm_regs
203 v3_translate_segment(core, state->sym_call_cs, &sym_cs);
204 memcpy(&(core->segments.cs), &sym_cs, sizeof(struct v3_segment));
206 v3_translate_segment(core, state->sym_call_cs + 8, &sym_ss);
207 memcpy(&(core->segments.ss), &sym_ss, sizeof(struct v3_segment));
209 core->segments.gs.base = state->sym_call_gs;
210 core->segments.fs.base = state->sym_call_fs;
213 core->vm_regs.rax = call_num;
214 core->vm_regs.rbx = *arg0;
215 core->vm_regs.rcx = *arg1;
216 core->vm_regs.rdx = *arg2;
217 core->vm_regs.rsi = *arg3;
218 core->vm_regs.rdi = *arg4;
220 // Mark sym call as active
221 state->sym_call_active = 1;
222 state->sym_call_returned = 0;
224 // PrintDebug("Sym state\n");
225 // v3_print_guest_state(core);
227 // Do the sym call entry
228 if (execute_symcall(core) == -1) {
229 PrintError("SYMCALL error\n");
234 state->sym_call_active = 0;
236 *arg0 = core->vm_regs.rbx;
237 *arg1 = core->vm_regs.rcx;
238 *arg2 = core->vm_regs.rdx;
239 *arg3 = core->vm_regs.rsi;
240 *arg4 = core->vm_regs.rdi;
242 // restore guest state
243 memcpy(&(core->vm_regs), &(old_ctx->vm_regs), sizeof(struct v3_gprs));
244 memcpy(&(core->segments.cs), &(old_ctx->cs), sizeof(struct v3_segment));
245 memcpy(&(core->segments.ss), &(old_ctx->ss), sizeof(struct v3_segment));
246 core->segments.gs.base = old_ctx->gs_base;
247 core->segments.fs.base = old_ctx->fs_base;
248 core->rip = old_ctx->rip;
249 core->cpl = old_ctx->cpl;
250 core->ctrl_regs.rflags = old_ctx->flags;
254 // PrintError("restoring guest state\n");
255 // v3_print_guest_state(core);