From cadf4cd094edbd62d0d1df552ad8a83b62132f86 Mon Sep 17 00:00:00 2001 From: Suravee Suthikulpanit Date: Tue, 20 Aug 2013 15:35:09 +0200 Subject: x86/AMD: Fix nested svm crash due to assertion in __virt_to_maddr Fix assertion in __virt_to_maddr when starting nested SVM guest in debug mode. Investigation has shown that svm_vmsave/svm_vmload make use of __pa() with invalid address. Signed-off-by: Suravee Suthikulpanit Reviewed-by: Tim Deegan master commit: 85fc517ec3055e8e8d9c9e36e15a81e630237252 master date: 2013-08-13 14:22:14 +0200 --- xen/arch/x86/hvm/svm/svm.c | 52 ++++++++++++++++++++++++++++++++------- xen/include/asm-x86/hvm/svm/svm.h | 11 ++++++--- 2 files changed, 50 insertions(+), 13 deletions(-) diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c index 59ac6abd11..db7b06346b 100644 --- a/xen/arch/x86/hvm/svm/svm.c +++ b/xen/arch/x86/hvm/svm/svm.c @@ -1813,6 +1813,32 @@ svm_vmexit_do_vmrun(struct cpu_user_regs *regs, return; } +static struct page_info * +nsvm_get_nvmcb_page(struct vcpu *v, uint64_t vmcbaddr) +{ + p2m_type_t p2mt; + struct page_info *page; + struct nestedvcpu *nv = &vcpu_nestedhvm(v); + + if ( !nestedsvm_vmcb_map(v, vmcbaddr) ) + return NULL; + + /* Need to translate L1-GPA to MPA */ + page = get_page_from_gfn(v->domain, + nv->nv_vvmcxaddr >> PAGE_SHIFT, + &p2mt, P2M_ALLOC | P2M_UNSHARE); + if ( !page ) + return NULL; + + if ( !p2m_is_ram(p2mt) || p2m_is_readonly(p2mt) ) + { + put_page(page); + return NULL; + } + + return page; +} + static void svm_vmexit_do_vmload(struct vmcb_struct *vmcb, struct cpu_user_regs *regs, @@ -1820,7 +1846,7 @@ svm_vmexit_do_vmload(struct vmcb_struct *vmcb, { int ret; unsigned int inst_len; - struct nestedvcpu *nv = &vcpu_nestedhvm(v); + struct page_info *page; if ( (inst_len = __get_instruction_length(v, INSTR_VMLOAD)) == 0 ) return; @@ -1831,13 +1857,18 @@ svm_vmexit_do_vmload(struct vmcb_struct *vmcb, goto inject; } - if (!nestedsvm_vmcb_map(v, vmcbaddr)) { - gdprintk(XENLOG_ERR, "VMLOAD: mapping vmcb failed, injecting #UD\n"); + page = nsvm_get_nvmcb_page(v, vmcbaddr); + if ( !page ) + { + gdprintk(XENLOG_ERR, + "VMLOAD: mapping failed, injecting #UD\n"); ret = TRAP_invalid_op; goto inject; } - svm_vmload(nv->nv_vvmcx); + svm_vmload_pa(page_to_maddr(page)); + put_page(page); + /* State in L1 VMCB is stale now */ v->arch.hvm_svm.vmcb_in_sync = 0; @@ -1856,7 +1887,7 @@ svm_vmexit_do_vmsave(struct vmcb_struct *vmcb, { int ret; unsigned int inst_len; - struct nestedvcpu *nv = &vcpu_nestedhvm(v); + struct page_info *page; if ( (inst_len = __get_instruction_length(v, INSTR_VMSAVE)) == 0 ) return; @@ -1867,14 +1898,17 @@ svm_vmexit_do_vmsave(struct vmcb_struct *vmcb, goto inject; } - if (!nestedsvm_vmcb_map(v, vmcbaddr)) { - gdprintk(XENLOG_ERR, "VMSAVE: mapping vmcb failed, injecting #UD\n"); + page = nsvm_get_nvmcb_page(v, vmcbaddr); + if ( !page ) + { + gdprintk(XENLOG_ERR, + "VMSAVE: mapping vmcb failed, injecting #UD\n"); ret = TRAP_invalid_op; goto inject; } - svm_vmsave(nv->nv_vvmcx); - + svm_vmsave_pa(page_to_maddr(page)); + put_page(page); __update_guest_eip(regs, inst_len); return; diff --git a/xen/include/asm-x86/hvm/svm/svm.h b/xen/include/asm-x86/hvm/svm/svm.h index 8a9e66014a..16adc085bd 100644 --- a/xen/include/asm-x86/hvm/svm/svm.h +++ b/xen/include/asm-x86/hvm/svm/svm.h @@ -41,18 +41,21 @@ #define SVM_REG_R14 (14) #define SVM_REG_R15 (15) -static inline void svm_vmload(void *vmcb) +#define svm_vmload(x) svm_vmload_pa(__pa(x)) +#define svm_vmsave(x) svm_vmsave_pa(__pa(x)) + +static inline void svm_vmload_pa(unsigned long vmcb) { asm volatile ( ".byte 0x0f,0x01,0xda" /* vmload */ - : : "a" (__pa(vmcb)) : "memory" ); + : : "a" (vmcb) : "memory" ); } -static inline void svm_vmsave(void *vmcb) +static inline void svm_vmsave_pa(unsigned long vmcb) { asm volatile ( ".byte 0x0f,0x01,0xdb" /* vmsave */ - : : "a" (__pa(vmcb)) : "memory" ); + : : "a" (vmcb) : "memory" ); } static inline void svm_invlpga(unsigned long vaddr, uint32_t asid) -- cgit v1.2.3