Преглед изворни кода

traps: x86: make traps_32.c and traps_64.c equal

Use CONFIG_X86_64/CONFIG_X86_32 to condtionally compile the
parts needed for x86_64 or i386 only.

Runs a small userspace for a number of minimal configurations
and boots the defconfigs.

Signed-off-by: Alexander van Heukelum <heukelum@fastmail.fm>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Alexander van Heukelum пре 17 година
родитељ
комит
081f75bbdc
2 измењених фајлова са 536 додато и 5 уклоњено
  1. 169 4
      arch/x86/kernel/traps_32.c
  2. 367 1
      arch/x86/kernel/traps_64.c

+ 169 - 4
arch/x86/kernel/traps_32.c

@@ -48,7 +48,6 @@
 
 
 #include <asm/stacktrace.h>
 #include <asm/stacktrace.h>
 #include <asm/processor.h>
 #include <asm/processor.h>
-#include <asm/kmemcheck.h>
 #include <asm/debugreg.h>
 #include <asm/debugreg.h>
 #include <asm/atomic.h>
 #include <asm/atomic.h>
 #include <asm/system.h>
 #include <asm/system.h>
@@ -59,6 +58,11 @@
 
 
 #include <mach_traps.h>
 #include <mach_traps.h>
 
 
+#ifdef CONFIG_X86_64
+#include <asm/pgalloc.h>
+#include <asm/proto.h>
+#include <asm/pda.h>
+#else
 #include <asm/processor-flags.h>
 #include <asm/processor-flags.h>
 #include <asm/arch_hooks.h>
 #include <asm/arch_hooks.h>
 #include <asm/nmi.h>
 #include <asm/nmi.h>
@@ -83,6 +87,7 @@ char ignore_fpu_irq;
  */
  */
 gate_desc idt_table[256]
 gate_desc idt_table[256]
 	__attribute__((__section__(".data.idt"))) = { { { { 0, 0 } } }, };
 	__attribute__((__section__(".data.idt"))) = { { { { 0, 0 } } }, };
+#endif
 
 
 static int ignore_nmis;
 static int ignore_nmis;
 
 
@@ -106,6 +111,7 @@ static inline void preempt_conditional_cli(struct pt_regs *regs)
 	dec_preempt_count();
 	dec_preempt_count();
 }
 }
 
 
+#ifdef CONFIG_X86_32
 static inline void
 static inline void
 die_if_kernel(const char *str, struct pt_regs *regs, long err)
 die_if_kernel(const char *str, struct pt_regs *regs, long err)
 {
 {
@@ -153,6 +159,7 @@ static int lazy_iobitmap_copy(void)
 
 
 	return 0;
 	return 0;
 }
 }
+#endif
 
 
 static void __kprobes
 static void __kprobes
 do_trap(int trapnr, int signr, char *str, struct pt_regs *regs,
 do_trap(int trapnr, int signr, char *str, struct pt_regs *regs,
@@ -160,6 +167,7 @@ do_trap(int trapnr, int signr, char *str, struct pt_regs *regs,
 {
 {
 	struct task_struct *tsk = current;
 	struct task_struct *tsk = current;
 
 
+#ifdef CONFIG_X86_32
 	if (regs->flags & X86_VM_MASK) {
 	if (regs->flags & X86_VM_MASK) {
 		/*
 		/*
 		 * traps 0, 1, 3, 4, and 5 should be forwarded to vm86.
 		 * traps 0, 1, 3, 4, and 5 should be forwarded to vm86.
@@ -169,11 +177,14 @@ do_trap(int trapnr, int signr, char *str, struct pt_regs *regs,
 			goto vm86_trap;
 			goto vm86_trap;
 		goto trap_signal;
 		goto trap_signal;
 	}
 	}
+#endif
 
 
 	if (!user_mode(regs))
 	if (!user_mode(regs))
 		goto kernel_trap;
 		goto kernel_trap;
 
 
+#ifdef CONFIG_X86_32
 trap_signal:
 trap_signal:
+#endif
 	/*
 	/*
 	 * We want error_code and trap_no set for userspace faults and
 	 * We want error_code and trap_no set for userspace faults and
 	 * kernelspace faults which result in die(), but not
 	 * kernelspace faults which result in die(), but not
@@ -186,6 +197,18 @@ trap_signal:
 	tsk->thread.error_code = error_code;
 	tsk->thread.error_code = error_code;
 	tsk->thread.trap_no = trapnr;
 	tsk->thread.trap_no = trapnr;
 
 
+#ifdef CONFIG_X86_64
+	if (show_unhandled_signals && unhandled_signal(tsk, signr) &&
+	    printk_ratelimit()) {
+		printk(KERN_INFO
+		       "%s[%d] trap %s ip:%lx sp:%lx error:%lx",
+		       tsk->comm, tsk->pid, str,
+		       regs->ip, regs->sp, error_code);
+		print_vma_addr(" in ", regs->ip);
+		printk("\n");
+	}
+#endif
+
 	if (info)
 	if (info)
 		force_sig_info(signr, info, tsk);
 		force_sig_info(signr, info, tsk);
 	else
 	else
@@ -200,11 +223,13 @@ kernel_trap:
 	}
 	}
 	return;
 	return;
 
 
+#ifdef CONFIG_X86_32
 vm86_trap:
 vm86_trap:
 	if (handle_vm86_trap((struct kernel_vm86_regs *) regs,
 	if (handle_vm86_trap((struct kernel_vm86_regs *) regs,
 						error_code, trapnr))
 						error_code, trapnr))
 		goto trap_signal;
 		goto trap_signal;
 	return;
 	return;
+#endif
 }
 }
 
 
 #define DO_ERROR(trapnr, signr, str, name)				\
 #define DO_ERROR(trapnr, signr, str, name)				\
@@ -239,9 +264,41 @@ DO_ERROR_INFO(6, SIGILL, "invalid opcode", invalid_op, ILL_ILLOPN, regs->ip)
 DO_ERROR(9, SIGFPE, "coprocessor segment overrun", coprocessor_segment_overrun)
 DO_ERROR(9, SIGFPE, "coprocessor segment overrun", coprocessor_segment_overrun)
 DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS)
 DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS)
 DO_ERROR(11, SIGBUS, "segment not present", segment_not_present)
 DO_ERROR(11, SIGBUS, "segment not present", segment_not_present)
+#ifdef CONFIG_X86_32
 DO_ERROR(12, SIGBUS, "stack segment", stack_segment)
 DO_ERROR(12, SIGBUS, "stack segment", stack_segment)
+#endif
 DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0)
 DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0)
 
 
+#ifdef CONFIG_X86_64
+/* Runs on IST stack */
+dotraplinkage void do_stack_segment(struct pt_regs *regs, long error_code)
+{
+	if (notify_die(DIE_TRAP, "stack segment", regs, error_code,
+			12, SIGBUS) == NOTIFY_STOP)
+		return;
+	preempt_conditional_sti(regs);
+	do_trap(12, SIGBUS, "stack segment", regs, error_code, NULL);
+	preempt_conditional_cli(regs);
+}
+
+dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code)
+{
+	static const char str[] = "double fault";
+	struct task_struct *tsk = current;
+
+	/* Return not checked because double check cannot be ignored */
+	notify_die(DIE_TRAP, str, regs, error_code, 8, SIGSEGV);
+
+	tsk->thread.error_code = error_code;
+	tsk->thread.trap_no = 8;
+
+	/* This is always a kernel trap and never fixable (and thus must
+	   never return). */
+	for (;;)
+		die(str, regs, error_code);
+}
+#endif
+
 dotraplinkage void __kprobes
 dotraplinkage void __kprobes
 do_general_protection(struct pt_regs *regs, long error_code)
 do_general_protection(struct pt_regs *regs, long error_code)
 {
 {
@@ -249,6 +306,7 @@ do_general_protection(struct pt_regs *regs, long error_code)
 
 
 	conditional_sti(regs);
 	conditional_sti(regs);
 
 
+#ifdef CONFIG_X86_32
 	if (lazy_iobitmap_copy()) {
 	if (lazy_iobitmap_copy()) {
 		/* restart the faulting instruction */
 		/* restart the faulting instruction */
 		return;
 		return;
@@ -256,6 +314,7 @@ do_general_protection(struct pt_regs *regs, long error_code)
 
 
 	if (regs->flags & X86_VM_MASK)
 	if (regs->flags & X86_VM_MASK)
 		goto gp_in_vm86;
 		goto gp_in_vm86;
+#endif
 
 
 	tsk = current;
 	tsk = current;
 	if (!user_mode(regs))
 	if (!user_mode(regs))
@@ -277,10 +336,12 @@ do_general_protection(struct pt_regs *regs, long error_code)
 	force_sig(SIGSEGV, tsk);
 	force_sig(SIGSEGV, tsk);
 	return;
 	return;
 
 
+#ifdef CONFIG_X86_32
 gp_in_vm86:
 gp_in_vm86:
 	local_irq_enable();
 	local_irq_enable();
 	handle_vm86_fault((struct kernel_vm86_regs *) regs, error_code);
 	handle_vm86_fault((struct kernel_vm86_regs *) regs, error_code);
 	return;
 	return;
+#endif
 
 
 gp_in_kernel:
 gp_in_kernel:
 	if (fixup_exception(regs))
 	if (fixup_exception(regs))
@@ -368,6 +429,7 @@ unknown_nmi_error(unsigned char reason, struct pt_regs *regs)
 	printk(KERN_EMERG "Dazed and confused, but trying to continue\n");
 	printk(KERN_EMERG "Dazed and confused, but trying to continue\n");
 }
 }
 
 
+#ifdef CONFIG_X86_32
 static DEFINE_SPINLOCK(nmi_print_lock);
 static DEFINE_SPINLOCK(nmi_print_lock);
 
 
 void notrace __kprobes die_nmi(char *str, struct pt_regs *regs, int do_panic)
 void notrace __kprobes die_nmi(char *str, struct pt_regs *regs, int do_panic)
@@ -402,6 +464,7 @@ void notrace __kprobes die_nmi(char *str, struct pt_regs *regs, int do_panic)
 
 
 	do_exit(SIGSEGV);
 	do_exit(SIGSEGV);
 }
 }
+#endif
 
 
 static notrace __kprobes void default_do_nmi(struct pt_regs *regs)
 static notrace __kprobes void default_do_nmi(struct pt_regs *regs)
 {
 {
@@ -441,11 +504,13 @@ static notrace __kprobes void default_do_nmi(struct pt_regs *regs)
 		mem_parity_error(reason, regs);
 		mem_parity_error(reason, regs);
 	if (reason & 0x40)
 	if (reason & 0x40)
 		io_check_error(reason, regs);
 		io_check_error(reason, regs);
+#ifdef CONFIG_X86_32
 	/*
 	/*
 	 * Reassert NMI in case it became active meanwhile
 	 * Reassert NMI in case it became active meanwhile
 	 * as it's edge-triggered:
 	 * as it's edge-triggered:
 	 */
 	 */
 	reassert_nmi();
 	reassert_nmi();
+#endif
 }
 }
 
 
 dotraplinkage notrace __kprobes void
 dotraplinkage notrace __kprobes void
@@ -453,7 +518,11 @@ do_nmi(struct pt_regs *regs, long error_code)
 {
 {
 	nmi_enter();
 	nmi_enter();
 
 
+#ifdef CONFIG_X86_32
 	{ int cpu; cpu = smp_processor_id(); ++nmi_count(cpu); }
 	{ int cpu; cpu = smp_processor_id(); ++nmi_count(cpu); }
+#else
+	add_pda(__nmi_count, 1);
+#endif
 
 
 	if (!ignore_nmis)
 	if (!ignore_nmis)
 		default_do_nmi(regs);
 		default_do_nmi(regs);
@@ -491,6 +560,29 @@ dotraplinkage void __kprobes do_int3(struct pt_regs *regs, long error_code)
 	preempt_conditional_cli(regs);
 	preempt_conditional_cli(regs);
 }
 }
 
 
+#ifdef CONFIG_X86_64
+/* Help handler running on IST stack to switch back to user stack
+   for scheduling or signal handling. The actual stack switch is done in
+   entry.S */
+asmlinkage __kprobes struct pt_regs *sync_regs(struct pt_regs *eregs)
+{
+	struct pt_regs *regs = eregs;
+	/* Did already sync */
+	if (eregs == (struct pt_regs *)eregs->sp)
+		;
+	/* Exception from user space */
+	else if (user_mode(eregs))
+		regs = task_pt_regs(current);
+	/* Exception from kernel and interrupts are enabled. Move to
+	   kernel process stack. */
+	else if (eregs->flags & X86_EFLAGS_IF)
+		regs = (struct pt_regs *)(eregs->sp -= sizeof(struct pt_regs));
+	if (eregs != regs)
+		*regs = *eregs;
+	return regs;
+}
+#endif
+
 /*
 /*
  * Our handling of the processor debug registers is non-trivial.
  * Our handling of the processor debug registers is non-trivial.
  * We do not clear them on entry and exit from the kernel. Therefore
  * We do not clear them on entry and exit from the kernel. Therefore
@@ -542,8 +634,10 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
 			goto clear_dr7;
 			goto clear_dr7;
 	}
 	}
 
 
+#ifdef CONFIG_X86_32
 	if (regs->flags & X86_VM_MASK)
 	if (regs->flags & X86_VM_MASK)
 		goto debug_vm86;
 		goto debug_vm86;
+#endif
 
 
 	/* Save debug status register where ptrace can see it */
 	/* Save debug status register where ptrace can see it */
 	tsk->thread.debugreg6 = condition;
 	tsk->thread.debugreg6 = condition;
@@ -570,10 +664,12 @@ clear_dr7:
 	preempt_conditional_cli(regs);
 	preempt_conditional_cli(regs);
 	return;
 	return;
 
 
+#ifdef CONFIG_X86_32
 debug_vm86:
 debug_vm86:
 	handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, 1);
 	handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, 1);
 	preempt_conditional_cli(regs);
 	preempt_conditional_cli(regs);
 	return;
 	return;
+#endif
 
 
 clear_TF_reenable:
 clear_TF_reenable:
 	set_tsk_thread_flag(tsk, TIF_SINGLESTEP);
 	set_tsk_thread_flag(tsk, TIF_SINGLESTEP);
@@ -582,6 +678,20 @@ clear_TF_reenable:
 	return;
 	return;
 }
 }
 
 
+#ifdef CONFIG_X86_64
+static int kernel_math_error(struct pt_regs *regs, const char *str, int trapnr)
+{
+	if (fixup_exception(regs))
+		return 1;
+
+	notify_die(DIE_GPF, str, regs, 0, trapnr, SIGFPE);
+	/* Illegal floating point operation in the kernel */
+	current->thread.trap_no = trapnr;
+	die(str, regs, 0);
+	return 0;
+}
+#endif
+
 /*
 /*
  * Note that we play around with the 'TS' bit in an attempt to get
  * Note that we play around with the 'TS' bit in an attempt to get
  * the correct behaviour even in the presence of the asynchronous
  * the correct behaviour even in the presence of the asynchronous
@@ -618,7 +728,9 @@ void math_error(void __user *ip)
 	swd = get_fpu_swd(task);
 	swd = get_fpu_swd(task);
 	switch (swd & ~cwd & 0x3f) {
 	switch (swd & ~cwd & 0x3f) {
 	case 0x000: /* No unmasked exception */
 	case 0x000: /* No unmasked exception */
+#ifdef CONFIG_X86_32
 		return;
 		return;
+#endif
 	default: /* Multiple exceptions */
 	default: /* Multiple exceptions */
 		break;
 		break;
 	case 0x001: /* Invalid Op */
 	case 0x001: /* Invalid Op */
@@ -649,7 +761,15 @@ void math_error(void __user *ip)
 dotraplinkage void do_coprocessor_error(struct pt_regs *regs, long error_code)
 dotraplinkage void do_coprocessor_error(struct pt_regs *regs, long error_code)
 {
 {
 	conditional_sti(regs);
 	conditional_sti(regs);
+
+#ifdef CONFIG_X86_32
 	ignore_fpu_irq = 1;
 	ignore_fpu_irq = 1;
+#else
+	if (!user_mode(regs) &&
+	    kernel_math_error(regs, "kernel x87 math error", 16))
+		return;
+#endif
+
 	math_error((void __user *)regs->ip);
 	math_error((void __user *)regs->ip);
 }
 }
 
 
@@ -706,6 +826,7 @@ do_simd_coprocessor_error(struct pt_regs *regs, long error_code)
 {
 {
 	conditional_sti(regs);
 	conditional_sti(regs);
 
 
+#ifdef CONFIG_X86_32
 	if (cpu_has_xmm) {
 	if (cpu_has_xmm) {
 		/* Handle SIMD FPU exceptions on PIII+ processors. */
 		/* Handle SIMD FPU exceptions on PIII+ processors. */
 		ignore_fpu_irq = 1;
 		ignore_fpu_irq = 1;
@@ -724,6 +845,12 @@ do_simd_coprocessor_error(struct pt_regs *regs, long error_code)
 	current->thread.error_code = error_code;
 	current->thread.error_code = error_code;
 	die_if_kernel("cache flush denied", regs, error_code);
 	die_if_kernel("cache flush denied", regs, error_code);
 	force_sig(SIGSEGV, current);
 	force_sig(SIGSEGV, current);
+#else
+	if (!user_mode(regs) &&
+			kernel_math_error(regs, "kernel simd math error", 19))
+		return;
+	simd_math_error((void __user *)regs->ip);
+#endif
 }
 }
 
 
 dotraplinkage void
 dotraplinkage void
@@ -736,6 +863,7 @@ do_spurious_interrupt_bug(struct pt_regs *regs, long error_code)
 #endif
 #endif
 }
 }
 
 
+#ifdef CONFIG_X86_32
 unsigned long patch_espfix_desc(unsigned long uesp, unsigned long kesp)
 unsigned long patch_espfix_desc(unsigned long uesp, unsigned long kesp)
 {
 {
 	struct desc_struct *gdt = get_cpu_gdt_table(smp_processor_id());
 	struct desc_struct *gdt = get_cpu_gdt_table(smp_processor_id());
@@ -754,6 +882,15 @@ unsigned long patch_espfix_desc(unsigned long uesp, unsigned long kesp)
 
 
 	return new_kesp;
 	return new_kesp;
 }
 }
+#else
+asmlinkage void __attribute__((weak)) smp_thermal_interrupt(void)
+{
+}
+
+asmlinkage void __attribute__((weak)) mce_threshold_interrupt(void)
+{
+}
+#endif
 
 
 /*
 /*
  * 'math_state_restore()' saves the current math information in the
  * 'math_state_restore()' saves the current math information in the
@@ -786,14 +923,24 @@ asmlinkage void math_state_restore(void)
 	}
 	}
 
 
 	clts();				/* Allow maths ops (or we recurse) */
 	clts();				/* Allow maths ops (or we recurse) */
+#ifdef CONFIG_X86_32
 	restore_fpu(tsk);
 	restore_fpu(tsk);
+#else
+	/*
+	 * Paranoid restore. send a SIGSEGV if we fail to restore the state.
+	 */
+	if (unlikely(restore_fpu_checking(tsk))) {
+		stts();
+		force_sig(SIGSEGV, tsk);
+		return;
+	}
+#endif
 	thread->status |= TS_USEDFPU;	/* So we fnsave on switch_to() */
 	thread->status |= TS_USEDFPU;	/* So we fnsave on switch_to() */
 	tsk->fpu_counter++;
 	tsk->fpu_counter++;
 }
 }
 EXPORT_SYMBOL_GPL(math_state_restore);
 EXPORT_SYMBOL_GPL(math_state_restore);
 
 
 #ifndef CONFIG_MATH_EMULATION
 #ifndef CONFIG_MATH_EMULATION
-
 asmlinkage void math_emulate(long arg)
 asmlinkage void math_emulate(long arg)
 {
 {
 	printk(KERN_EMERG
 	printk(KERN_EMERG
@@ -802,12 +949,12 @@ asmlinkage void math_emulate(long arg)
 	force_sig(SIGFPE, current);
 	force_sig(SIGFPE, current);
 	schedule();
 	schedule();
 }
 }
-
 #endif /* CONFIG_MATH_EMULATION */
 #endif /* CONFIG_MATH_EMULATION */
 
 
 dotraplinkage void __kprobes
 dotraplinkage void __kprobes
 do_device_not_available(struct pt_regs *regs, long error)
 do_device_not_available(struct pt_regs *regs, long error)
 {
 {
+#ifdef CONFIG_X86_32
 	if (read_cr0() & X86_CR0_EM) {
 	if (read_cr0() & X86_CR0_EM) {
 		conditional_sti(regs);
 		conditional_sti(regs);
 		math_emulate(0);
 		math_emulate(0);
@@ -815,8 +962,12 @@ do_device_not_available(struct pt_regs *regs, long error)
 		math_state_restore(); /* interrupts still off */
 		math_state_restore(); /* interrupts still off */
 		conditional_sti(regs);
 		conditional_sti(regs);
 	}
 	}
+#else
+	math_state_restore();
+#endif
 }
 }
 
 
+#ifdef CONFIG_X86_32
 #ifdef CONFIG_X86_MCE
 #ifdef CONFIG_X86_MCE
 dotraplinkage void __kprobes do_machine_check(struct pt_regs *regs, long error)
 dotraplinkage void __kprobes do_machine_check(struct pt_regs *regs, long error)
 {
 {
@@ -839,10 +990,13 @@ dotraplinkage void do_iret_error(struct pt_regs *regs, long error_code)
 		return;
 		return;
 	do_trap(32, SIGILL, "iret exception", regs, error_code, &info);
 	do_trap(32, SIGILL, "iret exception", regs, error_code, &info);
 }
 }
+#endif
 
 
 void __init trap_init(void)
 void __init trap_init(void)
 {
 {
+#ifdef CONFIG_X86_32
 	int i;
 	int i;
+#endif
 
 
 #ifdef CONFIG_EISA
 #ifdef CONFIG_EISA
 	void __iomem *p = early_ioremap(0x0FFFD9, 4);
 	void __iomem *p = early_ioremap(0x0FFFD9, 4);
@@ -862,7 +1016,11 @@ void __init trap_init(void)
 	set_intr_gate(5, &bounds);
 	set_intr_gate(5, &bounds);
 	set_intr_gate(6, &invalid_op);
 	set_intr_gate(6, &invalid_op);
 	set_intr_gate(7, &device_not_available);
 	set_intr_gate(7, &device_not_available);
+#ifdef CONFIG_X86_32
 	set_task_gate(8, GDT_ENTRY_DOUBLEFAULT_TSS);
 	set_task_gate(8, GDT_ENTRY_DOUBLEFAULT_TSS);
+#else
+	set_intr_gate_ist(8, &double_fault, DOUBLEFAULT_STACK);
+#endif
 	set_intr_gate(9, &coprocessor_segment_overrun);
 	set_intr_gate(9, &coprocessor_segment_overrun);
 	set_intr_gate(10, &invalid_TSS);
 	set_intr_gate(10, &invalid_TSS);
 	set_intr_gate(11, &segment_not_present);
 	set_intr_gate(11, &segment_not_present);
@@ -877,6 +1035,11 @@ void __init trap_init(void)
 #endif
 #endif
 	set_intr_gate(19, &simd_coprocessor_error);
 	set_intr_gate(19, &simd_coprocessor_error);
 
 
+#ifdef CONFIG_IA32_EMULATION
+	set_system_intr_gate(IA32_SYSCALL_VECTOR, ia32_syscall);
+#endif
+
+#ifdef CONFIG_X86_32
 	if (cpu_has_fxsr) {
 	if (cpu_has_fxsr) {
 		printk(KERN_INFO "Enabling fast FPU save and restore... ");
 		printk(KERN_INFO "Enabling fast FPU save and restore... ");
 		set_in_cr4(X86_CR4_OSFXSR);
 		set_in_cr4(X86_CR4_OSFXSR);
@@ -896,11 +1059,13 @@ void __init trap_init(void)
 		set_bit(i, used_vectors);
 		set_bit(i, used_vectors);
 
 
 	set_bit(SYSCALL_VECTOR, used_vectors);
 	set_bit(SYSCALL_VECTOR, used_vectors);
-
+#endif
 	/*
 	/*
 	 * Should be a barrier for any external CPU state:
 	 * Should be a barrier for any external CPU state:
 	 */
 	 */
 	cpu_init();
 	cpu_init();
 
 
+#ifdef CONFIG_X86_32
 	trap_init_hook();
 	trap_init_hook();
+#endif
 }
 }

+ 367 - 1
arch/x86/kernel/traps_64.c

@@ -33,13 +33,21 @@
 #include <linux/smp.h>
 #include <linux/smp.h>
 #include <linux/io.h>
 #include <linux/io.h>
 
 
+#ifdef CONFIG_EISA
+#include <linux/ioport.h>
+#include <linux/eisa.h>
+#endif
+
+#ifdef CONFIG_MCA
+#include <linux/mca.h>
+#endif
+
 #if defined(CONFIG_EDAC)
 #if defined(CONFIG_EDAC)
 #include <linux/edac.h>
 #include <linux/edac.h>
 #endif
 #endif
 
 
 #include <asm/stacktrace.h>
 #include <asm/stacktrace.h>
 #include <asm/processor.h>
 #include <asm/processor.h>
-#include <asm/kmemcheck.h>
 #include <asm/debugreg.h>
 #include <asm/debugreg.h>
 #include <asm/atomic.h>
 #include <asm/atomic.h>
 #include <asm/system.h>
 #include <asm/system.h>
@@ -50,10 +58,35 @@
 
 
 #include <mach_traps.h>
 #include <mach_traps.h>
 
 
+#ifdef CONFIG_X86_64
 #include <asm/pgalloc.h>
 #include <asm/pgalloc.h>
 #include <asm/proto.h>
 #include <asm/proto.h>
 #include <asm/pda.h>
 #include <asm/pda.h>
+#else
+#include <asm/processor-flags.h>
+#include <asm/arch_hooks.h>
+#include <asm/nmi.h>
+#include <asm/smp.h>
+#include <asm/io.h>
+
+#include "cpu/mcheck/mce.h"
 
 
+DECLARE_BITMAP(used_vectors, NR_VECTORS);
+EXPORT_SYMBOL_GPL(used_vectors);
+
+asmlinkage int system_call(void);
+
+/* Do we ignore FPU interrupts ? */
+char ignore_fpu_irq;
+
+/*
+ * The IDT has to be page-aligned to simplify the Pentium
+ * F0 0F bug workaround.. We have a special link segment
+ * for this.
+ */
+gate_desc idt_table[256]
+	__attribute__((__section__(".data.idt"))) = { { { { 0, 0 } } }, };
+#endif
 
 
 static int ignore_nmis;
 static int ignore_nmis;
 
 
@@ -77,15 +110,80 @@ static inline void preempt_conditional_cli(struct pt_regs *regs)
 	dec_preempt_count();
 	dec_preempt_count();
 }
 }
 
 
+#ifdef CONFIG_X86_32
+static inline void
+die_if_kernel(const char *str, struct pt_regs *regs, long err)
+{
+	if (!user_mode_vm(regs))
+		die(str, regs, err);
+}
+
+/*
+ * Perform the lazy TSS's I/O bitmap copy. If the TSS has an
+ * invalid offset set (the LAZY one) and the faulting thread has
+ * a valid I/O bitmap pointer, we copy the I/O bitmap in the TSS,
+ * we set the offset field correctly and return 1.
+ */
+static int lazy_iobitmap_copy(void)
+{
+	struct thread_struct *thread;
+	struct tss_struct *tss;
+	int cpu;
+
+	cpu = get_cpu();
+	tss = &per_cpu(init_tss, cpu);
+	thread = &current->thread;
+
+	if (tss->x86_tss.io_bitmap_base == INVALID_IO_BITMAP_OFFSET_LAZY &&
+	    thread->io_bitmap_ptr) {
+		memcpy(tss->io_bitmap, thread->io_bitmap_ptr,
+		       thread->io_bitmap_max);
+		/*
+		 * If the previously set map was extending to higher ports
+		 * than the current one, pad extra space with 0xff (no access).
+		 */
+		if (thread->io_bitmap_max < tss->io_bitmap_max) {
+			memset((char *) tss->io_bitmap +
+				thread->io_bitmap_max, 0xff,
+				tss->io_bitmap_max - thread->io_bitmap_max);
+		}
+		tss->io_bitmap_max = thread->io_bitmap_max;
+		tss->x86_tss.io_bitmap_base = IO_BITMAP_OFFSET;
+		tss->io_bitmap_owner = thread;
+		put_cpu();
+
+		return 1;
+	}
+	put_cpu();
+
+	return 0;
+}
+#endif
+
 static void __kprobes
 static void __kprobes
 do_trap(int trapnr, int signr, char *str, struct pt_regs *regs,
 do_trap(int trapnr, int signr, char *str, struct pt_regs *regs,
 	long error_code, siginfo_t *info)
 	long error_code, siginfo_t *info)
 {
 {
 	struct task_struct *tsk = current;
 	struct task_struct *tsk = current;
 
 
+#ifdef CONFIG_X86_32
+	if (regs->flags & X86_VM_MASK) {
+		/*
+		 * traps 0, 1, 3, 4, and 5 should be forwarded to vm86.
+		 * On nmi (interrupt 2), do_trap should not be called.
+		 */
+		if (trapnr < 6)
+			goto vm86_trap;
+		goto trap_signal;
+	}
+#endif
+
 	if (!user_mode(regs))
 	if (!user_mode(regs))
 		goto kernel_trap;
 		goto kernel_trap;
 
 
+#ifdef CONFIG_X86_32
+trap_signal:
+#endif
 	/*
 	/*
 	 * We want error_code and trap_no set for userspace faults and
 	 * We want error_code and trap_no set for userspace faults and
 	 * kernelspace faults which result in die(), but not
 	 * kernelspace faults which result in die(), but not
@@ -98,6 +196,7 @@ do_trap(int trapnr, int signr, char *str, struct pt_regs *regs,
 	tsk->thread.error_code = error_code;
 	tsk->thread.error_code = error_code;
 	tsk->thread.trap_no = trapnr;
 	tsk->thread.trap_no = trapnr;
 
 
+#ifdef CONFIG_X86_64
 	if (show_unhandled_signals && unhandled_signal(tsk, signr) &&
 	if (show_unhandled_signals && unhandled_signal(tsk, signr) &&
 	    printk_ratelimit()) {
 	    printk_ratelimit()) {
 		printk(KERN_INFO
 		printk(KERN_INFO
@@ -107,6 +206,7 @@ do_trap(int trapnr, int signr, char *str, struct pt_regs *regs,
 		print_vma_addr(" in ", regs->ip);
 		print_vma_addr(" in ", regs->ip);
 		printk("\n");
 		printk("\n");
 	}
 	}
+#endif
 
 
 	if (info)
 	if (info)
 		force_sig_info(signr, info, tsk);
 		force_sig_info(signr, info, tsk);
@@ -121,6 +221,14 @@ kernel_trap:
 		die(str, regs, error_code);
 		die(str, regs, error_code);
 	}
 	}
 	return;
 	return;
+
+#ifdef CONFIG_X86_32
+vm86_trap:
+	if (handle_vm86_trap((struct kernel_vm86_regs *) regs,
+						error_code, trapnr))
+		goto trap_signal;
+	return;
+#endif
 }
 }
 
 
 #define DO_ERROR(trapnr, signr, str, name)				\
 #define DO_ERROR(trapnr, signr, str, name)				\
@@ -155,8 +263,12 @@ DO_ERROR_INFO(6, SIGILL, "invalid opcode", invalid_op, ILL_ILLOPN, regs->ip)
 DO_ERROR(9, SIGFPE, "coprocessor segment overrun", coprocessor_segment_overrun)
 DO_ERROR(9, SIGFPE, "coprocessor segment overrun", coprocessor_segment_overrun)
 DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS)
 DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS)
 DO_ERROR(11, SIGBUS, "segment not present", segment_not_present)
 DO_ERROR(11, SIGBUS, "segment not present", segment_not_present)
+#ifdef CONFIG_X86_32
+DO_ERROR(12, SIGBUS, "stack segment", stack_segment)
+#endif
 DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0)
 DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0)
 
 
+#ifdef CONFIG_X86_64
 /* Runs on IST stack */
 /* Runs on IST stack */
 dotraplinkage void do_stack_segment(struct pt_regs *regs, long error_code)
 dotraplinkage void do_stack_segment(struct pt_regs *regs, long error_code)
 {
 {
@@ -184,6 +296,7 @@ dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code)
 	for (;;)
 	for (;;)
 		die(str, regs, error_code);
 		die(str, regs, error_code);
 }
 }
+#endif
 
 
 dotraplinkage void __kprobes
 dotraplinkage void __kprobes
 do_general_protection(struct pt_regs *regs, long error_code)
 do_general_protection(struct pt_regs *regs, long error_code)
@@ -192,6 +305,16 @@ do_general_protection(struct pt_regs *regs, long error_code)
 
 
 	conditional_sti(regs);
 	conditional_sti(regs);
 
 
+#ifdef CONFIG_X86_32
+	if (lazy_iobitmap_copy()) {
+		/* restart the faulting instruction */
+		return;
+	}
+
+	if (regs->flags & X86_VM_MASK)
+		goto gp_in_vm86;
+#endif
+
 	tsk = current;
 	tsk = current;
 	if (!user_mode(regs))
 	if (!user_mode(regs))
 		goto gp_in_kernel;
 		goto gp_in_kernel;
@@ -212,6 +335,13 @@ do_general_protection(struct pt_regs *regs, long error_code)
 	force_sig(SIGSEGV, tsk);
 	force_sig(SIGSEGV, tsk);
 	return;
 	return;
 
 
+#ifdef CONFIG_X86_32
+gp_in_vm86:
+	local_irq_enable();
+	handle_vm86_fault((struct kernel_vm86_regs *) regs, error_code);
+	return;
+#endif
+
 gp_in_kernel:
 gp_in_kernel:
 	if (fixup_exception(regs))
 	if (fixup_exception(regs))
 		return;
 		return;
@@ -277,6 +407,16 @@ unknown_nmi_error(unsigned char reason, struct pt_regs *regs)
 	if (notify_die(DIE_NMIUNKNOWN, "nmi", regs, reason, 2, SIGINT) ==
 	if (notify_die(DIE_NMIUNKNOWN, "nmi", regs, reason, 2, SIGINT) ==
 			NOTIFY_STOP)
 			NOTIFY_STOP)
 		return;
 		return;
+#ifdef CONFIG_MCA
+	/*
+	 * Might actually be able to figure out what the guilty party
+	 * is:
+	 */
+	if (MCA_bus) {
+		mca_handle_nmi();
+		return;
+	}
+#endif
 	printk(KERN_EMERG
 	printk(KERN_EMERG
 		"Uhhuh. NMI received for unknown reason %02x on CPU %d.\n",
 		"Uhhuh. NMI received for unknown reason %02x on CPU %d.\n",
 			reason, smp_processor_id());
 			reason, smp_processor_id());
@@ -288,6 +428,43 @@ unknown_nmi_error(unsigned char reason, struct pt_regs *regs)
 	printk(KERN_EMERG "Dazed and confused, but trying to continue\n");
 	printk(KERN_EMERG "Dazed and confused, but trying to continue\n");
 }
 }
 
 
+#ifdef CONFIG_X86_32
+static DEFINE_SPINLOCK(nmi_print_lock);
+
+void notrace __kprobes die_nmi(char *str, struct pt_regs *regs, int do_panic)
+{
+	if (notify_die(DIE_NMIWATCHDOG, str, regs, 0, 2, SIGINT) == NOTIFY_STOP)
+		return;
+
+	spin_lock(&nmi_print_lock);
+	/*
+	* We are in trouble anyway, lets at least try
+	* to get a message out:
+	*/
+	bust_spinlocks(1);
+	printk(KERN_EMERG "%s", str);
+	printk(" on CPU%d, ip %08lx, registers:\n",
+		smp_processor_id(), regs->ip);
+	show_registers(regs);
+	if (do_panic)
+		panic("Non maskable interrupt");
+	console_silent();
+	spin_unlock(&nmi_print_lock);
+	bust_spinlocks(0);
+
+	/*
+	 * If we are in kernel we are probably nested up pretty bad
+	 * and might aswell get out now while we still can:
+	 */
+	if (!user_mode_vm(regs)) {
+		current->thread.trap_no = 2;
+		crash_kexec(regs);
+	}
+
+	do_exit(SIGSEGV);
+}
+#endif
+
 static notrace __kprobes void default_do_nmi(struct pt_regs *regs)
 static notrace __kprobes void default_do_nmi(struct pt_regs *regs)
 {
 {
 	unsigned char reason = 0;
 	unsigned char reason = 0;
@@ -303,6 +480,7 @@ static notrace __kprobes void default_do_nmi(struct pt_regs *regs)
 		if (notify_die(DIE_NMI_IPI, "nmi_ipi", regs, reason, 2, SIGINT)
 		if (notify_die(DIE_NMI_IPI, "nmi_ipi", regs, reason, 2, SIGINT)
 								== NOTIFY_STOP)
 								== NOTIFY_STOP)
 			return;
 			return;
+#ifdef CONFIG_X86_LOCAL_APIC
 		/*
 		/*
 		 * Ok, so this is none of the documented NMI sources,
 		 * Ok, so this is none of the documented NMI sources,
 		 * so it must be the NMI watchdog.
 		 * so it must be the NMI watchdog.
@@ -311,6 +489,9 @@ static notrace __kprobes void default_do_nmi(struct pt_regs *regs)
 			return;
 			return;
 		if (!do_nmi_callback(regs, cpu))
 		if (!do_nmi_callback(regs, cpu))
 			unknown_nmi_error(reason, regs);
 			unknown_nmi_error(reason, regs);
+#else
+		unknown_nmi_error(reason, regs);
+#endif
 
 
 		return;
 		return;
 	}
 	}
@@ -322,6 +503,13 @@ static notrace __kprobes void default_do_nmi(struct pt_regs *regs)
 		mem_parity_error(reason, regs);
 		mem_parity_error(reason, regs);
 	if (reason & 0x40)
 	if (reason & 0x40)
 		io_check_error(reason, regs);
 		io_check_error(reason, regs);
+#ifdef CONFIG_X86_32
+	/*
+	 * Reassert NMI in case it became active meanwhile
+	 * as it's edge-triggered:
+	 */
+	reassert_nmi();
+#endif
 }
 }
 
 
 dotraplinkage notrace __kprobes void
 dotraplinkage notrace __kprobes void
@@ -329,7 +517,11 @@ do_nmi(struct pt_regs *regs, long error_code)
 {
 {
 	nmi_enter();
 	nmi_enter();
 
 
+#ifdef CONFIG_X86_32
+	{ int cpu; cpu = smp_processor_id(); ++nmi_count(cpu); }
+#else
 	add_pda(__nmi_count, 1);
 	add_pda(__nmi_count, 1);
+#endif
 
 
 	if (!ignore_nmis)
 	if (!ignore_nmis)
 		default_do_nmi(regs);
 		default_do_nmi(regs);
@@ -352,15 +544,22 @@ void restart_nmi(void)
 /* May run on IST stack. */
 /* May run on IST stack. */
 dotraplinkage void __kprobes do_int3(struct pt_regs *regs, long error_code)
 dotraplinkage void __kprobes do_int3(struct pt_regs *regs, long error_code)
 {
 {
+#ifdef CONFIG_KPROBES
 	if (notify_die(DIE_INT3, "int3", regs, error_code, 3, SIGTRAP)
 	if (notify_die(DIE_INT3, "int3", regs, error_code, 3, SIGTRAP)
 			== NOTIFY_STOP)
 			== NOTIFY_STOP)
 		return;
 		return;
+#else
+	if (notify_die(DIE_TRAP, "int3", regs, error_code, 3, SIGTRAP)
+			== NOTIFY_STOP)
+		return;
+#endif
 
 
 	preempt_conditional_sti(regs);
 	preempt_conditional_sti(regs);
 	do_trap(3, SIGTRAP, "int3", regs, error_code, NULL);
 	do_trap(3, SIGTRAP, "int3", regs, error_code, NULL);
 	preempt_conditional_cli(regs);
 	preempt_conditional_cli(regs);
 }
 }
 
 
+#ifdef CONFIG_X86_64
 /* Help handler running on IST stack to switch back to user stack
 /* Help handler running on IST stack to switch back to user stack
    for scheduling or signal handling. The actual stack switch is done in
    for scheduling or signal handling. The actual stack switch is done in
    entry.S */
    entry.S */
@@ -381,6 +580,7 @@ asmlinkage __kprobes struct pt_regs *sync_regs(struct pt_regs *eregs)
 		*regs = *eregs;
 		*regs = *eregs;
 	return regs;
 	return regs;
 }
 }
+#endif
 
 
 /*
 /*
  * Our handling of the processor debug registers is non-trivial.
  * Our handling of the processor debug registers is non-trivial.
@@ -433,6 +633,11 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
 			goto clear_dr7;
 			goto clear_dr7;
 	}
 	}
 
 
+#ifdef CONFIG_X86_32
+	if (regs->flags & X86_VM_MASK)
+		goto debug_vm86;
+#endif
+
 	/* Save debug status register where ptrace can see it */
 	/* Save debug status register where ptrace can see it */
 	tsk->thread.debugreg6 = condition;
 	tsk->thread.debugreg6 = condition;
 
 
@@ -458,6 +663,13 @@ clear_dr7:
 	preempt_conditional_cli(regs);
 	preempt_conditional_cli(regs);
 	return;
 	return;
 
 
+#ifdef CONFIG_X86_32
+debug_vm86:
+	handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, 1);
+	preempt_conditional_cli(regs);
+	return;
+#endif
+
 clear_TF_reenable:
 clear_TF_reenable:
 	set_tsk_thread_flag(tsk, TIF_SINGLESTEP);
 	set_tsk_thread_flag(tsk, TIF_SINGLESTEP);
 	regs->flags &= ~X86_EFLAGS_TF;
 	regs->flags &= ~X86_EFLAGS_TF;
@@ -465,6 +677,7 @@ clear_TF_reenable:
 	return;
 	return;
 }
 }
 
 
+#ifdef CONFIG_X86_64
 static int kernel_math_error(struct pt_regs *regs, const char *str, int trapnr)
 static int kernel_math_error(struct pt_regs *regs, const char *str, int trapnr)
 {
 {
 	if (fixup_exception(regs))
 	if (fixup_exception(regs))
@@ -476,6 +689,7 @@ static int kernel_math_error(struct pt_regs *regs, const char *str, int trapnr)
 	die(str, regs, 0);
 	die(str, regs, 0);
 	return 0;
 	return 0;
 }
 }
+#endif
 
 
 /*
 /*
  * Note that we play around with the 'TS' bit in an attempt to get
  * Note that we play around with the 'TS' bit in an attempt to get
@@ -513,6 +727,9 @@ void math_error(void __user *ip)
 	swd = get_fpu_swd(task);
 	swd = get_fpu_swd(task);
 	switch (swd & ~cwd & 0x3f) {
 	switch (swd & ~cwd & 0x3f) {
 	case 0x000: /* No unmasked exception */
 	case 0x000: /* No unmasked exception */
+#ifdef CONFIG_X86_32
+		return;
+#endif
 	default: /* Multiple exceptions */
 	default: /* Multiple exceptions */
 		break;
 		break;
 	case 0x001: /* Invalid Op */
 	case 0x001: /* Invalid Op */
@@ -543,9 +760,15 @@ void math_error(void __user *ip)
 dotraplinkage void do_coprocessor_error(struct pt_regs *regs, long error_code)
 dotraplinkage void do_coprocessor_error(struct pt_regs *regs, long error_code)
 {
 {
 	conditional_sti(regs);
 	conditional_sti(regs);
+
+#ifdef CONFIG_X86_32
+	ignore_fpu_irq = 1;
+#else
 	if (!user_mode(regs) &&
 	if (!user_mode(regs) &&
 	    kernel_math_error(regs, "kernel x87 math error", 16))
 	    kernel_math_error(regs, "kernel x87 math error", 16))
 		return;
 		return;
+#endif
+
 	math_error((void __user *)regs->ip);
 	math_error((void __user *)regs->ip);
 }
 }
 
 
@@ -601,17 +824,64 @@ dotraplinkage void
 do_simd_coprocessor_error(struct pt_regs *regs, long error_code)
 do_simd_coprocessor_error(struct pt_regs *regs, long error_code)
 {
 {
 	conditional_sti(regs);
 	conditional_sti(regs);
+
+#ifdef CONFIG_X86_32
+	if (cpu_has_xmm) {
+		/* Handle SIMD FPU exceptions on PIII+ processors. */
+		ignore_fpu_irq = 1;
+		simd_math_error((void __user *)regs->ip);
+		return;
+	}
+	/*
+	 * Handle strange cache flush from user space exception
+	 * in all other cases.  This is undocumented behaviour.
+	 */
+	if (regs->flags & X86_VM_MASK) {
+		handle_vm86_fault((struct kernel_vm86_regs *)regs, error_code);
+		return;
+	}
+	current->thread.trap_no = 19;
+	current->thread.error_code = error_code;
+	die_if_kernel("cache flush denied", regs, error_code);
+	force_sig(SIGSEGV, current);
+#else
 	if (!user_mode(regs) &&
 	if (!user_mode(regs) &&
 			kernel_math_error(regs, "kernel simd math error", 19))
 			kernel_math_error(regs, "kernel simd math error", 19))
 		return;
 		return;
 	simd_math_error((void __user *)regs->ip);
 	simd_math_error((void __user *)regs->ip);
+#endif
 }
 }
 
 
 dotraplinkage void
 dotraplinkage void
 do_spurious_interrupt_bug(struct pt_regs *regs, long error_code)
 do_spurious_interrupt_bug(struct pt_regs *regs, long error_code)
 {
 {
+	conditional_sti(regs);
+#if 0
+	/* No need to warn about this any longer. */
+	printk(KERN_INFO "Ignoring P6 Local APIC Spurious Interrupt Bug...\n");
+#endif
 }
 }
 
 
+#ifdef CONFIG_X86_32
+unsigned long patch_espfix_desc(unsigned long uesp, unsigned long kesp)
+{
+	struct desc_struct *gdt = get_cpu_gdt_table(smp_processor_id());
+	unsigned long base = (kesp - uesp) & -THREAD_SIZE;
+	unsigned long new_kesp = kesp - base;
+	unsigned long lim_pages = (new_kesp | (THREAD_SIZE - 1)) >> PAGE_SHIFT;
+	__u64 desc = *(__u64 *)&gdt[GDT_ENTRY_ESPFIX_SS];
+
+	/* Set up base for espfix segment */
+	desc &= 0x00f0ff0000000000ULL;
+	desc |=	((((__u64)base) << 16) & 0x000000ffffff0000ULL) |
+		((((__u64)base) << 32) & 0xff00000000000000ULL) |
+		((((__u64)lim_pages) << 32) & 0x000f000000000000ULL) |
+		(lim_pages & 0xffff);
+	*(__u64 *)&gdt[GDT_ENTRY_ESPFIX_SS] = desc;
+
+	return new_kesp;
+}
+#else
 asmlinkage void __attribute__((weak)) smp_thermal_interrupt(void)
 asmlinkage void __attribute__((weak)) smp_thermal_interrupt(void)
 {
 {
 }
 }
@@ -619,6 +889,7 @@ asmlinkage void __attribute__((weak)) smp_thermal_interrupt(void)
 asmlinkage void __attribute__((weak)) mce_threshold_interrupt(void)
 asmlinkage void __attribute__((weak)) mce_threshold_interrupt(void)
 {
 {
 }
 }
+#endif
 
 
 /*
 /*
  * 'math_state_restore()' saves the current math information in the
  * 'math_state_restore()' saves the current math information in the
@@ -626,6 +897,9 @@ asmlinkage void __attribute__((weak)) mce_threshold_interrupt(void)
  *
  *
  * Careful.. There are problems with IBM-designed IRQ13 behaviour.
  * Careful.. There are problems with IBM-designed IRQ13 behaviour.
  * Don't touch unless you *really* know how it works.
  * Don't touch unless you *really* know how it works.
+ *
+ * Must be called with kernel preemption disabled (in this case,
+ * local interrupts are disabled at the call-site in entry.S).
  */
  */
 asmlinkage void math_state_restore(void)
 asmlinkage void math_state_restore(void)
 {
 {
@@ -648,6 +922,9 @@ asmlinkage void math_state_restore(void)
 	}
 	}
 
 
 	clts();				/* Allow maths ops (or we recurse) */
 	clts();				/* Allow maths ops (or we recurse) */
+#ifdef CONFIG_X86_32
+	restore_fpu(tsk);
+#else
 	/*
 	/*
 	 * Paranoid restore. send a SIGSEGV if we fail to restore the state.
 	 * Paranoid restore. send a SIGSEGV if we fail to restore the state.
 	 */
 	 */
@@ -656,19 +933,78 @@ asmlinkage void math_state_restore(void)
 		force_sig(SIGSEGV, tsk);
 		force_sig(SIGSEGV, tsk);
 		return;
 		return;
 	}
 	}
+#endif
 	thread->status |= TS_USEDFPU;	/* So we fnsave on switch_to() */
 	thread->status |= TS_USEDFPU;	/* So we fnsave on switch_to() */
 	tsk->fpu_counter++;
 	tsk->fpu_counter++;
 }
 }
 EXPORT_SYMBOL_GPL(math_state_restore);
 EXPORT_SYMBOL_GPL(math_state_restore);
 
 
+#ifndef CONFIG_MATH_EMULATION
+asmlinkage void math_emulate(long arg)
+{
+	printk(KERN_EMERG
+		"math-emulation not enabled and no coprocessor found.\n");
+	printk(KERN_EMERG "killing %s.\n", current->comm);
+	force_sig(SIGFPE, current);
+	schedule();
+}
+#endif /* CONFIG_MATH_EMULATION */
+
 dotraplinkage void __kprobes
 dotraplinkage void __kprobes
 do_device_not_available(struct pt_regs *regs, long error)
 do_device_not_available(struct pt_regs *regs, long error)
 {
 {
+#ifdef CONFIG_X86_32
+	if (read_cr0() & X86_CR0_EM) {
+		conditional_sti(regs);
+		math_emulate(0);
+	} else {
+		math_state_restore(); /* interrupts still off */
+		conditional_sti(regs);
+	}
+#else
 	math_state_restore();
 	math_state_restore();
+#endif
+}
+
+#ifdef CONFIG_X86_32
+#ifdef CONFIG_X86_MCE
+dotraplinkage void __kprobes do_machine_check(struct pt_regs *regs, long error)
+{
+	conditional_sti(regs);
+	machine_check_vector(regs, error);
 }
 }
+#endif
+
+dotraplinkage void do_iret_error(struct pt_regs *regs, long error_code)
+{
+	siginfo_t info;
+	local_irq_enable();
+
+	info.si_signo = SIGILL;
+	info.si_errno = 0;
+	info.si_code = ILL_BADSTK;
+	info.si_addr = 0;
+	if (notify_die(DIE_TRAP, "iret exception",
+			regs, error_code, 32, SIGILL) == NOTIFY_STOP)
+		return;
+	do_trap(32, SIGILL, "iret exception", regs, error_code, &info);
+}
+#endif
 
 
 void __init trap_init(void)
 void __init trap_init(void)
 {
 {
+#ifdef CONFIG_X86_32
+	int i;
+#endif
+
+#ifdef CONFIG_EISA
+	void __iomem *p = early_ioremap(0x0FFFD9, 4);
+
+	if (readl(p) == 'E' + ('I'<<8) + ('S'<<16) + ('A'<<24))
+		EISA_bus = 1;
+	early_iounmap(p, 4);
+#endif
+
 	set_intr_gate(0, &divide_error);
 	set_intr_gate(0, &divide_error);
 	set_intr_gate_ist(1, &debug, DEBUG_STACK);
 	set_intr_gate_ist(1, &debug, DEBUG_STACK);
 	set_intr_gate_ist(2, &nmi, NMI_STACK);
 	set_intr_gate_ist(2, &nmi, NMI_STACK);
@@ -679,7 +1015,11 @@ void __init trap_init(void)
 	set_intr_gate(5, &bounds);
 	set_intr_gate(5, &bounds);
 	set_intr_gate(6, &invalid_op);
 	set_intr_gate(6, &invalid_op);
 	set_intr_gate(7, &device_not_available);
 	set_intr_gate(7, &device_not_available);
+#ifdef CONFIG_X86_32
+	set_task_gate(8, GDT_ENTRY_DOUBLEFAULT_TSS);
+#else
 	set_intr_gate_ist(8, &double_fault, DOUBLEFAULT_STACK);
 	set_intr_gate_ist(8, &double_fault, DOUBLEFAULT_STACK);
+#endif
 	set_intr_gate(9, &coprocessor_segment_overrun);
 	set_intr_gate(9, &coprocessor_segment_overrun);
 	set_intr_gate(10, &invalid_TSS);
 	set_intr_gate(10, &invalid_TSS);
 	set_intr_gate(11, &segment_not_present);
 	set_intr_gate(11, &segment_not_present);
@@ -697,8 +1037,34 @@ void __init trap_init(void)
 #ifdef CONFIG_IA32_EMULATION
 #ifdef CONFIG_IA32_EMULATION
 	set_system_intr_gate(IA32_SYSCALL_VECTOR, ia32_syscall);
 	set_system_intr_gate(IA32_SYSCALL_VECTOR, ia32_syscall);
 #endif
 #endif
+
+#ifdef CONFIG_X86_32
+	if (cpu_has_fxsr) {
+		printk(KERN_INFO "Enabling fast FPU save and restore... ");
+		set_in_cr4(X86_CR4_OSFXSR);
+		printk("done.\n");
+	}
+	if (cpu_has_xmm) {
+		printk(KERN_INFO
+			"Enabling unmasked SIMD FPU exception support... ");
+		set_in_cr4(X86_CR4_OSXMMEXCPT);
+		printk("done.\n");
+	}
+
+	set_system_trap_gate(SYSCALL_VECTOR, &system_call);
+
+	/* Reserve all the builtin and the syscall vector: */
+	for (i = 0; i < FIRST_EXTERNAL_VECTOR; i++)
+		set_bit(i, used_vectors);
+
+	set_bit(SYSCALL_VECTOR, used_vectors);
+#endif
 	/*
 	/*
 	 * Should be a barrier for any external CPU state:
 	 * Should be a barrier for any external CPU state:
 	 */
 	 */
 	cpu_init();
 	cpu_init();
+
+#ifdef CONFIG_X86_32
+	trap_init_hook();
+#endif
 }
 }