diff options
author | Olaf Hering <olaf@aepfle.de> | 2013-05-07 16:41:24 +0200 |
---|---|---|
committer | Jan Beulich <jbeulich@suse.com> | 2013-05-07 16:41:24 +0200 |
commit | 013e34f5a61725012467f17650597d351fc0ca99 (patch) | |
tree | 594b4e26937725656d6b6ff45b307bb770eaaae1 | |
parent | da3ef0f81250b5a680001610028ff35ee94741bc (diff) | |
download | xen-013e34f5a61725012467f17650597d351fc0ca99.tar.gz xen-013e34f5a61725012467f17650597d351fc0ca99.tar.bz2 xen-013e34f5a61725012467f17650597d351fc0ca99.zip |
x86: handle paged gfn in wrmsr_hypervisor_regs
If xenpaging is started very early for a guest the gfn for the hypercall
page may be paged-out already. This leads to a guest crash:
...
(XEN) HVM10: Allocated Xen hypercall page at 169ff000
(XEN) traps.c:654:d10 Bad GMFN 169ff (MFN 3e900000000) to MSR 40000000
(XEN) HVM10: Detected Xen v4.3
(XEN) io.c:201:d10 MMIO emulation failed @ 0008:c2c2c2c2: 18 7c 55 6d 03 83 ff ff 10 7c
(XEN) hvm.c:1253:d10 Triple fault on VCPU0 - invoking HVM shutdown action 1.
(XEN) HVM11: HVM Loader
...
Update return codes of wrmsr_hypervisor_regs, update callers to deal
with the new return codes:
0: not handled
1: handled
-EAGAIN: retry
Currently wrmsr_hypervisor_regs will not return the following error, it
will be added in a separate patch:
-EINVAL: error during handling
Also update the gdprintk to handle a page value of NULL to avoid
printing a bogus MFN value. Update also computing of MSR value in
gdprintk, the idx was always zero.
Signed-off-by: Olaf Hering <olaf@aepfle.de>
Acked-by: Keir Fraser <keir@xen.org>
-rw-r--r-- | xen/arch/x86/hvm/svm/svm.c | 16 | ||||
-rw-r--r-- | xen/arch/x86/hvm/vmx/vmx.c | 11 | ||||
-rw-r--r-- | xen/arch/x86/traps.c | 14 |
3 files changed, 34 insertions, 7 deletions
diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c index bc1fe62b03..cdc176da3e 100644 --- a/xen/arch/x86/hvm/svm/svm.c +++ b/xen/arch/x86/hvm/svm/svm.c @@ -1569,7 +1569,7 @@ static int svm_msr_read_intercept(unsigned int msr, uint64_t *msr_content) static int svm_msr_write_intercept(unsigned int msr, uint64_t msr_content) { - int ret; + int ret, result = X86EMUL_OKAY; struct vcpu *v = current; struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb; int sync = 0; @@ -1682,14 +1682,24 @@ static int svm_msr_write_intercept(unsigned int msr, uint64_t msr_content) if ( wrmsr_viridian_regs(msr, msr_content) ) break; - wrmsr_hypervisor_regs(msr, msr_content); + switch ( wrmsr_hypervisor_regs(msr, msr_content) ) + { + case -EAGAIN: + result = X86EMUL_RETRY; + break; + case 0: + case 1: + break; + default: + goto gpf; + } break; } if ( sync ) svm_vmload(vmcb); - return X86EMUL_OKAY; + return result; gpf: hvm_inject_hw_exception(TRAP_gp_fault, 0); diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c index 51187a932a..d0de44a2ae 100644 --- a/xen/arch/x86/hvm/vmx/vmx.c +++ b/xen/arch/x86/hvm/vmx/vmx.c @@ -2088,7 +2088,16 @@ static int vmx_msr_write_intercept(unsigned int msr, uint64_t msr_content) case HNDL_unhandled: if ( (vmx_write_guest_msr(msr, msr_content) != 0) && !is_last_branch_msr(msr) ) - wrmsr_hypervisor_regs(msr, msr_content); + switch ( wrmsr_hypervisor_regs(msr, msr_content) ) + { + case -EAGAIN: + return X86EMUL_RETRY; + case 0: + case 1: + break; + default: + goto gp_fault; + } break; case HNDL_exception_raised: return X86EMUL_EXCEPTION; diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c index fbbe31d6fc..f630f8318d 100644 --- a/xen/arch/x86/traps.c +++ b/xen/arch/x86/traps.c @@ -634,6 +634,7 @@ int wrmsr_hypervisor_regs(uint32_t idx, uint64_t val) unsigned long gmfn = val >> 12; unsigned int idx = val & 0xfff; struct page_info *page; + p2m_type_t t; if ( idx > 0 ) { @@ -643,15 +644,22 @@ int wrmsr_hypervisor_regs(uint32_t idx, uint64_t val) return 0; } - page = get_page_from_gfn(d, gmfn, NULL, P2M_ALLOC); + page = get_page_from_gfn(d, gmfn, &t, P2M_ALLOC); if ( !page || !get_page_type(page, PGT_writable_page) ) { if ( page ) put_page(page); + + if ( p2m_is_paging(t) ) + { + p2m_mem_paging_populate(d, gmfn); + return -EAGAIN; + } + gdprintk(XENLOG_WARNING, "Bad GMFN %lx (MFN %lx) to MSR %08x\n", - gmfn, page_to_mfn(page), base + idx); + gmfn, page ? page_to_mfn(page) : -1UL, base); return 0; } @@ -2490,7 +2498,7 @@ static int emulate_privileged_op(struct cpu_user_regs *regs) goto fail; break; default: - if ( wrmsr_hypervisor_regs(regs->ecx, msr_content) ) + if ( wrmsr_hypervisor_regs(regs->ecx, msr_content) == 1 ) break; rc = vmce_wrmsr(regs->ecx, msr_content); |