From: Linus Torvalds 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); _