aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2015-06-05 13:03:48 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2015-06-05 13:03:48 -0400
commit51d0f0cb3ae0da0ce5bb0bff8d1305345e6ec7ec (patch)
tree9f1be28982bca81b19887f47cd85dc7898c6f831
parenta0e9c6efa585897f00eb22e67887e5a25482b1b8 (diff)
parent425be5679fd292a3c36cb1fe423086708a99f11a (diff)
Merge branch 'x86-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 fixes from Ingo Molnar: "Misc fixes: - early_idt_handlers[] fix that fixes the build with bleeding edge tooling - build warning fix on GCC 5.1 - vm86 fix plus self-test to make it harder to break it again" * 'x86-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86/asm/irq: Stop relying on magic JMP behavior for early_idt_handlers x86/asm/entry/32, selftests: Add a selftest for kernel entries from VM86 mode x86/boot: Add CONFIG_PARAVIRT_SPINLOCKS quirk to arch/x86/boot/compressed/misc.h x86/asm/entry/32: Really make user_mode() work correctly for VM86 mode
-rw-r--r--arch/x86/boot/compressed/misc.h11
-rw-r--r--arch/x86/include/asm/ptrace.h2
-rw-r--r--arch/x86/include/asm/segment.h14
-rw-r--r--arch/x86/kernel/head64.c2
-rw-r--r--arch/x86/kernel/head_32.S33
-rw-r--r--arch/x86/kernel/head_64.S20
-rw-r--r--tools/testing/selftests/x86/Makefile6
-rw-r--r--tools/testing/selftests/x86/entry_from_vm86.c114
8 files changed, 166 insertions, 36 deletions
diff --git a/arch/x86/boot/compressed/misc.h b/arch/x86/boot/compressed/misc.h
index 89dd0d78013a..805d25ca5f1d 100644
--- a/arch/x86/boot/compressed/misc.h
+++ b/arch/x86/boot/compressed/misc.h
@@ -2,15 +2,14 @@
2#define BOOT_COMPRESSED_MISC_H 2#define BOOT_COMPRESSED_MISC_H
3 3
4/* 4/*
5 * we have to be careful, because no indirections are allowed here, and 5 * Special hack: we have to be careful, because no indirections are allowed here,
6 * paravirt_ops is a kind of one. As it will only run in baremetal anyway, 6 * and paravirt_ops is a kind of one. As it will only run in baremetal anyway,
7 * we just keep it from happening 7 * we just keep it from happening. (This list needs to be extended when new
8 * paravirt and debugging variants are added.)
8 */ 9 */
9#undef CONFIG_PARAVIRT 10#undef CONFIG_PARAVIRT
11#undef CONFIG_PARAVIRT_SPINLOCKS
10#undef CONFIG_KASAN 12#undef CONFIG_KASAN
11#ifdef CONFIG_X86_32
12#define _ASM_X86_DESC_H 1
13#endif
14 13
15#include <linux/linkage.h> 14#include <linux/linkage.h>
16#include <linux/screen_info.h> 15#include <linux/screen_info.h>
diff --git a/arch/x86/include/asm/ptrace.h b/arch/x86/include/asm/ptrace.h
index 19507ffa5d28..5fabf1362942 100644
--- a/arch/x86/include/asm/ptrace.h
+++ b/arch/x86/include/asm/ptrace.h
@@ -107,7 +107,7 @@ static inline unsigned long regs_return_value(struct pt_regs *regs)
107static inline int user_mode(struct pt_regs *regs) 107static inline int user_mode(struct pt_regs *regs)
108{ 108{
109#ifdef CONFIG_X86_32 109#ifdef CONFIG_X86_32
110 return (regs->cs & SEGMENT_RPL_MASK) == USER_RPL; 110 return ((regs->cs & SEGMENT_RPL_MASK) | (regs->flags & X86_VM_MASK)) >= USER_RPL;
111#else 111#else
112 return !!(regs->cs & 3); 112 return !!(regs->cs & 3);
113#endif 113#endif
diff --git a/arch/x86/include/asm/segment.h b/arch/x86/include/asm/segment.h
index 5a9856eb12ba..7d5a1929d76b 100644
--- a/arch/x86/include/asm/segment.h
+++ b/arch/x86/include/asm/segment.h
@@ -231,11 +231,21 @@
231#define TLS_SIZE (GDT_ENTRY_TLS_ENTRIES* 8) 231#define TLS_SIZE (GDT_ENTRY_TLS_ENTRIES* 8)
232 232
233#ifdef __KERNEL__ 233#ifdef __KERNEL__
234
235/*
236 * early_idt_handler_array is an array of entry points referenced in the
237 * early IDT. For simplicity, it's a real array with one entry point
238 * every nine bytes. That leaves room for an optional 'push $0' if the
239 * vector has no error code (two bytes), a 'push $vector_number' (two
240 * bytes), and a jump to the common entry code (up to five bytes).
241 */
242#define EARLY_IDT_HANDLER_SIZE 9
243
234#ifndef __ASSEMBLY__ 244#ifndef __ASSEMBLY__
235 245
236extern const char early_idt_handlers[NUM_EXCEPTION_VECTORS][2+2+5]; 246extern const char early_idt_handler_array[NUM_EXCEPTION_VECTORS][EARLY_IDT_HANDLER_SIZE];
237#ifdef CONFIG_TRACING 247#ifdef CONFIG_TRACING
238# define trace_early_idt_handlers early_idt_handlers 248# define trace_early_idt_handler_array early_idt_handler_array
239#endif 249#endif
240 250
241/* 251/*
diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c
index 2b55ee6db053..5a4668136e98 100644
--- a/arch/x86/kernel/head64.c
+++ b/arch/x86/kernel/head64.c
@@ -167,7 +167,7 @@ asmlinkage __visible void __init x86_64_start_kernel(char * real_mode_data)
167 clear_bss(); 167 clear_bss();
168 168
169 for (i = 0; i < NUM_EXCEPTION_VECTORS; i++) 169 for (i = 0; i < NUM_EXCEPTION_VECTORS; i++)
170 set_intr_gate(i, early_idt_handlers[i]); 170 set_intr_gate(i, early_idt_handler_array[i]);
171 load_idt((const struct desc_ptr *)&idt_descr); 171 load_idt((const struct desc_ptr *)&idt_descr);
172 172
173 copy_bootdata(__va(real_mode_data)); 173 copy_bootdata(__va(real_mode_data));
diff --git a/arch/x86/kernel/head_32.S b/arch/x86/kernel/head_32.S
index d031bad9e07e..53eeb226657c 100644
--- a/arch/x86/kernel/head_32.S
+++ b/arch/x86/kernel/head_32.S
@@ -478,21 +478,22 @@ is486:
478__INIT 478__INIT
479setup_once: 479setup_once:
480 /* 480 /*
481 * Set up a idt with 256 entries pointing to ignore_int, 481 * Set up a idt with 256 interrupt gates that push zero if there
482 * interrupt gates. It doesn't actually load idt - that needs 482 * is no error code and then jump to early_idt_handler_common.
483 * to be done on each CPU. Interrupts are enabled elsewhere, 483 * It doesn't actually load the idt - that needs to be done on
484 * when we can be relatively sure everything is ok. 484 * each CPU. Interrupts are enabled elsewhere, when we can be
485 * relatively sure everything is ok.
485 */ 486 */
486 487
487 movl $idt_table,%edi 488 movl $idt_table,%edi
488 movl $early_idt_handlers,%eax 489 movl $early_idt_handler_array,%eax
489 movl $NUM_EXCEPTION_VECTORS,%ecx 490 movl $NUM_EXCEPTION_VECTORS,%ecx
4901: 4911:
491 movl %eax,(%edi) 492 movl %eax,(%edi)
492 movl %eax,4(%edi) 493 movl %eax,4(%edi)
493 /* interrupt gate, dpl=0, present */ 494 /* interrupt gate, dpl=0, present */
494 movl $(0x8E000000 + __KERNEL_CS),2(%edi) 495 movl $(0x8E000000 + __KERNEL_CS),2(%edi)
495 addl $9,%eax 496 addl $EARLY_IDT_HANDLER_SIZE,%eax
496 addl $8,%edi 497 addl $8,%edi
497 loop 1b 498 loop 1b
498 499
@@ -524,26 +525,28 @@ setup_once:
524 andl $0,setup_once_ref /* Once is enough, thanks */ 525 andl $0,setup_once_ref /* Once is enough, thanks */
525 ret 526 ret
526 527
527ENTRY(early_idt_handlers) 528ENTRY(early_idt_handler_array)
528 # 36(%esp) %eflags 529 # 36(%esp) %eflags
529 # 32(%esp) %cs 530 # 32(%esp) %cs
530 # 28(%esp) %eip 531 # 28(%esp) %eip
531 # 24(%rsp) error code 532 # 24(%rsp) error code
532 i = 0 533 i = 0
533 .rept NUM_EXCEPTION_VECTORS 534 .rept NUM_EXCEPTION_VECTORS
534 .if (EXCEPTION_ERRCODE_MASK >> i) & 1 535 .ifeq (EXCEPTION_ERRCODE_MASK >> i) & 1
535 ASM_NOP2
536 .else
537 pushl $0 # Dummy error code, to make stack frame uniform 536 pushl $0 # Dummy error code, to make stack frame uniform
538 .endif 537 .endif
539 pushl $i # 20(%esp) Vector number 538 pushl $i # 20(%esp) Vector number
540 jmp early_idt_handler 539 jmp early_idt_handler_common
541 i = i + 1 540 i = i + 1
541 .fill early_idt_handler_array + i*EARLY_IDT_HANDLER_SIZE - ., 1, 0xcc
542 .endr 542 .endr
543ENDPROC(early_idt_handlers) 543ENDPROC(early_idt_handler_array)
544 544
545 /* This is global to keep gas from relaxing the jumps */ 545early_idt_handler_common:
546ENTRY(early_idt_handler) 546 /*
547 * The stack is the hardware frame, an error code or zero, and the
548 * vector number.
549 */
547 cld 550 cld
548 551
549 cmpl $2,(%esp) # X86_TRAP_NMI 552 cmpl $2,(%esp) # X86_TRAP_NMI
@@ -603,7 +606,7 @@ ex_entry:
603is_nmi: 606is_nmi:
604 addl $8,%esp /* drop vector number and error code */ 607 addl $8,%esp /* drop vector number and error code */
605 iret 608 iret
606ENDPROC(early_idt_handler) 609ENDPROC(early_idt_handler_common)
607 610
608/* This is the default interrupt "handler" :-) */ 611/* This is the default interrupt "handler" :-) */
609 ALIGN 612 ALIGN
diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S
index ae6588b301c2..df7e78057ae0 100644
--- a/arch/x86/kernel/head_64.S
+++ b/arch/x86/kernel/head_64.S
@@ -321,26 +321,28 @@ bad_address:
321 jmp bad_address 321 jmp bad_address
322 322
323 __INIT 323 __INIT
324 .globl early_idt_handlers 324ENTRY(early_idt_handler_array)
325early_idt_handlers:
326 # 104(%rsp) %rflags 325 # 104(%rsp) %rflags
327 # 96(%rsp) %cs 326 # 96(%rsp) %cs
328 # 88(%rsp) %rip 327 # 88(%rsp) %rip
329 # 80(%rsp) error code 328 # 80(%rsp) error code
330 i = 0 329 i = 0
331 .rept NUM_EXCEPTION_VECTORS 330 .rept NUM_EXCEPTION_VECTORS
332 .if (EXCEPTION_ERRCODE_MASK >> i) & 1 331 .ifeq (EXCEPTION_ERRCODE_MASK >> i) & 1
333 ASM_NOP2
334 .else
335 pushq $0 # Dummy error code, to make stack frame uniform 332 pushq $0 # Dummy error code, to make stack frame uniform
336 .endif 333 .endif
337 pushq $i # 72(%rsp) Vector number 334 pushq $i # 72(%rsp) Vector number
338 jmp early_idt_handler 335 jmp early_idt_handler_common
339 i = i + 1 336 i = i + 1
337 .fill early_idt_handler_array + i*EARLY_IDT_HANDLER_SIZE - ., 1, 0xcc
340 .endr 338 .endr
339ENDPROC(early_idt_handler_array)
341 340
342/* This is global to keep gas from relaxing the jumps */ 341early_idt_handler_common:
343ENTRY(early_idt_handler) 342 /*
343 * The stack is the hardware frame, an error code or zero, and the
344 * vector number.
345 */
344 cld 346 cld
345 347
346 cmpl $2,(%rsp) # X86_TRAP_NMI 348 cmpl $2,(%rsp) # X86_TRAP_NMI
@@ -412,7 +414,7 @@ ENTRY(early_idt_handler)
412is_nmi: 414is_nmi:
413 addq $16,%rsp # drop vector number and error code 415 addq $16,%rsp # drop vector number and error code
414 INTERRUPT_RETURN 416 INTERRUPT_RETURN
415ENDPROC(early_idt_handler) 417ENDPROC(early_idt_handler_common)
416 418
417 __INITDATA 419 __INITDATA
418 420
diff --git a/tools/testing/selftests/x86/Makefile b/tools/testing/selftests/x86/Makefile
index 5bdb781163d1..9b0d8baf2934 100644
--- a/tools/testing/selftests/x86/Makefile
+++ b/tools/testing/selftests/x86/Makefile
@@ -5,8 +5,10 @@ include ../lib.mk
5.PHONY: all all_32 all_64 warn_32bit_failure clean 5.PHONY: all all_32 all_64 warn_32bit_failure clean
6 6
7TARGETS_C_BOTHBITS := sigreturn single_step_syscall 7TARGETS_C_BOTHBITS := sigreturn single_step_syscall
8TARGETS_C_32BIT_ONLY := entry_from_vm86
8 9
9BINARIES_32 := $(TARGETS_C_BOTHBITS:%=%_32) 10TARGETS_C_32BIT_ALL := $(TARGETS_C_BOTHBITS) $(TARGETS_C_32BIT_ONLY)
11BINARIES_32 := $(TARGETS_C_32BIT_ALL:%=%_32)
10BINARIES_64 := $(TARGETS_C_BOTHBITS:%=%_64) 12BINARIES_64 := $(TARGETS_C_BOTHBITS:%=%_64)
11 13
12CFLAGS := -O2 -g -std=gnu99 -pthread -Wall 14CFLAGS := -O2 -g -std=gnu99 -pthread -Wall
@@ -32,7 +34,7 @@ all_64: $(BINARIES_64)
32clean: 34clean:
33 $(RM) $(BINARIES_32) $(BINARIES_64) 35 $(RM) $(BINARIES_32) $(BINARIES_64)
34 36
35$(TARGETS_C_BOTHBITS:%=%_32): %_32: %.c 37$(TARGETS_C_32BIT_ALL:%=%_32): %_32: %.c
36 $(CC) -m32 -o $@ $(CFLAGS) $(EXTRA_CFLAGS) $^ -lrt -ldl 38 $(CC) -m32 -o $@ $(CFLAGS) $(EXTRA_CFLAGS) $^ -lrt -ldl
37 39
38$(TARGETS_C_BOTHBITS:%=%_64): %_64: %.c 40$(TARGETS_C_BOTHBITS:%=%_64): %_64: %.c
diff --git a/tools/testing/selftests/x86/entry_from_vm86.c b/tools/testing/selftests/x86/entry_from_vm86.c
new file mode 100644
index 000000000000..5c38a187677b
--- /dev/null
+++ b/tools/testing/selftests/x86/entry_from_vm86.c
@@ -0,0 +1,114 @@
1/*
2 * entry_from_vm86.c - tests kernel entries from vm86 mode
3 * Copyright (c) 2014-2015 Andrew Lutomirski
4 *
5 * This exercises a few paths that need to special-case vm86 mode.
6 *
7 * GPL v2.
8 */
9
10#define _GNU_SOURCE
11
12#include <assert.h>
13#include <stdlib.h>
14#include <sys/syscall.h>
15#include <sys/signal.h>
16#include <sys/ucontext.h>
17#include <unistd.h>
18#include <stdio.h>
19#include <string.h>
20#include <inttypes.h>
21#include <sys/mman.h>
22#include <err.h>
23#include <stddef.h>
24#include <stdbool.h>
25#include <errno.h>
26#include <sys/vm86.h>
27
28static unsigned long load_addr = 0x10000;
29static int nerrs = 0;
30
31asm (
32 ".pushsection .rodata\n\t"
33 ".type vmcode_bound, @object\n\t"
34 "vmcode:\n\t"
35 "vmcode_bound:\n\t"
36 ".code16\n\t"
37 "bound %ax, (2048)\n\t"
38 "int3\n\t"
39 "vmcode_sysenter:\n\t"
40 "sysenter\n\t"
41 ".size vmcode, . - vmcode\n\t"
42 "end_vmcode:\n\t"
43 ".code32\n\t"
44 ".popsection"
45 );
46
47extern unsigned char vmcode[], end_vmcode[];
48extern unsigned char vmcode_bound[], vmcode_sysenter[];
49
50static void do_test(struct vm86plus_struct *v86, unsigned long eip,
51 const char *text)
52{
53 long ret;
54
55 printf("[RUN]\t%s from vm86 mode\n", text);
56 v86->regs.eip = eip;
57 ret = vm86(VM86_ENTER, v86);
58
59 if (ret == -1 && errno == ENOSYS) {
60 printf("[SKIP]\tvm86 not supported\n");
61 return;
62 }
63
64 if (VM86_TYPE(ret) == VM86_INTx) {
65 char trapname[32];
66 int trapno = VM86_ARG(ret);
67 if (trapno == 13)
68 strcpy(trapname, "GP");
69 else if (trapno == 5)
70 strcpy(trapname, "BR");
71 else if (trapno == 14)
72 strcpy(trapname, "PF");
73 else
74 sprintf(trapname, "%d", trapno);
75
76 printf("[OK]\tExited vm86 mode due to #%s\n", trapname);
77 } else if (VM86_TYPE(ret) == VM86_UNKNOWN) {
78 printf("[OK]\tExited vm86 mode due to unhandled GP fault\n");
79 } else {
80 printf("[OK]\tExited vm86 mode due to type %ld, arg %ld\n",
81 VM86_TYPE(ret), VM86_ARG(ret));
82 }
83}
84
85int main(void)
86{
87 struct vm86plus_struct v86;
88 unsigned char *addr = mmap((void *)load_addr, 4096,
89 PROT_READ | PROT_WRITE | PROT_EXEC,
90 MAP_ANONYMOUS | MAP_PRIVATE, -1,0);
91 if (addr != (unsigned char *)load_addr)
92 err(1, "mmap");
93
94 memcpy(addr, vmcode, end_vmcode - vmcode);
95 addr[2048] = 2;
96 addr[2050] = 3;
97
98 memset(&v86, 0, sizeof(v86));
99
100 v86.regs.cs = load_addr / 16;
101 v86.regs.ss = load_addr / 16;
102 v86.regs.ds = load_addr / 16;
103 v86.regs.es = load_addr / 16;
104
105 assert((v86.regs.cs & 3) == 0); /* Looks like RPL = 0 */
106
107 /* #BR -- should deliver SIG??? */
108 do_test(&v86, vmcode_bound - vmcode, "#BR");
109
110 /* SYSENTER -- should cause #GP or #UD depending on CPU */
111 do_test(&v86, vmcode_sysenter - vmcode, "SYSENTER");
112
113 return (nerrs == 0 ? 0 : 1);
114}