diff options
author | Suravee Suthikulpanit <suravee.suthikulpanit@amd.com> | 2013-08-13 14:22:14 +0200 |
---|---|---|
committer | Jan Beulich <jbeulich@suse.com> | 2013-08-13 14:22:14 +0200 |
commit | 85fc517ec3055e8e8d9c9e36e15a81e630237252 (patch) | |
tree | 9b268fb99f72f77824deb9e5573329fc06d441c8 /xen/arch/x86/hvm | |
parent | 73f18583dd824f0e49f65149ef603600ce31b8ee (diff) | |
download | xen-85fc517ec3055e8e8d9c9e36e15a81e630237252.tar.gz xen-85fc517ec3055e8e8d9c9e36e15a81e630237252.tar.bz2 xen-85fc517ec3055e8e8d9c9e36e15a81e630237252.zip |
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 <suravee.suthikulpanit@amd.com>
Reviewed-by: Tim Deegan <tim@xen.org>
Diffstat (limited to 'xen/arch/x86/hvm')
-rw-r--r-- | xen/arch/x86/hvm/svm/svm.c | 52 |
1 files changed, 43 insertions, 9 deletions
diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c index 4cc4b15315..a20540b1d1 100644 --- a/xen/arch/x86/hvm/svm/svm.c +++ b/xen/arch/x86/hvm/svm/svm.c @@ -1795,6 +1795,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, @@ -1802,7 +1828,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; @@ -1813,13 +1839,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; @@ -1838,7 +1869,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; @@ -1849,14 +1880,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; |