diff options
Diffstat (limited to 'xen/arch/x86/hvm/svm/svm.c')
-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 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; |