x86: emulate I/O port access breakpoints
PATCH 1/1 x86: emulate I/O port access breakpoints
Emulate the trapping on I/O port accesses when emulating IN/OUT.
Also allow 8-byte breakpoints on x86-64 (and on i686 if the hardware supports them), and tighten the condition for loading debug registers during context switch.
This patch depends on the prior single step injection patch.
Signed-off-by Jan Beulich <[email protected]>
xen/arch/x86/domain.c +3 -2
@@ -42,6 +42,7 @@#include <asm/hypercall.h> #include <asm/hvm/hvm.h> #include <asm/hvm/support.h> +#include <asm/debugreg.h> #include <asm/msr.h> #include <asm/nmi.h> #include <asm/iommu.h>
@@ -1219,7 +1220,7 @@ static void paravirt_ctxt_switch_from(st* inside Xen, before we get a chance to reload DR7, and this cannot always * safely be handled. */ -if (unlikely (v->arch.guest_context.debugreg[7 ]) ) +if (unlikely (v->arch.guest_context.debugreg[7 ] &DR7_ACTIVE_MASK ) )write_debugreg (7 ,0 ); }
@@ -1234,7 +1235,7 @@ static void paravirt_ctxt_switch_to(struif (unlikely (cr4 !=read_cr4 ()) )write_cr4 (cr4); -if (unlikely (v->arch.guest_context.debugreg[7 ]) ) +if (unlikely (v->arch.guest_context.debugreg[7 ] &DR7_ACTIVE_MASK ) ) {write_debugreg (0 , v->arch.guest_context.debugreg[0 ]);write_debugreg (1 , v->arch.guest_context.debugreg[1 ]);
xen/arch/x86/domctl.c +6 -0
@@ -825,12 +825,18 @@ void arch_get_info_guest(struct vcpu *v, c.nat->ctrlreg[1 ] =xen_pfn_to_cr3 (pagetable_get_pfn (v->arch.guest_table_user));#endif + + c.nat->debugreg[7 ] |= c.nat->debugreg[5 ]; + c.nat->debugreg[5 ] =0 ; }#ifdef CONFIG_COMPAT else {l4_pgentry_t *l4e =__va (pagetable_get_paddr (v->arch.guest_table)); c.cmp->ctrlreg[3 ] =compat_pfn_to_cr3 (l4e_get_pfn (*l4e)); + + c.cmp->debugreg[7 ] |= c.cmp->debugreg[5 ]; + c.cmp->debugreg[5 ] =0 ; }#endif
xen/arch/x86/hvm/svm/svm.c +1 -2
@@ -34,6 +34,7 @@#include <asm/cpufeature.h> #include <asm/processor.h> #include <asm/types.h> +#include <asm/debugreg.h> #include <asm/msr.h> #include <asm/spinlock.h> #include <asm/hvm/hvm.h>
@@ -189,8 +190,6 @@ static void __restore_debug_registers(st* if one of the breakpoints is enabled. So mask out all bits that don't * enable some breakpoint functionality. */ -#define DR7_ACTIVE_MASK 0xff -static void svm_restore_dr (struct vcpu *v) {if (unlikely (v->arch.guest_context.debugreg[7 ] &DR7_ACTIVE_MASK ) )
xen/arch/x86/hvm/vmx/vmx.c +1 -2
@@ -33,6 +33,7 @@#include <asm/cpufeature.h> #include <asm/processor.h> #include <asm/types.h> +#include <asm/debugreg.h> #include <asm/msr.h> #include <asm/spinlock.h> #include <asm/paging.h>
@@ -434,8 +435,6 @@ static void __restore_debug_registers(st* if one of the breakpoints is enabled. So mask out all bits that don't * enable some breakpoint functionality. */ -#define DR7_ACTIVE_MASK 0xff -static void vmx_restore_dr (struct vcpu *v) {/* NB. __vmread() is not usable here, so we cannot read from the VMCS. */
xen/arch/x86/traps.c +94 -27
238 lines not on this page · raw message
xen/include/asm-x86/debugreg.h +9 -3
@@ -33,11 +33,13 @@#define DR_RW_EXECUTE (0x0)/* Settings for the access types to trap on */ #define DR_RW_WRITE (0x1) +#define DR_IO (0x2)#define DR_RW_READ (0x3)#define DR_LEN_1 (0x0)/* Settings for data length to trap on */ #define DR_LEN_2 (0x4)#define DR_LEN_4 (0xC) +#define DR_LEN_8 (0x8)/* The low byte to the control register determine which registers are enabled. There are 4 fields of two bits. One bit is "local", meaning
@@ -53,12 +55,16 @@#define DR_LOCAL_ENABLE_MASK (0x55)/* Set local bits for all 4 regs */ #define DR_GLOBAL_ENABLE_MASK (0xAA)/* Set global bits for all 4 regs */ +#define DR7_ACTIVE_MASK (DR_LOCAL_ENABLE_MASK|DR_GLOBAL_ENABLE_MASK) +/* The second byte to the control register has a few special things. We can slow the instruction pipeline for instructions coming via the gdt or the ldt if we want to. I am not sure why this is an advantage */ -#define DR_CONTROL_RESERVED (~0xFFFF03FFUL)/* Reserved by Intel */ -#define DR_LOCAL_SLOWDOWN (0x100)/* Local slow the pipeline */ -#define DR_GLOBAL_SLOWDOWN (0x200)/* Global slow the pipeline */ +#define DR_CONTROL_RESERVED_ZERO (~0xFFFF23FFUL)/* Reserved, read as zero */ +#define DR_CONTROL_RESERVED_ONE ( 0x00000400 )/* Reserved, read as one */ +#define DR_LOCAL_EXACT_ENABLE ( 0x00000100 )/* Local exact enable */ +#define DR_GLOBAL_EXACT_ENABLE ( 0x00000200 )/* Global exact enable */ +#define DR_GENERAL_DETECT ( 0x00002000 )/* General detect enable */ #endif /* _X86_DEBUGREG_H */