2014-04-16 23:10:15 +00:00
|
|
|
From 272e319977ab4feb79a28621215a9aca42d60003 Mon Sep 17 00:00:00 2001
|
|
|
|
From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
|
|
|
|
Date: Fri, 3 Jan 2014 14:55:48 +0100
|
|
|
|
Subject: [PATCH] Revert "x86: Disable IST stacks for debug/int 3/stack fault
|
|
|
|
for PREEMPT_RT"
|
2014-05-13 18:04:41 +00:00
|
|
|
Origin: https://www.kernel.org/pub/linux/kernel/projects/rt/3.14/patches-3.14.3-rt5.tar.xz
|
2014-04-16 23:10:15 +00:00
|
|
|
|
|
|
|
where do I start. Let me explain what is going on here. The code
|
|
|
|
sequence
|
|
|
|
| pushf
|
|
|
|
| pop %edx
|
|
|
|
| or $0x1,%dh
|
|
|
|
| push %edx
|
|
|
|
| mov $0xe0,%eax
|
|
|
|
| popf
|
|
|
|
| sysenter
|
|
|
|
|
|
|
|
triggers the bug. On 64bit kernel we see the double fault (with 32bit and
|
|
|
|
64bit userland) and on 32bit kernel there is no problem. The reporter said
|
|
|
|
that double fault does not happen on 64bit kernel with 64bit userland and
|
|
|
|
this is because in that case the VDSO uses the "syscall" interface instead
|
|
|
|
of "sysenter".
|
|
|
|
|
|
|
|
The bug. "popf" loads the flags with the TF bit set which enables
|
|
|
|
"single stepping" and this leads to a debug exception. Usually on 64bit
|
|
|
|
we have a special IST stack for the debug exception. Due to patch [0] we
|
|
|
|
do not use the IST stack but the kernel stack instead. On 64bit the
|
|
|
|
sysenter instruction starts in kernel with the stack address NULL. The
|
|
|
|
code sequence above enters the debug exception (TF flag) after the
|
|
|
|
sysenter instruction was executed which sets the stack pointer to NULL
|
|
|
|
and we have a fault (it seems that the debug exception saves some bytes
|
|
|
|
on the stack).
|
|
|
|
To fix the double fault I'm going to drop patch [0]. It is completely
|
|
|
|
pointless. In do_debug() and do_stack_segment() we disable preemption
|
|
|
|
which means the task can't leave the CPU. So it does not matter if we run
|
|
|
|
on IST or on kernel stack.
|
|
|
|
There is a patch [1] which drops preempt_disable() call for a 32bit
|
|
|
|
kernel but not for 64bit so there should be no regression.
|
|
|
|
And [1] seems valid even for this code sequence. We enter the debug
|
|
|
|
exception with a 256bytes long per cpu stack and migrate to the kernel
|
|
|
|
stack before calling do_debug().
|
|
|
|
|
|
|
|
[0] x86-disable-debug-stack.patch
|
|
|
|
[1] fix-rt-int3-x86_32-3.2-rt.patch
|
|
|
|
|
|
|
|
Cc: stable-rt@vger.kernel.org
|
|
|
|
Reported-by: Brian Silverman <bsilver16384@gmail.com>
|
|
|
|
Cc: Andi Kleen <andi@firstfloor.org>
|
|
|
|
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
|
|
|
|
---
|
|
|
|
arch/x86/include/asm/page_64_types.h | 21 ++++++---------------
|
|
|
|
arch/x86/kernel/cpu/common.c | 2 --
|
|
|
|
arch/x86/kernel/dumpstack_64.c | 4 ----
|
|
|
|
3 files changed, 6 insertions(+), 21 deletions(-)
|
|
|
|
|
|
|
|
--- a/arch/x86/include/asm/page_64_types.h
|
|
|
|
+++ b/arch/x86/include/asm/page_64_types.h
|
|
|
|
@@ -14,21 +14,12 @@
|
|
|
|
#define IRQ_STACK_ORDER 2
|
|
|
|
#define IRQ_STACK_SIZE (PAGE_SIZE << IRQ_STACK_ORDER)
|
|
|
|
|
|
|
|
-#ifdef CONFIG_PREEMPT_RT_FULL
|
|
|
|
-# define STACKFAULT_STACK 0
|
|
|
|
-# define DOUBLEFAULT_STACK 1
|
|
|
|
-# define NMI_STACK 2
|
|
|
|
-# define DEBUG_STACK 0
|
|
|
|
-# define MCE_STACK 3
|
|
|
|
-# define N_EXCEPTION_STACKS 3 /* hw limit: 7 */
|
|
|
|
-#else
|
|
|
|
-# define STACKFAULT_STACK 1
|
|
|
|
-# define DOUBLEFAULT_STACK 2
|
|
|
|
-# define NMI_STACK 3
|
|
|
|
-# define DEBUG_STACK 4
|
|
|
|
-# define MCE_STACK 5
|
|
|
|
-# define N_EXCEPTION_STACKS 5 /* hw limit: 7 */
|
|
|
|
-#endif
|
|
|
|
+#define STACKFAULT_STACK 1
|
|
|
|
+#define DOUBLEFAULT_STACK 2
|
|
|
|
+#define NMI_STACK 3
|
|
|
|
+#define DEBUG_STACK 4
|
|
|
|
+#define MCE_STACK 5
|
|
|
|
+#define N_EXCEPTION_STACKS 5 /* hw limit: 7 */
|
|
|
|
|
|
|
|
#define PUD_PAGE_SIZE (_AC(1, UL) << PUD_SHIFT)
|
|
|
|
#define PUD_PAGE_MASK (~(PUD_PAGE_SIZE-1))
|
|
|
|
--- a/arch/x86/kernel/cpu/common.c
|
|
|
|
+++ b/arch/x86/kernel/cpu/common.c
|
|
|
|
@@ -1116,9 +1116,7 @@ DEFINE_PER_CPU(struct task_struct *, fpu
|
|
|
|
*/
|
|
|
|
static const unsigned int exception_stack_sizes[N_EXCEPTION_STACKS] = {
|
|
|
|
[0 ... N_EXCEPTION_STACKS - 1] = EXCEPTION_STKSZ,
|
|
|
|
-#if DEBUG_STACK > 0
|
|
|
|
[DEBUG_STACK - 1] = DEBUG_STKSZ
|
|
|
|
-#endif
|
|
|
|
};
|
|
|
|
|
|
|
|
static DEFINE_PER_CPU_PAGE_ALIGNED(char, exception_stacks
|
|
|
|
--- a/arch/x86/kernel/dumpstack_64.c
|
|
|
|
+++ b/arch/x86/kernel/dumpstack_64.c
|
|
|
|
@@ -21,14 +21,10 @@
|
|
|
|
(N_EXCEPTION_STACKS + DEBUG_STKSZ/EXCEPTION_STKSZ - 2)
|
|
|
|
|
|
|
|
static char x86_stack_ids[][8] = {
|
|
|
|
-#if DEBUG_STACK > 0
|
|
|
|
[ DEBUG_STACK-1 ] = "#DB",
|
|
|
|
-#endif
|
|
|
|
[ NMI_STACK-1 ] = "NMI",
|
|
|
|
[ DOUBLEFAULT_STACK-1 ] = "#DF",
|
|
|
|
-#if STACKFAULT_STACK > 0
|
|
|
|
[ STACKFAULT_STACK-1 ] = "#SS",
|
|
|
|
-#endif
|
|
|
|
[ MCE_STACK-1 ] = "#MC",
|
|
|
|
#if DEBUG_STKSZ > EXCEPTION_STKSZ
|
|
|
|
[ N_EXCEPTION_STACKS ...
|