From: Linus Torvalds <torvalds@transmeta.com>

Basically, that debug/NMI stack handling code is already fragile as hell, 
and has been wrong at least twice. I _think_ the current code is right, 
and I think it's right in assuming that the kernel stack is never empty. 
Again, sysenter is a very special case, and the fix is not to change the 
assumption, but to make sysenter follow the "we don't ever have an empty 
stack" rule.

The patch itself could be a lot cleaner. That old 0x200 #define was a 
magic "this is the size of our TSS" thing, and I made it worse. The right 
thing to do is probably to have a real TSS size #define, and force the TSS 
out with a __attribute__((__aligned__(TSS_SIZE))), and have a

	#define TSS_SIZE 0x200
	#define TSS_STACK_OFFSET (TSS_SIZE-8)

in some file that can be included from both C and asm, and then make the
all users use that.




 arch/i386/kernel/entry.S    |    6 +++---
 arch/i386/kernel/sysenter.c |    2 +-
 2 files changed, 4 insertions(+), 4 deletions(-)

diff -puN arch/i386/kernel/entry.S~sysenter-nmi-fix-2 arch/i386/kernel/entry.S
--- 25/arch/i386/kernel/entry.S~sysenter-nmi-fix-2	2003-05-26 13:25:06.000000000 -0700
+++ 25-akpm/arch/i386/kernel/entry.S	2003-05-26 13:25:06.000000000 -0700
@@ -73,10 +73,10 @@ NT_MASK		= 0x00004000
 VM_MASK		= 0x00020000
 
 /*
- * ESP0 is at offset 4. 0x200 is the size of the TSS, and
- * also thus the top-of-stack pointer offset of SYSENTER_ESP
+ * ESP0 is at offset 4.  0x1F8 is the top-of-stack pointer
+ * offset of SYSENTER_ESP
  */
-TSS_ESP0_OFFSET = (4 - 0x200)
+TSS_ESP0_OFFSET = (4 - 0x1F8)
 
 #ifdef CONFIG_PREEMPT
 #define preempt_stop		cli
diff -puN arch/i386/kernel/sysenter.c~sysenter-nmi-fix-2 arch/i386/kernel/sysenter.c
--- 25/arch/i386/kernel/sysenter.c~sysenter-nmi-fix-2	2003-05-26 13:25:06.000000000 -0700
+++ 25-akpm/arch/i386/kernel/sysenter.c	2003-05-26 13:25:06.000000000 -0700
@@ -27,7 +27,7 @@ void enable_sep_cpu(void *info)
 	struct tss_struct *tss = init_tss + cpu;
 
 	tss->ss1 = __KERNEL_CS;
-	tss->esp1 = sizeof(struct tss_struct) + (unsigned long) tss;
+	tss->esp1 = sizeof(struct tss_struct) + (unsigned long) tss - 8;
 	wrmsr(MSR_IA32_SYSENTER_CS, __KERNEL_CS, 0);
 	wrmsr(MSR_IA32_SYSENTER_ESP, tss->esp1, 0);
 	wrmsr(MSR_IA32_SYSENTER_EIP, (unsigned long) sysenter_entry, 0);

_