From patchwork Mon Dec 12 09:59:35 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jan Beulich X-Patchwork-Id: 9470329 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 8E42060476 for ; Mon, 12 Dec 2016 10:01:56 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 84E5A283F8 for ; Mon, 12 Dec 2016 10:01:56 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 79B5B2845A; Mon, 12 Dec 2016 10:01:56 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.2 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id AE302283F8 for ; Mon, 12 Dec 2016 10:01:55 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1cGNOa-0005jc-Qw; Mon, 12 Dec 2016 09:59:44 +0000 Received: from mail6.bemta6.messagelabs.com ([193.109.254.103]) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1cGNOZ-0005jP-1S for xen-devel@lists.xenproject.org; Mon, 12 Dec 2016 09:59:43 +0000 Received: from [85.158.143.35] by server-8.bemta-6.messagelabs.com id F4/1F-30093-E057E485; Mon, 12 Dec 2016 09:59:42 +0000 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFjrOIsWRWlGSWpSXmKPExsXS6fjDS5e31C/ C4FOHksX3LZOZHBg9Dn+4whLAGMWamZeUX5HAmrHp7HOWggXRFV96jrA1MK636WLk5BASyJN4 NP0zM4jNK2An0Xf4EROILSFgKPH0/XU2EJtFQFVi1/V/YDabgLpE27PtrF2MHBwiAgYS544mg ZjMAvoS29axgFQIC1hIzFwxgQ1iup3E+fU3GEFsTgF7id99k1hAynkFBCX+7hAGCTMDlUz5so F1AiPPLITMLCQZCFtL4uGvWywQtrbEsoWvmWeB7ZWWWP6PA8K0kvi2mQtVBYjtKjFnwSSmBYw cqxg1ilOLylKLdI1M9JKKMtMzSnITM3N0DQ3M9HJTi4sT01NzEpOK9ZLzczcxAgOVAQh2MK5c F3iIUZKDSUmU94e3X4QQX1J+SmVGYnFGfFFpTmrxIUYNDg6BbbtWX2CUYsnLz0tVkuCdUgxUJ 1iUmp5akZaZA4wlmFIJDh4lEYg0b3FBYm5xZjpE6hSjopQ47z6QhABIIqM0D64NFr+XGGWlhH kZgY4S4ilILcrNLEGVf8UozsGoJMy7FmQKT2ZeCdz0V0CLmYAWP9/nDbK4JBEhJdXAmFBu+d7 sXXDMf7cJMiplVgcPBIoZXdxyiI0xoePV+zOfLDkS98ZUPutMWrlabLHWXJkpIt9nlk7fm3aK f2uNw9nTx3hKWNase9N1egFvi/+em0rXbned1OgoSVu5wTL9h1LKwp/G91WSjT/tL1M+c19ZY Hndwr13Dprw+fmr/a5JfVqT/9yqS4mlOCPRUIu5qDgRAF86EXzaAgAA X-Env-Sender: JBeulich@suse.com X-Msg-Ref: server-14.tower-21.messagelabs.com!1481536779!42002422!1 X-Originating-IP: [137.65.248.74] X-SpamReason: No, hits=0.0 required=7.0 tests= X-StarScan-Received: X-StarScan-Version: 9.1.1; banners=-,-,- X-VirusChecked: Checked Received: (qmail 42627 invoked from network); 12 Dec 2016 09:59:41 -0000 Received: from prv-mh.provo.novell.com (HELO prv-mh.provo.novell.com) (137.65.248.74) by server-14.tower-21.messagelabs.com with DHE-RSA-AES256-GCM-SHA384 encrypted SMTP; 12 Dec 2016 09:59:41 -0000 Received: from INET-PRV-MTA by prv-mh.provo.novell.com with Novell_GroupWise; Mon, 12 Dec 2016 02:59:38 -0700 Message-Id: <584E83170200007800127DC4@prv-mh.provo.novell.com> X-Mailer: Novell GroupWise Internet Agent 14.2.1 Date: Mon, 12 Dec 2016 02:59:35 -0700 From: "Jan Beulich" To: "xen-devel" References: <584E7E320200007800127D69@prv-mh.provo.novell.com> In-Reply-To: <584E7E320200007800127D69@prv-mh.provo.novell.com> Mime-Version: 1.0 Cc: Andrew Cooper Subject: [Xen-devel] [PATCH 1/3] x86emul: correct EFLAGS.TF handling X-BeenThere: xen-devel@lists.xen.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xen.org Sender: "Xen-devel" X-Virus-Scanned: ClamAV using ClamSMTP For repeated string instructions we should not emulate multiple iterations in one go when a single step trap needs injecting (which needs to happen after every iteration). For all non-branch instructions as well as not taken conditional branches we additionally need to take DebugCtl.BTF into consideration. And for mov-to/pop-into %ss there should be no #DB at all (EFLAGS.TF remaining set means there'll be #DB after the next instruction). Signed-off-by: Jan Beulich x86emul: correct EFLAGS.TF handling For repeated string instructions we should not emulate multiple iterations in one go when a single step trap needs injecting (which needs to happen after every iteration). For all non-branch instructions as well as not taken conditional branches we additionally need to take DebugCtl.BTF into consideration. And for mov-to/pop-into %ss there should be no #DB at all (EFLAGS.TF remaining set means there'll be #DB after the next instruction). Signed-off-by: Jan Beulich --- a/xen/arch/x86/x86_emulate/x86_emulate.c +++ b/xen/arch/x86/x86_emulate/x86_emulate.c @@ -415,6 +415,8 @@ typedef union { #define MSR_SYSENTER_CS 0x00000174 #define MSR_SYSENTER_ESP 0x00000175 #define MSR_SYSENTER_EIP 0x00000176 +#define MSR_DEBUGCTL 0x000001d9 +#define DEBUGCTL_BTF (1 << 1) #define MSR_EFER 0xc0000080 #define MSR_STAR 0xc0000081 #define MSR_LSTAR 0xc0000082 @@ -751,6 +753,8 @@ do { rc = ops->insn_fetch(x86_seg_cs, ip, NULL, 0, ctxt); \ if ( rc ) goto done; \ _regs.eip = ip; \ + if ( _regs.eflags & EFLG_TF ) \ + ctxt->retire.singlestep = true; \ } while (0) #define validate_far_branch(cs, ip) ({ \ @@ -767,6 +771,8 @@ do { #define commit_far_branch(cs, ip) ({ \ validate_far_branch(cs, ip); \ _regs.eip = (ip); \ + if ( _regs.eflags & EFLG_TF ) \ + ctxt->retire.singlestep = true; \ ops->write_segment(x86_seg_cs, cs, ctxt); \ }) @@ -948,6 +954,9 @@ static inline void put_loop_count( } \ goto no_writeback; \ } \ + if ( max_reps > 1 && (_regs.eflags & EFLG_TF) && \ + !is_branch_step(ctxt, ops) ) \ + max_reps = 1; \ max_reps; \ }) @@ -1637,6 +1646,16 @@ static bool is_aligned(enum x86_segment return !((reg.base + offs) & (size - 1)); } +static bool is_branch_step(struct x86_emulate_ctxt *ctxt, + const struct x86_emulate_ops *ops) +{ + uint64_t debugctl; + + return ops->read_msr && + ops->read_msr(MSR_DEBUGCTL, &debugctl, ctxt) == X86EMUL_OKAY && + (debugctl & DEBUGCTL_BTF); +} + static bool umip_active(struct x86_emulate_ctxt *ctxt, const struct x86_emulate_ops *ops) { @@ -3132,6 +3151,8 @@ x86_emulate( goto done; _regs.eip = imm1; + if ( _regs.eflags & EFLG_TF ) + ctxt->retire.singlestep = true; break; case 0x9b: /* wait/fwait */ @@ -4608,6 +4629,8 @@ x86_emulate( (rc = ops->write_segment(x86_seg_ss, &sreg, ctxt)) ) goto done; + if ( ctxt->regs->eflags & EFLG_TF ) + ctxt->retire.singlestep = true; break; } @@ -4875,6 +4898,8 @@ x86_emulate( goto done; _regs.esp = lm ? msr_content : (uint32_t)msr_content; + if ( _regs.eflags & EFLG_TF ) + ctxt->retire.singlestep = true; break; } @@ -4914,6 +4939,9 @@ x86_emulate( _regs.eip = user64 ? _regs.edx : (uint32_t)_regs.edx; _regs.esp = user64 ? _regs.ecx : (uint32_t)_regs.ecx; + + if ( _regs.eflags & EFLG_TF ) + ctxt->retire.singlestep = true; break; } @@ -5400,7 +5428,9 @@ x86_emulate( break; #endif default: - goto cannot_emulate; + cannot_emulate: + rc = X86EMUL_UNHANDLEABLE; + goto done; } switch ( dst.type ) @@ -5445,7 +5475,8 @@ x86_emulate( _regs.eip = (uint32_t)_regs.eip; /* Was singestepping active at the start of this instruction? */ - if ( (rc == X86EMUL_OKAY) && (ctxt->regs->eflags & EFLG_TF) ) + if ( (rc == X86EMUL_OKAY) && (ctxt->regs->eflags & EFLG_TF) && + !is_branch_step(ctxt, ops) && !ctxt->retire.mov_ss ) ctxt->retire.singlestep = true; *ctxt->regs = _regs; @@ -5461,12 +5492,17 @@ x86_emulate( done: _put_fpu(); put_stub(stub); - return rc; - cannot_emulate: - _put_fpu(); - put_stub(stub); - return X86EMUL_UNHANDLEABLE; + /* + * We may have set the single step flag ahead of the last possible point + * of failure (unavoidably with the current near CALL code flow, but also + * used on some far branch paths to keep the code simple), so to satisfy + * x86_emulate_wrapper()'s ASSERT() we may need to clear it here again. + */ + if ( rc != X86EMUL_OKAY ) + ctxt->retire.singlestep = false; + + return rc; #undef state } --- a/xen/arch/x86/x86_emulate/x86_emulate.c +++ b/xen/arch/x86/x86_emulate/x86_emulate.c @@ -415,6 +415,8 @@ typedef union { #define MSR_SYSENTER_CS 0x00000174 #define MSR_SYSENTER_ESP 0x00000175 #define MSR_SYSENTER_EIP 0x00000176 +#define MSR_DEBUGCTL 0x000001d9 +#define DEBUGCTL_BTF (1 << 1) #define MSR_EFER 0xc0000080 #define MSR_STAR 0xc0000081 #define MSR_LSTAR 0xc0000082 @@ -751,6 +753,8 @@ do { rc = ops->insn_fetch(x86_seg_cs, ip, NULL, 0, ctxt); \ if ( rc ) goto done; \ _regs.eip = ip; \ + if ( _regs.eflags & EFLG_TF ) \ + ctxt->retire.singlestep = true; \ } while (0) #define validate_far_branch(cs, ip) ({ \ @@ -767,6 +771,8 @@ do { #define commit_far_branch(cs, ip) ({ \ validate_far_branch(cs, ip); \ _regs.eip = (ip); \ + if ( _regs.eflags & EFLG_TF ) \ + ctxt->retire.singlestep = true; \ ops->write_segment(x86_seg_cs, cs, ctxt); \ }) @@ -948,6 +954,9 @@ static inline void put_loop_count( } \ goto no_writeback; \ } \ + if ( max_reps > 1 && (_regs.eflags & EFLG_TF) && \ + !is_branch_step(ctxt, ops) ) \ + max_reps = 1; \ max_reps; \ }) @@ -1637,6 +1646,16 @@ static bool is_aligned(enum x86_segment return !((reg.base + offs) & (size - 1)); } +static bool is_branch_step(struct x86_emulate_ctxt *ctxt, + const struct x86_emulate_ops *ops) +{ + uint64_t debugctl; + + return ops->read_msr && + ops->read_msr(MSR_DEBUGCTL, &debugctl, ctxt) == X86EMUL_OKAY && + (debugctl & DEBUGCTL_BTF); +} + static bool umip_active(struct x86_emulate_ctxt *ctxt, const struct x86_emulate_ops *ops) { @@ -3132,6 +3151,8 @@ x86_emulate( goto done; _regs.eip = imm1; + if ( _regs.eflags & EFLG_TF ) + ctxt->retire.singlestep = true; break; case 0x9b: /* wait/fwait */ @@ -4608,6 +4629,8 @@ x86_emulate( (rc = ops->write_segment(x86_seg_ss, &sreg, ctxt)) ) goto done; + if ( ctxt->regs->eflags & EFLG_TF ) + ctxt->retire.singlestep = true; break; } @@ -4875,6 +4898,8 @@ x86_emulate( goto done; _regs.esp = lm ? msr_content : (uint32_t)msr_content; + if ( _regs.eflags & EFLG_TF ) + ctxt->retire.singlestep = true; break; } @@ -4914,6 +4939,9 @@ x86_emulate( _regs.eip = user64 ? _regs.edx : (uint32_t)_regs.edx; _regs.esp = user64 ? _regs.ecx : (uint32_t)_regs.ecx; + + if ( _regs.eflags & EFLG_TF ) + ctxt->retire.singlestep = true; break; } @@ -5400,7 +5428,9 @@ x86_emulate( break; #endif default: - goto cannot_emulate; + cannot_emulate: + rc = X86EMUL_UNHANDLEABLE; + goto done; } switch ( dst.type ) @@ -5445,7 +5475,8 @@ x86_emulate( _regs.eip = (uint32_t)_regs.eip; /* Was singestepping active at the start of this instruction? */ - if ( (rc == X86EMUL_OKAY) && (ctxt->regs->eflags & EFLG_TF) ) + if ( (rc == X86EMUL_OKAY) && (ctxt->regs->eflags & EFLG_TF) && + !is_branch_step(ctxt, ops) && !ctxt->retire.mov_ss ) ctxt->retire.singlestep = true; *ctxt->regs = _regs; @@ -5461,12 +5492,17 @@ x86_emulate( done: _put_fpu(); put_stub(stub); - return rc; - cannot_emulate: - _put_fpu(); - put_stub(stub); - return X86EMUL_UNHANDLEABLE; + /* + * We may have set the single step flag ahead of the last possible point + * of failure (unavoidably with the current near CALL code flow, but also + * used on some far branch paths to keep the code simple), so to satisfy + * x86_emulate_wrapper()'s ASSERT() we may need to clear it here again. + */ + if ( rc != X86EMUL_OKAY ) + ctxt->retire.singlestep = false; + + return rc; #undef state }