Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

x86/entry/32: Change INT80 to be an interrupt gate

We want all of the syscall entries to run with interrupts off so that
we can efficiently run context tracking before enabling interrupts.

This will regress int $0x80 performance on 32-bit kernels by a
couple of cycles. This shouldn't matter much -- int $0x80 is not a
fast path.

This effectively reverts:

657c1eea0019 ("x86/entry/32: Fix entry_INT80_32() to expect interrupts to be on")

... and fixes the same issue differently.

Signed-off-by: Andy Lutomirski <luto@kernel.org>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: Denys Vlasenko <dvlasenk@redhat.com>
Cc: Frédéric Weisbecker <fweisbec@gmail.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Rik van Riel <riel@redhat.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/59b4f90c9ebfccd8c937305dbbbca680bc74b905.1457558566.git.luto@kernel.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>

authored by

Andy Lutomirski and committed by
Ingo Molnar
a798f091 fda57b22

+9 -18
+3 -12
arch/x86/entry/common.c
··· 371 371 * in workloads that use it, and it's usually called from 372 372 * do_fast_syscall_32, so forcibly inline it to improve performance. 373 373 */ 374 - #ifdef CONFIG_X86_32 375 - /* 32-bit kernels use a trap gate for INT80, and the asm code calls here. */ 376 - __visible 377 - #else 378 - /* 64-bit kernels use do_syscall_32_irqs_off() instead. */ 379 - static 380 - #endif 381 - __always_inline void do_syscall_32_irqs_on(struct pt_regs *regs) 374 + static __always_inline void do_syscall_32_irqs_on(struct pt_regs *regs) 382 375 { 383 376 struct thread_info *ti = pt_regs_to_thread_info(regs); 384 377 unsigned int nr = (unsigned int)regs->orig_ax; ··· 406 413 syscall_return_slowpath(regs); 407 414 } 408 415 409 - #ifdef CONFIG_X86_64 410 - /* Handles INT80 on 64-bit kernels */ 411 - __visible void do_syscall_32_irqs_off(struct pt_regs *regs) 416 + /* Handles int $0x80 */ 417 + __visible void do_int80_syscall_32(struct pt_regs *regs) 412 418 { 413 419 local_irq_enable(); 414 420 do_syscall_32_irqs_on(regs); 415 421 } 416 - #endif 417 422 418 423 /* Returns 0 to return using IRET or 1 to return using SYSEXIT/SYSRETL. */ 419 424 __visible long do_fast_syscall_32(struct pt_regs *regs)
+4 -4
arch/x86/entry/entry_32.S
··· 463 463 SAVE_ALL pt_regs_ax=$-ENOSYS /* save rest */ 464 464 465 465 /* 466 - * User mode is traced as though IRQs are on. Unlike the 64-bit 467 - * case, INT80 is a trap gate on 32-bit kernels, so interrupts 468 - * are already on (unless user code is messing around with iopl). 466 + * User mode is traced as though IRQs are on, and the interrupt gate 467 + * turned them off. 469 468 */ 469 + TRACE_IRQS_OFF 470 470 471 471 movl %esp, %eax 472 - call do_syscall_32_irqs_on 472 + call do_int80_syscall_32 473 473 .Lsyscall_32_done: 474 474 475 475 restore_all:
+1 -1
arch/x86/entry/entry_64_compat.S
··· 336 336 TRACE_IRQS_OFF 337 337 338 338 movq %rsp, %rdi 339 - call do_syscall_32_irqs_off 339 + call do_int80_syscall_32 340 340 .Lsyscall_32_done: 341 341 342 342 /* Go back to user mode. */
+1 -1
arch/x86/kernel/traps.c
··· 912 912 #endif 913 913 914 914 #ifdef CONFIG_X86_32 915 - set_system_trap_gate(IA32_SYSCALL_VECTOR, entry_INT80_32); 915 + set_system_intr_gate(IA32_SYSCALL_VECTOR, entry_INT80_32); 916 916 set_bit(IA32_SYSCALL_VECTOR, used_vectors); 917 917 #endif 918 918