x86: Make support for 16-bit segments a config option

Embedded systems and the like are likely never going to experience
16-bit software, so make it an option to reject them entirely and not
carry any of the overhead.

Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 25d2c6f..f1da8b1 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -914,6 +914,14 @@
 	  XFree86 to initialize some video cards via BIOS. Disabling this
 	  option saves about 6k.
 
+config X86_16BIT
+	bool "Enable 16-bit segments" if EXPERT
+	default y
+	---help---
+	  This option enables the execution of 16-bit protected mode
+	  software.  This is primarily used to run Win16 software
+	  under Wine and 16-bit extended DOS programs under DOSEMU.
+
 config TOSHIBA
 	tristate "Toshiba Laptop support"
 	depends on X86_32
diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S
index 2780b8f..30dd6e5 100644
--- a/arch/x86/kernel/entry_32.S
+++ b/arch/x86/kernel/entry_32.S
@@ -527,6 +527,7 @@
 restore_all:
 	TRACE_IRQS_IRET
 restore_all_notrace:
+#ifdef CONFIG_X86_16BIT
 	movl PT_EFLAGS(%esp), %eax	# mix EFLAGS, SS and CS
 	# Warning: PT_OLDSS(%esp) contains the wrong/random values if we
 	# are returning to the kernel.
@@ -537,6 +538,7 @@
 	cmpl $((SEGMENT_LDT << 8) | USER_RPL), %eax
 	CFI_REMEMBER_STATE
 	je ldt_ss			# returning to user-space with LDT SS
+#endif
 restore_nocheck:
 	RESTORE_REGS 4			# skip orig_eax/error_code
 irq_return:
@@ -549,6 +551,7 @@
 .previous
 	_ASM_EXTABLE(irq_return,iret_exc)
 
+#ifdef CONFIG_X86_16BIT
 	CFI_RESTORE_STATE
 ldt_ss:
 #ifdef CONFIG_PARAVIRT
@@ -592,6 +595,7 @@
 	lss (%esp), %esp		/* switch to espfix segment */
 	CFI_ADJUST_CFA_OFFSET -8
 	jmp restore_nocheck
+#endif /* CONFIG_X86_16BIT */
 	CFI_ENDPROC
 ENDPROC(system_call)
 
@@ -692,6 +696,7 @@
 	.popsection
 
 .macro FIXUP_ESPFIX_STACK
+#ifdef CONFIG_X86_16BIT
 /*
  * Switch back for ESPFIX stack to the normal zerobased stack
  *
@@ -708,8 +713,10 @@
 	pushl_cfi %eax
 	lss (%esp), %esp		/* switch to the normal stack segment */
 	CFI_ADJUST_CFA_OFFSET -8
+#endif
 .endm
 .macro UNWIND_ESPFIX_STACK
+#ifdef CONFIG_X86_16BIT
 	movl %ss, %eax
 	/* see if on espfix stack */
 	cmpw $__ESPFIX_SS, %ax
@@ -720,6 +727,7 @@
 	/* switch to normal stack */
 	FIXUP_ESPFIX_STACK
 27:
+#endif
 .endm
 
 /*
@@ -1350,11 +1358,13 @@
 ENTRY(nmi)
 	RING0_INT_FRAME
 	ASM_CLAC
+#ifdef CONFIG_X86_16BIT
 	pushl_cfi %eax
 	movl %ss, %eax
 	cmpw $__ESPFIX_SS, %ax
 	popl_cfi %eax
 	je nmi_espfix_stack
+#endif
 	cmpl $ia32_sysenter_target,(%esp)
 	je nmi_stack_fixup
 	pushl_cfi %eax
@@ -1394,6 +1404,7 @@
 	FIX_STACK 24, nmi_stack_correct, 1
 	jmp nmi_stack_correct
 
+#ifdef CONFIG_X86_16BIT
 nmi_espfix_stack:
 	/* We have a RING0_INT_FRAME here.
 	 *
@@ -1415,6 +1426,8 @@
 	lss 12+4(%esp), %esp		# back to espfix stack
 	CFI_ADJUST_CFA_OFFSET -24
 	jmp irq_return
+#endif /* CONFIG_X86_16BIT */
+
 	CFI_ENDPROC
 END(nmi)
 
diff --git a/arch/x86/kernel/ldt.c b/arch/x86/kernel/ldt.c
index af1d14a..cc34ae8 100644
--- a/arch/x86/kernel/ldt.c
+++ b/arch/x86/kernel/ldt.c
@@ -229,11 +229,7 @@
 		}
 	}
 
-	/*
-	 * On x86-64 we do not support 16-bit segments due to
-	 * IRET leaking the high bits of the kernel stack address.
-	 */
-#ifdef CONFIG_X86_64
+#ifndef CONFIG_X86_16BIT
 	if (!ldt_info.seg_32bit) {
 		error = -EINVAL;
 		goto out_unlock;