Commit-ID:  b9894a2f5bd18b1691cb6872c9afe32b148d0132
Gitweb:     http://git.kernel.org/tip/b9894a2f5bd18b1691cb6872c9afe32b148d0132
Author:     Kyle Huey <m...@kylehuey.com>
AuthorDate: Tue, 14 Feb 2017 00:11:03 -0800
Committer:  Thomas Gleixner <t...@linutronix.de>
CommitDate: Sat, 11 Mar 2017 12:45:18 +0100

x86/process: Correct and optimize TIF_BLOCKSTEP switch

The debug control MSR is "highly magical" as the blockstep bit can be
cleared by hardware under not well documented circumstances.

So a task switch relying on the bit set by the previous task (according to
the previous tasks thread flags) can trip over this and not update the flag
for the next task.

To fix this its required to handle DEBUGCTLMSR_BTF when either the previous
or the next or both tasks have the TIF_BLOCKSTEP flag set.

While at it avoid branching within the TIF_BLOCKSTEP case and evaluating
boot_cpu_data twice in kernels without CONFIG_X86_DEBUGCTLMSR.

x86_64: arch/x86/kernel/process.o
text    data    bss     dec      hex
3024    8577    16      11617    2d61   Before
3008    8577    16      11601    2d51   After

i386: No change

[ tglx: Made the shift value explicit, use a local variable to make the
code readable and massaged changelog]

Originally-by: Thomas Gleixner <t...@linutronix.de>
Signed-off-by: Kyle Huey <kh...@kylehuey.com>
Cc: Peter Zijlstra <pet...@infradead.org>
Cc: Andy Lutomirski <l...@kernel.org>
Link: http://lkml.kernel.org/r/20170214081104.9244-3-kh...@kylehuey.com
Signed-off-by: Thomas Gleixner <t...@linutronix.de>

---
 arch/x86/include/asm/msr-index.h |  1 +
 arch/x86/kernel/process.c        | 12 +++++++-----
 2 files changed, 8 insertions(+), 5 deletions(-)

diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h
index d8b5f8a..4c928f3 100644
--- a/arch/x86/include/asm/msr-index.h
+++ b/arch/x86/include/asm/msr-index.h
@@ -127,6 +127,7 @@
 
 /* DEBUGCTLMSR bits (others vary by model): */
 #define DEBUGCTLMSR_LBR                        (1UL <<  0) /* last branch 
recording */
+#define DEBUGCTLMSR_BTF_SHIFT          1
 #define DEBUGCTLMSR_BTF                        (1UL <<  1) /* single-step on 
branches */
 #define DEBUGCTLMSR_TR                 (1UL <<  6)
 #define DEBUGCTLMSR_BTS                        (1UL <<  7)
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index ea9ea25..83fa3cb 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -222,13 +222,15 @@ void __switch_to_xtra(struct task_struct *prev_p, struct 
task_struct *next_p,
 
        propagate_user_return_notify(prev_p, next_p);
 
-       if ((tifp ^ tifn) & _TIF_BLOCKSTEP) {
-               unsigned long debugctl = get_debugctlmsr();
+       if ((tifp & _TIF_BLOCKSTEP || tifn & _TIF_BLOCKSTEP) &&
+           arch_has_block_step()) {
+               unsigned long debugctl, msk;
 
+               rdmsrl(MSR_IA32_DEBUGCTLMSR, debugctl);
                debugctl &= ~DEBUGCTLMSR_BTF;
-               if (tifn & _TIF_BLOCKSTEP)
-                       debugctl |= DEBUGCTLMSR_BTF;
-               update_debugctlmsr(debugctl);
+               msk = tifn & _TIF_BLOCKSTEP;
+               debugctl |= (msk >> TIF_BLOCKSTEP) << DEBUGCTLMSR_BTF_SHIFT;
+               wrmsrl(MSR_IA32_DEBUGCTLMSR, debugctl);
        }
 
        if ((tifp ^ tifn) & _TIF_NOTSC) {

Reply via email to