[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen stable-4.10] x86/pv: Introduce and use x86emul_write_dr()
commit 3bb756be2b2d5037b348f7e0589b524f38f520f4 Author: Andrew Cooper <andrew.cooper3@xxxxxxxxxx> AuthorDate: Fri May 18 11:41:11 2018 +0200 Commit: Jan Beulich <jbeulich@xxxxxxxx> CommitDate: Fri May 18 11:41:11 2018 +0200 x86/pv: Introduce and use x86emul_write_dr() set_debugreg() has several bugs: * %dr4/5 should function correctly as aliases of %dr6/7 when CR4.DE is clear. * Attempting to set the upper 32 bits of %dr6/7 should fail with #GP[0] rather than be silently corrected and complete. * For emulation, the #UD and #GP[0] cases need properly distinguishing. Use -ENODEV for #UD cases, leaving -EINVAL (bad bits) and -EPERM (not allowed to use that valid bit) as before for hypercall callers. * A write which clears %dr7.L/G leaves the IO shadow intact, meaning that subsequent reads of %dr7 will see stale IO watchpoint configuration. Implement x86emul_write_dr() as a thin wrapper around set_debugreg(). Signed-off-by: Andrew Cooper <andrew.cooper3@xxxxxxxxxx> Reviewed-by: Jan Beulich <jbeulich@xxxxxxxx> master commit: f539ae27061c6811fd5e80e0755bf0514e22b977 master date: 2018-04-17 15:12:36 +0100 --- xen/arch/x86/pv/emul-priv-op.c | 9 +-------- xen/arch/x86/traps.c | 32 +++++++++++++++++++++++++++++++- xen/arch/x86/x86_emulate.c | 24 ++++++++++++++++++++++++ xen/arch/x86/x86_emulate/x86_emulate.h | 2 ++ 4 files changed, 58 insertions(+), 9 deletions(-) diff --git a/xen/arch/x86/pv/emul-priv-op.c b/xen/arch/x86/pv/emul-priv-op.c index 8d8af2e3a8..37627054b1 100644 --- a/xen/arch/x86/pv/emul-priv-op.c +++ b/xen/arch/x86/pv/emul-priv-op.c @@ -813,13 +813,6 @@ static int write_cr(unsigned int reg, unsigned long val, return X86EMUL_UNHANDLEABLE; } -static int write_dr(unsigned int reg, unsigned long val, - struct x86_emulate_ctxt *ctxt) -{ - return do_set_debugreg(reg, val) == 0 - ? X86EMUL_OKAY : X86EMUL_UNHANDLEABLE; -} - static inline uint64_t guest_misc_enable(uint64_t val) { val &= ~(MSR_IA32_MISC_ENABLE_PERF_AVAIL | @@ -1314,7 +1307,7 @@ static const struct x86_emulate_ops priv_op_ops = { .read_cr = read_cr, .write_cr = write_cr, .read_dr = x86emul_read_dr, - .write_dr = write_dr, + .write_dr = x86emul_write_dr, .read_msr = read_msr, .write_msr = write_msr, .cpuid = pv_emul_cpuid, diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c index d21c8c709d..e217b0d6e2 100644 --- a/xen/arch/x86/traps.c +++ b/xen/arch/x86/traps.c @@ -2039,6 +2039,12 @@ void activate_debugregs(const struct vcpu *curr) } } +/* + * Used by hypercalls and the emulator. + * -ENODEV => #UD + * -EINVAL => #GP Invalid bit + * -EPERM => #GP Valid bit, but not permitted to use + */ long set_debugreg(struct vcpu *v, unsigned int reg, unsigned long value) { int i; @@ -2070,7 +2076,17 @@ long set_debugreg(struct vcpu *v, unsigned int reg, unsigned long value) if ( v == curr ) write_debugreg(3, value); break; + + case 4: + if ( v->arch.pv_vcpu.ctrlreg[4] & X86_CR4_DE ) + return -ENODEV; + + /* Fallthrough */ case 6: + /* The upper 32 bits are strictly reserved. */ + if ( value != (uint32_t)value ) + return -EINVAL; + /* * DR6: Bits 4-11,16-31 reserved (set to 1). * Bit 12 reserved (set to 0). @@ -2080,7 +2096,17 @@ long set_debugreg(struct vcpu *v, unsigned int reg, unsigned long value) if ( v == curr ) write_debugreg(6, value); break; + + case 5: + if ( v->arch.pv_vcpu.ctrlreg[4] & X86_CR4_DE ) + return -ENODEV; + + /* Fallthrough */ case 7: + /* The upper 32 bits are strictly reserved. */ + if ( value != (uint32_t)value ) + return -EINVAL; + /* * DR7: Bit 10 reserved (set to 1). * Bits 11-12,14-15 reserved (set to 0). @@ -2093,6 +2119,10 @@ long set_debugreg(struct vcpu *v, unsigned int reg, unsigned long value) */ if ( value & DR_GENERAL_DETECT ) return -EPERM; + + /* Zero the IO shadow before recalculating the real %dr7 */ + v->arch.debugreg[5] = 0; + /* DR7.{G,L}E = 0 => debugging disabled for this domain. */ if ( value & DR7_ACTIVE_MASK ) { @@ -2125,7 +2155,7 @@ long set_debugreg(struct vcpu *v, unsigned int reg, unsigned long value) write_debugreg(7, value); break; default: - return -EINVAL; + return -ENODEV; } v->arch.debugreg[reg] = value; diff --git a/xen/arch/x86/x86_emulate.c b/xen/arch/x86/x86_emulate.c index d3155a09d5..9125c67c9e 100644 --- a/xen/arch/x86/x86_emulate.c +++ b/xen/arch/x86/x86_emulate.c @@ -14,6 +14,7 @@ #include <asm/processor.h> /* current_cpu_info */ #include <asm/xstate.h> #include <asm/amd.h> /* cpu_has_amd_erratum() */ +#include <asm/debugreg.h> /* Avoid namespace pollution. */ #undef cmpxchg @@ -81,6 +82,29 @@ int x86emul_read_dr(unsigned int reg, unsigned long *val, return X86EMUL_OKAY; } +int x86emul_write_dr(unsigned int reg, unsigned long val, + struct x86_emulate_ctxt *ctxt) +{ + struct vcpu *curr = current; + + /* HVM support requires a bit more plumbing before it will work. */ + ASSERT(is_pv_vcpu(curr)); + + switch ( set_debugreg(curr, reg, val) ) + { + case 0: + return X86EMUL_OKAY; + + case -ENODEV: + x86_emul_hw_exception(TRAP_invalid_op, X86_EVENT_NO_EC, ctxt); + return X86EMUL_EXCEPTION; + + default: + x86_emul_hw_exception(TRAP_gp_fault, 0, ctxt); + return X86EMUL_EXCEPTION; + } +} + /* * Local variables: * mode: C diff --git a/xen/arch/x86/x86_emulate/x86_emulate.h b/xen/arch/x86/x86_emulate/x86_emulate.h index 064bfc6a82..9c2bb8157c 100644 --- a/xen/arch/x86/x86_emulate/x86_emulate.h +++ b/xen/arch/x86/x86_emulate/x86_emulate.h @@ -664,6 +664,8 @@ void x86_emulate_free_state(struct x86_emulate_state *state); int x86emul_read_dr(unsigned int reg, unsigned long *val, struct x86_emulate_ctxt *ctxt); +int x86emul_write_dr(unsigned int reg, unsigned long val, + struct x86_emulate_ctxt *ctxt); #endif -- generated by git-patchbot for /home/xen/git/xen.git#stable-4.10 _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |