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".
21 #include <palacios/vmm.h>
22 #include <palacios/vmm_msr.h>
23 #include <palacios/vmm_mem.h>
24 #include <palacios/vmm_hypercall.h>
26 #define SYM_PAGE_MSR 0x535
28 #define SYM_CPUID_NUM 0x90000000
30 #define SYM_CALL_RET_HCALL 0x535
33 /* Notes: We use a combination of SYSCALL and SYSENTER Semantics
34 * SYSCALL just sets an EIP, CS/SS seg, and GS seg via swapgs
35 * the RSP is loaded via the structure pointed to by GS
36 * This is safe because it assumes that system calls are guaranteed to be made with an empty kernel stack.
37 * We cannot make that assumption with a symcall, so we have to have our own stack area somewhere.
38 * SYSTENTER does not really use the GS base MSRs, but we do to map to 64 bit kernels
41 #define SYMCALL_RIP_MSR 0x536
42 #define SYMCALL_RSP_MSR 0x537
43 #define SYMCALL_CS_MSR 0x538
44 #define SYMCALL_GS_MSR 0x539
45 #define SYMCALL_FS_MSR 0x540
48 static int msr_read(uint_t msr, struct v3_msr * dst, void * priv_data) {
49 struct guest_info * info = (struct guest_info *)priv_data;
50 struct v3_sym_state * state = &(info->sym_state);
54 dst->value = state->guest_pg_addr;
57 dst->value = state->sym_call_rip;
60 dst->value = state->sym_call_rsp;
63 dst->value = state->sym_call_cs;
66 dst->value = state->sym_call_gs;
69 dst->value = state->sym_call_fs;
78 static int msr_write(uint_t msr, struct v3_msr src, void * priv_data) {
79 struct guest_info * info = (struct guest_info *)priv_data;
80 struct v3_sym_state * state = &(info->sym_state);
82 if (msr == SYM_PAGE_MSR) {
83 PrintDebug("Symbiotic MSR write for page %p\n", (void *)src.value);
85 if (state->active == 1) {
87 struct v3_shadow_region * old_reg = v3_get_shadow_region(info, (addr_t)state->guest_pg_addr);
89 if (old_reg == NULL) {
90 PrintError("Could not find previously active symbiotic page (%p)\n", (void *)state->guest_pg_addr);
94 v3_delete_shadow_region(info, old_reg);
97 state->guest_pg_addr = src.value;
98 state->guest_pg_addr &= ~0xfffLL;
103 v3_add_shadow_mem(info, (addr_t)state->guest_pg_addr,
104 (addr_t)(state->guest_pg_addr + PAGE_SIZE_4KB - 1),
108 } else if (msr == SYMCALL_RIP_MSR) {
109 state->sym_call_rip = src.value;
110 } else if (msr == SYMCALL_RSP_MSR) {
111 state->sym_call_rsp = src.value;
112 } else if (msr == SYMCALL_CS_MSR) {
113 state->sym_call_cs = src.value;
114 } else if (msr == SYMCALL_GS_MSR) {
115 state->sym_call_gs = src.value;
116 } else if (msr == SYMCALL_FS_MSR) {
117 state->sym_call_fs = src.value;
119 PrintError("Invalid Symbiotic MSR write (0x%x)\n", msr);
126 static int cpuid_fn(struct guest_info * info, uint32_t cpuid,
127 uint32_t * eax, uint32_t * ebx,
128 uint32_t * ecx, uint32_t * edx,
129 void * private_data) {
130 extern v3_cpu_arch_t v3_cpu_types[];
132 *eax = *(uint32_t *)"V3V";
134 if ((v3_cpu_types[info->cpu_id] == V3_SVM_CPU) ||
135 (v3_cpu_types[info->cpu_id] == V3_SVM_REV3_CPU)) {
136 *ebx = *(uint32_t *)"SVM";
137 } else if ((v3_cpu_types[info->cpu_id] == V3_VMX_CPU) ||
138 (v3_cpu_types[info->cpu_id] == V3_VMX_EPT_CPU)) {
139 *ebx = *(uint32_t *)"VMX";
147 static int sym_call_ret(struct guest_info * info, uint_t hcall_id, void * private_data);
151 int v3_init_sym_iface(struct guest_info * info) {
152 struct v3_sym_state * state = &(info->sym_state);
153 memset(state, 0, sizeof(struct v3_sym_state));
155 state->sym_page_pa = (addr_t)V3_AllocPages(1);
156 state->sym_page = (struct v3_sym_interface *)V3_VAddr((void *)state->sym_page_pa);
157 memset(state->sym_page, 0, PAGE_SIZE_4KB);
160 memcpy(&(state->sym_page->magic), "V3V", 3);
162 v3_hook_msr(info, SYM_PAGE_MSR, msr_read, msr_write, info);
164 v3_hook_cpuid(info, SYM_CPUID_NUM, cpuid_fn, info);
166 v3_hook_msr(info, SYMCALL_RIP_MSR, msr_read, msr_write, info);
167 v3_hook_msr(info, SYMCALL_RSP_MSR, msr_read, msr_write, info);
168 v3_hook_msr(info, SYMCALL_CS_MSR, msr_read, msr_write, info);
169 v3_hook_msr(info, SYMCALL_GS_MSR, msr_read, msr_write, info);
170 v3_hook_msr(info, SYMCALL_FS_MSR, msr_read, msr_write, info);
172 v3_register_hypercall(info, SYM_CALL_RET_HCALL, sym_call_ret, NULL);
177 int v3_sym_map_pci_passthrough(struct guest_info * info, uint_t bus, uint_t dev, uint_t fn) {
178 struct v3_sym_state * state = &(info->sym_state);
179 uint_t dev_index = (bus << 8) + (dev << 3) + fn;
180 uint_t major = dev_index / 8;
181 uint_t minor = dev_index % 8;
184 PrintError("Invalid PCI bus %d\n", bus);
188 PrintDebug("Setting passthrough pci map for index=%d\n", dev_index);
190 state->sym_page->pci_pt_map[major] |= 0x1 << minor;
192 PrintDebug("pt_map entry=%x\n", state->sym_page->pci_pt_map[major]);
194 PrintDebug("pt map vmm addr=%p\n", state->sym_page->pci_pt_map);
199 int v3_sym_unmap_pci_passthrough(struct guest_info * info, uint_t bus, uint_t dev, uint_t fn) {
200 struct v3_sym_state * state = &(info->sym_state);
201 uint_t dev_index = (bus << 8) + (dev << 3) + fn;
202 uint_t major = dev_index / 8;
203 uint_t minor = dev_index % 8;
206 PrintError("Invalid PCI bus %d\n", bus);
210 state->sym_page->pci_pt_map[major] &= ~(0x1 << minor);
217 static int sym_call_ret(struct guest_info * info, uint_t hcall_id, void * private_data) {
218 struct v3_sym_state * state = (struct v3_sym_state *)&(info->sym_state);
219 struct v3_sym_context * old_ctx = (struct v3_sym_context *)&(state->old_ctx);
222 PrintError("Return from sym call\n");
223 v3_print_guest_state(info);
224 v3_print_mem_map(info);
227 if (state->notifier != NULL) {
228 if (state->notifier(info, state->private_data) == -1) {
229 PrintError("Error in return from symcall.\n");
235 // restore guest state
236 memcpy(&(info->vm_regs), &(old_ctx->vm_regs), sizeof(struct v3_gprs));
237 memcpy(&(info->segments.cs), &(old_ctx->cs), sizeof(struct v3_segment));
238 memcpy(&(info->segments.ss), &(old_ctx->ss), sizeof(struct v3_segment));
239 info->segments.gs.base = old_ctx->gs_base;
240 info->segments.fs.base = old_ctx->fs_base;
241 info->rip = old_ctx->rip;
242 info->cpl = old_ctx->cpl;
245 PrintDebug("restoring guest state\n");
246 v3_print_guest_state(info);
249 state->call_active = 0;
256 int v3_sym_call(struct guest_info * info,
257 uint64_t call_num, uint64_t arg0,
258 uint64_t arg1, uint64_t arg2,
259 uint64_t arg3, uint64_t arg4,
260 int (*notifier)(struct guest_info * info, void * private_data),
261 void * private_data) {
262 struct v3_sym_state * state = (struct v3_sym_state *)&(info->sym_state);
265 PrintDebug("Making Sym call\n");
267 if ((state->sym_page->sym_call_enabled == 0) ||
268 (state->call_active == 1) ||
269 (state->call_pending == 1)) {
273 state->args[0] = call_num;
274 state->args[1] = arg0;
275 state->args[2] = arg1;
276 state->args[3] = arg2;
277 state->args[4] = arg3;
278 state->args[5] = arg4;
280 state->notifier = notifier;
281 state->private_data = private_data;
283 state->call_pending = 1;
290 int v3_activate_sym_call(struct guest_info * info) {
291 struct v3_sym_state * state = (struct v3_sym_state *)&(info->sym_state);
292 struct v3_sym_context * old_ctx = (struct v3_sym_context *)&(state->old_ctx);
293 struct v3_segment sym_cs;
294 struct v3_segment sym_ss;
297 if ((state->sym_page->sym_call_enabled == 0) ||
298 (state->call_pending == 0)) {
299 // Unable to make sym call or none pending
300 if (state->call_active == 1) {
301 PrintError("handled exit while in symcall\n");
307 PrintDebug("Activating Symbiotic call\n");
308 v3_print_guest_state(info);
311 // Save the old context
312 memcpy(&(old_ctx->vm_regs), &(info->vm_regs), sizeof(struct v3_gprs));
313 memcpy(&(old_ctx->cs), &(info->segments.cs), sizeof(struct v3_segment));
314 memcpy(&(old_ctx->ss), &(info->segments.ss), sizeof(struct v3_segment));
315 old_ctx->gs_base = info->segments.gs.base;
316 old_ctx->fs_base = info->segments.fs.base;
317 old_ctx->rip = info->rip;
318 old_ctx->cpl = info->cpl;
322 // Setup the sym call context
323 info->rip = state->sym_call_rip;
324 info->vm_regs.rsp = state->sym_call_rsp;
326 v3_translate_segment(info, state->sym_call_cs, &sym_cs);
327 memcpy(&(info->segments.cs), &sym_cs, sizeof(struct v3_segment));
329 v3_translate_segment(info, state->sym_call_cs + 8, &sym_ss);
330 memcpy(&(info->segments.ss), &sym_ss, sizeof(struct v3_segment));
332 info->segments.gs.base = state->sym_call_gs;
333 info->segments.fs.base = state->sym_call_fs;
336 info->vm_regs.rax = state->args[0];
337 info->vm_regs.rbx = state->args[1];
338 info->vm_regs.rcx = state->args[2];
339 info->vm_regs.rdx = state->args[3];
340 info->vm_regs.rsi = state->args[4];
341 info->vm_regs.rdi = state->args[5];
343 // Mark sym call as active
344 state->call_pending = 0;
345 state->call_active = 1;
348 PrintDebug("Sym state\n");
349 v3_print_guest_state(info);