x86, espfix: Make it possible to disable 16-bit support
authorH. Peter Anvin <hpa@zytor.com>
Sun, 4 May 2014 17:36:22 +0000 (10:36 -0700)
committerBen Hutchings <ben@decadent.org.uk>
Sat, 13 Sep 2014 22:41:51 +0000 (23:41 +0100)
commit 34273f41d57ee8d854dcd2a1d754cbb546cb548f upstream.

Embedded systems, which may be very memory-size-sensitive, are
extremely unlikely to ever encounter any 16-bit software, so make it
a CONFIG_EXPERT option to turn off support for any 16-bit software
whatsoever.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
Link: http://lkml.kernel.org/r/1398816946-3351-1-git-send-email-hpa@linux.intel.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
arch/x86/Kconfig
arch/x86/kernel/entry_32.S
arch/x86/kernel/entry_64.S
arch/x86/kernel/ldt.c

index 6c9ec2d..28a1bca 100644 (file)
@@ -896,14 +896,27 @@ config VM86
        default y
        depends on X86_32
        ---help---
        default y
        depends on X86_32
        ---help---
-         This option is required by programs like DOSEMU to run 16-bit legacy
-         code on X86 processors. It also may be needed by software like
-         XFree86 to initialize some video cards via BIOS. Disabling this
-         option saves about 6k.
+         This option is required by programs like DOSEMU to run
+         16-bit real mode legacy code on x86 processors. It also may
+         be needed by software like XFree86 to initialize some video
+         cards via BIOS. Disabling this option saves about 6K.
+
+config X86_16BIT
+       bool "Enable support for 16-bit segments" if EXPERT
+       default y
+       ---help---
+         This option is required by programs like Wine to run 16-bit
+         protected mode legacy code on x86 processors.  Disabling
+         this option saves about 300 bytes on i386, or around 6K text
+         plus 16K runtime memory on x86-64,
+
+config X86_ESPFIX32
+       def_bool y
+       depends on X86_16BIT && X86_32
 
 config X86_ESPFIX64
        def_bool y
 
 config X86_ESPFIX64
        def_bool y
-       depends on X86_64
+       depends on X86_16BIT && X86_64
 
 config TOSHIBA
        tristate "Toshiba Laptop support"
 
 config TOSHIBA
        tristate "Toshiba Laptop support"
index dd52355..0fa4f89 100644 (file)
@@ -527,6 +527,7 @@ syscall_exit:
 restore_all:
        TRACE_IRQS_IRET
 restore_all_notrace:
 restore_all:
        TRACE_IRQS_IRET
 restore_all_notrace:
+#ifdef CONFIG_X86_ESPFIX32
        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.
        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 @@ restore_all_notrace:
        cmpl $((SEGMENT_LDT << 8) | USER_RPL), %eax
        CFI_REMEMBER_STATE
        je ldt_ss                       # returning to user-space with LDT SS
        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:
 restore_nocheck:
        RESTORE_REGS 4                  # skip orig_eax/error_code
 irq_return:
@@ -552,6 +554,7 @@ ENTRY(iret_exc)
        .long irq_return,iret_exc
 .previous
 
        .long irq_return,iret_exc
 .previous
 
+#ifdef CONFIG_X86_ESPFIX32
        CFI_RESTORE_STATE
 ldt_ss:
 #ifdef CONFIG_PARAVIRT
        CFI_RESTORE_STATE
 ldt_ss:
 #ifdef CONFIG_PARAVIRT
@@ -595,6 +598,7 @@ ldt_ss:
        lss (%esp), %esp                /* switch to espfix segment */
        CFI_ADJUST_CFA_OFFSET -8
        jmp restore_nocheck
        lss (%esp), %esp                /* switch to espfix segment */
        CFI_ADJUST_CFA_OFFSET -8
        jmp restore_nocheck
+#endif
        CFI_ENDPROC
 ENDPROC(system_call)
 
        CFI_ENDPROC
 ENDPROC(system_call)
 
@@ -766,6 +770,7 @@ ENDPROC(ptregs_clone)
  * the high word of the segment base from the GDT and swiches to the
  * normal stack and adjusts ESP with the matching offset.
  */
  * the high word of the segment base from the GDT and swiches to the
  * normal stack and adjusts ESP with the matching offset.
  */
+#ifdef CONFIG_X86_ESPFIX32
        /* fixup the stack */
        mov GDT_ESPFIX_SS + 4, %al /* bits 16..23 */
        mov GDT_ESPFIX_SS + 7, %ah /* bits 24..31 */
        /* fixup the stack */
        mov GDT_ESPFIX_SS + 4, %al /* bits 16..23 */
        mov GDT_ESPFIX_SS + 7, %ah /* bits 24..31 */
@@ -775,8 +780,10 @@ ENDPROC(ptregs_clone)
        pushl_cfi %eax
        lss (%esp), %esp                /* switch to the normal stack segment */
        CFI_ADJUST_CFA_OFFSET -8
        pushl_cfi %eax
        lss (%esp), %esp                /* switch to the normal stack segment */
        CFI_ADJUST_CFA_OFFSET -8
+#endif
 .endm
 .macro UNWIND_ESPFIX_STACK
 .endm
 .macro UNWIND_ESPFIX_STACK
+#ifdef CONFIG_X86_ESPFIX32
        movl %ss, %eax
        /* see if on espfix stack */
        cmpw $__ESPFIX_SS, %ax
        movl %ss, %eax
        /* see if on espfix stack */
        cmpw $__ESPFIX_SS, %ax
@@ -787,6 +794,7 @@ ENDPROC(ptregs_clone)
        /* switch to normal stack */
        FIXUP_ESPFIX_STACK
 27:
        /* switch to normal stack */
        FIXUP_ESPFIX_STACK
 27:
+#endif
 .endm
 
 /*
 .endm
 
 /*
@@ -1323,11 +1331,13 @@ END(debug)
  */
 ENTRY(nmi)
        RING0_INT_FRAME
  */
 ENTRY(nmi)
        RING0_INT_FRAME
+#ifdef CONFIG_X86_ESPFIX32
        pushl_cfi %eax
        movl %ss, %eax
        cmpw $__ESPFIX_SS, %ax
        popl_cfi %eax
        je nmi_espfix_stack
        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
        cmpl $ia32_sysenter_target,(%esp)
        je nmi_stack_fixup
        pushl_cfi %eax
@@ -1367,6 +1377,7 @@ nmi_debug_stack_check:
        FIX_STACK 24, nmi_stack_correct, 1
        jmp nmi_stack_correct
 
        FIX_STACK 24, nmi_stack_correct, 1
        jmp nmi_stack_correct
 
+#ifdef CONFIG_X86_ESPFIX32
 nmi_espfix_stack:
        /* We have a RING0_INT_FRAME here.
         *
 nmi_espfix_stack:
        /* We have a RING0_INT_FRAME here.
         *
@@ -1388,6 +1399,7 @@ nmi_espfix_stack:
        lss 12+4(%esp), %esp            # back to espfix stack
        CFI_ADJUST_CFA_OFFSET -24
        jmp irq_return
        lss 12+4(%esp), %esp            # back to espfix stack
        CFI_ADJUST_CFA_OFFSET -24
        jmp irq_return
+#endif
        CFI_ENDPROC
 END(nmi)
 
        CFI_ENDPROC
 END(nmi)
 
index 3812ef6..67fd181 100644 (file)
@@ -865,8 +865,10 @@ irq_return:
         * Are we returning to a stack segment from the LDT?  Note: in
         * 64-bit mode SS:RSP on the exception stack is always valid.
         */
         * Are we returning to a stack segment from the LDT?  Note: in
         * 64-bit mode SS:RSP on the exception stack is always valid.
         */
+#ifdef CONFIG_X86_ESPFIX64
        testb $4,(SS-RIP)(%rsp)
        jnz irq_return_ldt
        testb $4,(SS-RIP)(%rsp)
        jnz irq_return_ldt
+#endif
 
 irq_return_iret:
        INTERRUPT_RETURN
 
 irq_return_iret:
        INTERRUPT_RETURN
@@ -884,6 +886,7 @@ ENTRY(native_iret)
        .previous
 #endif
 
        .previous
 #endif
 
+#ifdef CONFIG_X86_ESPFIX64
 irq_return_ldt:
        pushq_cfi %rax
        pushq_cfi %rdi
 irq_return_ldt:
        pushq_cfi %rax
        pushq_cfi %rdi
@@ -907,6 +910,7 @@ irq_return_ldt:
        movq %rax,%rsp
        popq_cfi %rax
        jmp irq_return_iret
        movq %rax,%rsp
        popq_cfi %rax
        jmp irq_return_iret
+#endif
 
        .section .fixup,"ax"
 bad_iret:
 
        .section .fixup,"ax"
 bad_iret:
@@ -980,6 +984,7 @@ END(common_interrupt)
         * modify the stack to make it look like we just entered
         * the #GP handler from user space, similar to bad_iret.
         */
         * modify the stack to make it look like we just entered
         * the #GP handler from user space, similar to bad_iret.
         */
+#ifdef CONFIG_X86_ESPFIX64
        ALIGN
 __do_double_fault:
        XCPT_FRAME 1 RDI+8
        ALIGN
 __do_double_fault:
        XCPT_FRAME 1 RDI+8
@@ -1005,6 +1010,9 @@ __do_double_fault:
        retq
        CFI_ENDPROC
 END(__do_double_fault)
        retq
        CFI_ENDPROC
 END(__do_double_fault)
+#else
+# define __do_double_fault do_double_fault
+#endif
 
 /*
  * End of kprobes section
 
 /*
  * End of kprobes section
index ea69726..0a8e65e 100644 (file)
@@ -230,6 +230,11 @@ static int write_ldt(void __user *ptr, unsigned long bytecount, int oldmode)
                }
        }
 
                }
        }
 
+       if (!IS_ENABLED(CONFIG_X86_16BIT) && !ldt_info.seg_32bit) {
+               error = -EINVAL;
+               goto out_unlock;
+       }
+
        fill_ldt(&ldt, &ldt_info);
        if (oldmode)
                ldt.avl = 0;
        fill_ldt(&ldt, &ldt_info);
        if (oldmode)
                ldt.avl = 0;