X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?a=blobdiff_plain;f=palacios%2Fsrc%2Fpalacios%2Fvmx_assist.c;fp=palacios%2Fsrc%2Fpalacios%2Fvmx_assist.c;h=8a12fe7f772a24292d7f5e305753599277a2d26d;hb=61597ea2c5ccace036d8a65e429e32b8f8a7ed4a;hp=0000000000000000000000000000000000000000;hpb=f3eb8bbb7c58c98b03797f2188e6c1d2a7610c15;p=palacios.git diff --git a/palacios/src/palacios/vmx_assist.c b/palacios/src/palacios/vmx_assist.c new file mode 100644 index 0000000..8a12fe7 --- /dev/null +++ b/palacios/src/palacios/vmx_assist.c @@ -0,0 +1,217 @@ +/* + * This file is part of the Palacios Virtual Machine Monitor developed + * by the V3VEE Project with funding from the United States National + * Science Foundation and the Department of Energy. + * + * The V3VEE Project is a joint project between Northwestern University + * and the University of New Mexico. You can find out more at + * http://www.v3vee.org + * + * Copyright (c) 2008, Andy Gocke + * Copyright (c) 2008, The V3VEE Project + * All rights reserved. + * + * Author: Andy Gocke + * + * This is free software. You are permitted to use, + * redistribute, and modify it as specified in the file "V3VEE_LICENSE". + */ + +#include +#include +#include +#include + +static int vmx_save_world_ctx(struct guest_info * info, struct vmx_assist_context * ctx); +static int vmx_restore_world_ctx(struct guest_info * info, struct vmx_assist_context * ctx); + +int v3_vmxassist_ctx_switch(struct guest_info * info) { + uint32_t vmx_magic = 0; // Magic number to check for vmxassist + struct vmx_assist_context * old_ctx = NULL; + struct vmx_assist_context * new_ctx = NULL; + uint32_t old_ctx_gpa = 0; + uint32_t new_ctx_gpa = 0; + vmx_state_t state = ((struct vmx_data *)info->vmm_data)->state; + + /* Check validity of VMXASSIST_MAGIC field */ + if (read_guest_pa_memory(info, VMXASSIST_MAGIC_OFFSET, sizeof(vmx_magic), (uint8_t *)&vmx_magic) != sizeof(vmx_magic)) { + PrintError("Could not read guest VMXASSIST magic field\n"); + return -1; + } + + if (vmx_magic != VMXASSIST_MAGIC) { + PrintError("VMXASSIT_MAGIC field is invalid\n"); + return -1; + } + + + /* Retrieve the pointer to the Old Context struct */ + if (read_guest_pa_memory(info, VMXASSIST_OLD_CONTEXT, sizeof(old_ctx_gpa), (uint8_t *)&old_ctx_gpa) != sizeof(old_ctx_gpa)) { + PrintError("Could not read Old Context pointer field\n"); + return -1; + } + + guest_pa_to_host_va(info, (addr_t)old_ctx_gpa, (addr_t *)&(old_ctx)); + + + /* Retrieve the pointer to the New Context struct */ + if (read_guest_pa_memory(info, VMXASSIST_NEW_CONTEXT, sizeof(new_ctx_gpa), (uint8_t *)&new_ctx_gpa) != sizeof(new_ctx_gpa)) { + PrintError("Could not read New Context pointer field\n"); + return -1; + } + + guest_pa_to_host_va(info, (addr_t)new_ctx_gpa, (addr_t *)&(new_ctx)); + + + + if (state == VMXASSIST_DISABLED) { + + /* Save the old Context */ + if (vmx_save_world_ctx(info, old_ctx) != 0) { + PrintError("Could not save VMXASSIST world context\n"); + return -1; + } + + /* restore new context, vmxassist should launch the bios the first time */ + if (vmx_restore_world_ctx(info, new_ctx) != 0) { + PrintError("VMXASSIST could not restore new context\n"); + return -1; + } + + } else if (state == VMXASSIST_ENABLED) { + /* restore old context */ + if (vmx_restore_world_ctx(info, old_ctx) != 0) { + PrintError("VMXASSIST could not restore old context\n"); + return -1; + } + } + + return 0; +} + + +int vmx_save_world_ctx(struct guest_info * info, struct vmx_assist_context * ctx) { + int error = 0; + + PrintDebug("Writing from RIP: 0x%p\n", (void *)info->rip); + + error |= vmcs_read(VMCS_GUEST_RIP, &(ctx->eip)); + error |= vmcs_read(VMCS_GUEST_RSP, &(ctx->esp)); + error |= vmcs_read(VMCS_GUEST_RFLAGS, &(ctx->eflags)); + + error |= vmcs_read(VMCS_CR0_READ_SHDW, &(ctx->cr0)); + ctx->cr3 = info->shdw_pg_state.guest_cr3; + error |= vmcs_read(VMCS_CR4_READ_SHDW, &(ctx->cr4)); + + error |= vmcs_read(VMCS_GUEST_IDTR_LIMIT, &(ctx->idtr_limit)); + error |= vmcs_read(VMCS_GUEST_IDTR_BASE, &(ctx->idtr_base)); + + error |= vmcs_read(VMCS_GUEST_GDTR_LIMIT, &(ctx->gdtr_limit)); + error |= vmcs_read(VMCS_GUEST_GDTR_BASE, &(ctx->gdtr_base)); + + error |= vmcs_read(VMCS_GUEST_CS_SELECTOR, &(ctx->cs_sel)); + error |= vmcs_read(VMCS_GUEST_CS_LIMIT, &(ctx->cs_limit)); + error |= vmcs_read(VMCS_GUEST_CS_BASE, &(ctx->cs_base)); + error |= vmcs_read(VMCS_GUEST_CS_ACCESS, &(ctx->cs_arbytes.bytes)); + + error |= vmcs_read(VMCS_GUEST_DS_SELECTOR, &(ctx->ds_sel)); + error |= vmcs_read(VMCS_GUEST_DS_LIMIT, &(ctx->ds_limit)); + error |= vmcs_read(VMCS_GUEST_DS_BASE, &(ctx->ds_base)); + error |= vmcs_read(VMCS_GUEST_DS_ACCESS, &(ctx->ds_arbytes.bytes)); + + error |= vmcs_read(VMCS_GUEST_ES_SELECTOR, &(ctx->es_sel)); + error |= vmcs_read(VMCS_GUEST_ES_LIMIT, &(ctx->es_limit)); + error |= vmcs_read(VMCS_GUEST_ES_BASE, &(ctx->es_base)); + error |= vmcs_read(VMCS_GUEST_ES_ACCESS, &(ctx->es_arbytes.bytes)); + + error |= vmcs_read(VMCS_GUEST_SS_SELECTOR, &(ctx->ss_sel)); + error |= vmcs_read(VMCS_GUEST_SS_LIMIT, &(ctx->ss_limit)); + error |= vmcs_read(VMCS_GUEST_SS_BASE, &(ctx->ss_base)); + error |= vmcs_read(VMCS_GUEST_SS_ACCESS, &(ctx->ss_arbytes.bytes)); + + error |= vmcs_read(VMCS_GUEST_FS_SELECTOR, &(ctx->fs_sel)); + error |= vmcs_read(VMCS_GUEST_FS_LIMIT, &(ctx->fs_limit)); + error |= vmcs_read(VMCS_GUEST_FS_BASE, &(ctx->fs_base)); + error |= vmcs_read(VMCS_GUEST_FS_ACCESS, &(ctx->fs_arbytes.bytes)); + + error |= vmcs_read(VMCS_GUEST_GS_SELECTOR, &(ctx->gs_sel)); + error |= vmcs_read(VMCS_GUEST_GS_LIMIT, &(ctx->gs_limit)); + error |= vmcs_read(VMCS_GUEST_GS_BASE, &(ctx->gs_base)); + error |= vmcs_read(VMCS_GUEST_GS_ACCESS, &(ctx->gs_arbytes.bytes)); + + error |= vmcs_read(VMCS_GUEST_TR_SELECTOR, &(ctx->tr_sel)); + error |= vmcs_read(VMCS_GUEST_TR_LIMIT, &(ctx->tr_limit)); + error |= vmcs_read(VMCS_GUEST_TR_BASE, &(ctx->tr_base)); + error |= vmcs_read(VMCS_GUEST_TR_ACCESS, &(ctx->tr_arbytes.bytes)); + + error |= vmcs_read(VMCS_GUEST_LDTR_SELECTOR, &(ctx->ldtr_sel)); + error |= vmcs_read(VMCS_GUEST_LDTR_LIMIT, &(ctx->ldtr_limit)); + error |= vmcs_read(VMCS_GUEST_LDTR_BASE, &(ctx->ldtr_base)); + error |= vmcs_read(VMCS_GUEST_LDTR_ACCESS, &(ctx->ldtr_arbytes.bytes)); + + return error; +} + +int vmx_restore_world_ctx(struct guest_info * info, struct vmx_assist_context * ctx) { + int error = 0; + + PrintDebug("ctx rip: %p\n", (void *)(addr_t)ctx->eip); + + error |= vmcs_write(VMCS_GUEST_RIP, ctx->eip); + error |= vmcs_write(VMCS_GUEST_RSP, ctx->esp); + error |= vmcs_write(VMCS_GUEST_RFLAGS, ctx->eflags); + + error |= vmcs_write(VMCS_CR0_READ_SHDW, ctx->cr0); + info->shdw_pg_state.guest_cr3 = ctx->cr3; + error |= vmcs_write(VMCS_CR4_READ_SHDW, ctx->cr4); + + error |= vmcs_write(VMCS_GUEST_IDTR_LIMIT, ctx->idtr_limit); + error |= vmcs_write(VMCS_GUEST_IDTR_BASE, ctx->idtr_base); + + error |= vmcs_write(VMCS_GUEST_GDTR_LIMIT, ctx->gdtr_limit); + error |= vmcs_write(VMCS_GUEST_GDTR_BASE, ctx->gdtr_base); + + error |= vmcs_write(VMCS_GUEST_CS_SELECTOR, ctx->cs_sel); + error |= vmcs_write(VMCS_GUEST_CS_LIMIT, ctx->cs_limit); + error |= vmcs_write(VMCS_GUEST_CS_BASE, ctx->cs_base); + error |= vmcs_write(VMCS_GUEST_CS_ACCESS, ctx->cs_arbytes.bytes); + + error |= vmcs_write(VMCS_GUEST_DS_SELECTOR, ctx->ds_sel); + error |= vmcs_write(VMCS_GUEST_DS_LIMIT, ctx->ds_limit); + error |= vmcs_write(VMCS_GUEST_DS_BASE, ctx->ds_base); + error |= vmcs_write(VMCS_GUEST_DS_ACCESS, ctx->ds_arbytes.bytes); + + error |= vmcs_write(VMCS_GUEST_ES_SELECTOR, ctx->es_sel); + error |= vmcs_write(VMCS_GUEST_ES_LIMIT, ctx->es_limit); + error |= vmcs_write(VMCS_GUEST_ES_BASE, ctx->es_base); + error |= vmcs_write(VMCS_GUEST_ES_ACCESS, ctx->es_arbytes.bytes); + + error |= vmcs_write(VMCS_GUEST_SS_SELECTOR, ctx->ss_sel); + error |= vmcs_write(VMCS_GUEST_SS_LIMIT, ctx->ss_limit); + error |= vmcs_write(VMCS_GUEST_SS_BASE, ctx->ss_base); + error |= vmcs_write(VMCS_GUEST_SS_ACCESS, ctx->ss_arbytes.bytes); + + error |= vmcs_write(VMCS_GUEST_FS_SELECTOR, ctx->fs_sel); + error |= vmcs_write(VMCS_GUEST_FS_LIMIT, ctx->fs_limit); + error |= vmcs_write(VMCS_GUEST_FS_BASE, ctx->fs_base); + error |= vmcs_write(VMCS_GUEST_FS_ACCESS, ctx->fs_arbytes.bytes); + + error |= vmcs_write(VMCS_GUEST_GS_SELECTOR, ctx->gs_sel); + error |= vmcs_write(VMCS_GUEST_GS_LIMIT, ctx->gs_limit); + error |= vmcs_write(VMCS_GUEST_GS_BASE, ctx->gs_base); + error |= vmcs_write(VMCS_GUEST_GS_ACCESS, ctx->gs_arbytes.bytes); + + error |= vmcs_write(VMCS_GUEST_TR_SELECTOR, ctx->tr_sel); + error |= vmcs_write(VMCS_GUEST_TR_LIMIT, ctx->tr_limit); + error |= vmcs_write(VMCS_GUEST_TR_BASE, ctx->tr_base); + error |= vmcs_write(VMCS_GUEST_TR_ACCESS, ctx->tr_arbytes.bytes); + + error |= vmcs_write(VMCS_GUEST_LDTR_SELECTOR, ctx->ldtr_sel); + error |= vmcs_write(VMCS_GUEST_LDTR_LIMIT, ctx->ldtr_limit); + error |= vmcs_write(VMCS_GUEST_LDTR_BASE, ctx->ldtr_base); + error |= vmcs_write(VMCS_GUEST_LDTR_ACCESS, ctx->ldtr_arbytes.bytes); + + return error; +} + +