aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/boot
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2015-02-21 13:41:29 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2015-02-21 13:41:29 -0500
commit5fbe4c224ce3e2e62bd487158dfd1e89f9ae3e11 (patch)
treeaee3c146fb7dd3dd10cb71f44affa9c680481f08 /arch/x86/boot
parente2defd02717ebc54ae2f4862271a3093665b426a (diff)
parent570e1aa84c376ff39809442f09c7606ddf62cfd1 (diff)
Merge branch 'x86-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull misc x86 fixes from Ingo Molnar: "This contains: - EFI fixes - a boot printout fix - ASLR/kASLR fixes - intel microcode driver fixes - other misc fixes Most of the linecount comes from an EFI revert" * 'x86-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86/mm/ASLR: Avoid PAGE_SIZE redefinition for UML subarch x86/microcode/intel: Handle truncated microcode images more robustly x86/microcode/intel: Guard against stack overflow in the loader x86, mm/ASLR: Fix stack randomization on 64-bit systems x86/mm/init: Fix incorrect page size in init_memory_mapping() printks x86/mm/ASLR: Propagate base load address calculation Documentation/x86: Fix path in zero-page.txt x86/apic: Fix the devicetree build in certain configs Revert "efi/libstub: Call get_memory_map() to obtain map and desc sizes" x86/efi: Avoid triple faults during EFI mixed mode calls
Diffstat (limited to 'arch/x86/boot')
-rw-r--r--arch/x86/boot/compressed/Makefile1
-rw-r--r--arch/x86/boot/compressed/aslr.c34
-rw-r--r--arch/x86/boot/compressed/efi_stub_64.S25
-rw-r--r--arch/x86/boot/compressed/efi_thunk_64.S196
-rw-r--r--arch/x86/boot/compressed/misc.c3
-rw-r--r--arch/x86/boot/compressed/misc.h6
6 files changed, 236 insertions, 29 deletions
diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile
index 843feb3eb20b..0a291cdfaf77 100644
--- a/arch/x86/boot/compressed/Makefile
+++ b/arch/x86/boot/compressed/Makefile
@@ -51,6 +51,7 @@ $(obj)/eboot.o: KBUILD_CFLAGS += -fshort-wchar -mno-red-zone
51 51
52vmlinux-objs-$(CONFIG_EFI_STUB) += $(obj)/eboot.o $(obj)/efi_stub_$(BITS).o \ 52vmlinux-objs-$(CONFIG_EFI_STUB) += $(obj)/eboot.o $(obj)/efi_stub_$(BITS).o \
53 $(objtree)/drivers/firmware/efi/libstub/lib.a 53 $(objtree)/drivers/firmware/efi/libstub/lib.a
54vmlinux-objs-$(CONFIG_EFI_MIXED) += $(obj)/efi_thunk_$(BITS).o
54 55
55$(obj)/vmlinux: $(vmlinux-objs-y) FORCE 56$(obj)/vmlinux: $(vmlinux-objs-y) FORCE
56 $(call if_changed,ld) 57 $(call if_changed,ld)
diff --git a/arch/x86/boot/compressed/aslr.c b/arch/x86/boot/compressed/aslr.c
index bb1376381985..7083c16cccba 100644
--- a/arch/x86/boot/compressed/aslr.c
+++ b/arch/x86/boot/compressed/aslr.c
@@ -14,6 +14,13 @@
14static const char build_str[] = UTS_RELEASE " (" LINUX_COMPILE_BY "@" 14static const char build_str[] = UTS_RELEASE " (" LINUX_COMPILE_BY "@"
15 LINUX_COMPILE_HOST ") (" LINUX_COMPILER ") " UTS_VERSION; 15 LINUX_COMPILE_HOST ") (" LINUX_COMPILER ") " UTS_VERSION;
16 16
17struct kaslr_setup_data {
18 __u64 next;
19 __u32 type;
20 __u32 len;
21 __u8 data[1];
22} kaslr_setup_data;
23
17#define I8254_PORT_CONTROL 0x43 24#define I8254_PORT_CONTROL 0x43
18#define I8254_PORT_COUNTER0 0x40 25#define I8254_PORT_COUNTER0 0x40
19#define I8254_CMD_READBACK 0xC0 26#define I8254_CMD_READBACK 0xC0
@@ -295,7 +302,29 @@ static unsigned long find_random_addr(unsigned long minimum,
295 return slots_fetch_random(); 302 return slots_fetch_random();
296} 303}
297 304
298unsigned char *choose_kernel_location(unsigned char *input, 305static void add_kaslr_setup_data(struct boot_params *params, __u8 enabled)
306{
307 struct setup_data *data;
308
309 kaslr_setup_data.type = SETUP_KASLR;
310 kaslr_setup_data.len = 1;
311 kaslr_setup_data.next = 0;
312 kaslr_setup_data.data[0] = enabled;
313
314 data = (struct setup_data *)(unsigned long)params->hdr.setup_data;
315
316 while (data && data->next)
317 data = (struct setup_data *)(unsigned long)data->next;
318
319 if (data)
320 data->next = (unsigned long)&kaslr_setup_data;
321 else
322 params->hdr.setup_data = (unsigned long)&kaslr_setup_data;
323
324}
325
326unsigned char *choose_kernel_location(struct boot_params *params,
327 unsigned char *input,
299 unsigned long input_size, 328 unsigned long input_size,
300 unsigned char *output, 329 unsigned char *output,
301 unsigned long output_size) 330 unsigned long output_size)
@@ -306,14 +335,17 @@ unsigned char *choose_kernel_location(unsigned char *input,
306#ifdef CONFIG_HIBERNATION 335#ifdef CONFIG_HIBERNATION
307 if (!cmdline_find_option_bool("kaslr")) { 336 if (!cmdline_find_option_bool("kaslr")) {
308 debug_putstr("KASLR disabled by default...\n"); 337 debug_putstr("KASLR disabled by default...\n");
338 add_kaslr_setup_data(params, 0);
309 goto out; 339 goto out;
310 } 340 }
311#else 341#else
312 if (cmdline_find_option_bool("nokaslr")) { 342 if (cmdline_find_option_bool("nokaslr")) {
313 debug_putstr("KASLR disabled by cmdline...\n"); 343 debug_putstr("KASLR disabled by cmdline...\n");
344 add_kaslr_setup_data(params, 0);
314 goto out; 345 goto out;
315 } 346 }
316#endif 347#endif
348 add_kaslr_setup_data(params, 1);
317 349
318 /* Record the various known unsafe memory ranges. */ 350 /* Record the various known unsafe memory ranges. */
319 mem_avoid_init((unsigned long)input, input_size, 351 mem_avoid_init((unsigned long)input, input_size,
diff --git a/arch/x86/boot/compressed/efi_stub_64.S b/arch/x86/boot/compressed/efi_stub_64.S
index 7ff3632806b1..99494dff2113 100644
--- a/arch/x86/boot/compressed/efi_stub_64.S
+++ b/arch/x86/boot/compressed/efi_stub_64.S
@@ -3,28 +3,3 @@
3#include <asm/processor-flags.h> 3#include <asm/processor-flags.h>
4 4
5#include "../../platform/efi/efi_stub_64.S" 5#include "../../platform/efi/efi_stub_64.S"
6
7#ifdef CONFIG_EFI_MIXED
8 .code64
9 .text
10ENTRY(efi64_thunk)
11 push %rbp
12 push %rbx
13
14 subq $16, %rsp
15 leaq efi_exit32(%rip), %rax
16 movl %eax, 8(%rsp)
17 leaq efi_gdt64(%rip), %rax
18 movl %eax, 4(%rsp)
19 movl %eax, 2(%rax) /* Fixup the gdt base address */
20 leaq efi32_boot_gdt(%rip), %rax
21 movl %eax, (%rsp)
22
23 call __efi64_thunk
24
25 addq $16, %rsp
26 pop %rbx
27 pop %rbp
28 ret
29ENDPROC(efi64_thunk)
30#endif /* CONFIG_EFI_MIXED */
diff --git a/arch/x86/boot/compressed/efi_thunk_64.S b/arch/x86/boot/compressed/efi_thunk_64.S
new file mode 100644
index 000000000000..630384a4c14a
--- /dev/null
+++ b/arch/x86/boot/compressed/efi_thunk_64.S
@@ -0,0 +1,196 @@
1/*
2 * Copyright (C) 2014, 2015 Intel Corporation; author Matt Fleming
3 *
4 * Early support for invoking 32-bit EFI services from a 64-bit kernel.
5 *
6 * Because this thunking occurs before ExitBootServices() we have to
7 * restore the firmware's 32-bit GDT before we make EFI serivce calls,
8 * since the firmware's 32-bit IDT is still currently installed and it
9 * needs to be able to service interrupts.
10 *
11 * On the plus side, we don't have to worry about mangling 64-bit
12 * addresses into 32-bits because we're executing with an identify
13 * mapped pagetable and haven't transitioned to 64-bit virtual addresses
14 * yet.
15 */
16
17#include <linux/linkage.h>
18#include <asm/msr.h>
19#include <asm/page_types.h>
20#include <asm/processor-flags.h>
21#include <asm/segment.h>
22
23 .code64
24 .text
25ENTRY(efi64_thunk)
26 push %rbp
27 push %rbx
28
29 subq $8, %rsp
30 leaq efi_exit32(%rip), %rax
31 movl %eax, 4(%rsp)
32 leaq efi_gdt64(%rip), %rax
33 movl %eax, (%rsp)
34 movl %eax, 2(%rax) /* Fixup the gdt base address */
35
36 movl %ds, %eax
37 push %rax
38 movl %es, %eax
39 push %rax
40 movl %ss, %eax
41 push %rax
42
43 /*
44 * Convert x86-64 ABI params to i386 ABI
45 */
46 subq $32, %rsp
47 movl %esi, 0x0(%rsp)
48 movl %edx, 0x4(%rsp)
49 movl %ecx, 0x8(%rsp)
50 movq %r8, %rsi
51 movl %esi, 0xc(%rsp)
52 movq %r9, %rsi
53 movl %esi, 0x10(%rsp)
54
55 sgdt save_gdt(%rip)
56
57 leaq 1f(%rip), %rbx
58 movq %rbx, func_rt_ptr(%rip)
59
60 /*
61 * Switch to gdt with 32-bit segments. This is the firmware GDT
62 * that was installed when the kernel started executing. This
63 * pointer was saved at the EFI stub entry point in head_64.S.
64 */
65 leaq efi32_boot_gdt(%rip), %rax
66 lgdt (%rax)
67
68 pushq $__KERNEL_CS
69 leaq efi_enter32(%rip), %rax
70 pushq %rax
71 lretq
72
731: addq $32, %rsp
74
75 lgdt save_gdt(%rip)
76
77 pop %rbx
78 movl %ebx, %ss
79 pop %rbx
80 movl %ebx, %es
81 pop %rbx
82 movl %ebx, %ds
83
84 /*
85 * Convert 32-bit status code into 64-bit.
86 */
87 test %rax, %rax
88 jz 1f
89 movl %eax, %ecx
90 andl $0x0fffffff, %ecx
91 andl $0xf0000000, %eax
92 shl $32, %rax
93 or %rcx, %rax
941:
95 addq $8, %rsp
96 pop %rbx
97 pop %rbp
98 ret
99ENDPROC(efi64_thunk)
100
101ENTRY(efi_exit32)
102 movq func_rt_ptr(%rip), %rax
103 push %rax
104 mov %rdi, %rax
105 ret
106ENDPROC(efi_exit32)
107
108 .code32
109/*
110 * EFI service pointer must be in %edi.
111 *
112 * The stack should represent the 32-bit calling convention.
113 */
114ENTRY(efi_enter32)
115 movl $__KERNEL_DS, %eax
116 movl %eax, %ds
117 movl %eax, %es
118 movl %eax, %ss
119
120 /* Reload pgtables */
121 movl %cr3, %eax
122 movl %eax, %cr3
123
124 /* Disable paging */
125 movl %cr0, %eax
126 btrl $X86_CR0_PG_BIT, %eax
127 movl %eax, %cr0
128
129 /* Disable long mode via EFER */
130 movl $MSR_EFER, %ecx
131 rdmsr
132 btrl $_EFER_LME, %eax
133 wrmsr
134
135 call *%edi
136
137 /* We must preserve return value */
138 movl %eax, %edi
139
140 /*
141 * Some firmware will return with interrupts enabled. Be sure to
142 * disable them before we switch GDTs.
143 */
144 cli
145
146 movl 56(%esp), %eax
147 movl %eax, 2(%eax)
148 lgdtl (%eax)
149
150 movl %cr4, %eax
151 btsl $(X86_CR4_PAE_BIT), %eax
152 movl %eax, %cr4
153
154 movl %cr3, %eax
155 movl %eax, %cr3
156
157 movl $MSR_EFER, %ecx
158 rdmsr
159 btsl $_EFER_LME, %eax
160 wrmsr
161
162 xorl %eax, %eax
163 lldt %ax
164
165 movl 60(%esp), %eax
166 pushl $__KERNEL_CS
167 pushl %eax
168
169 /* Enable paging */
170 movl %cr0, %eax
171 btsl $X86_CR0_PG_BIT, %eax
172 movl %eax, %cr0
173 lret
174ENDPROC(efi_enter32)
175
176 .data
177 .balign 8
178 .global efi32_boot_gdt
179efi32_boot_gdt: .word 0
180 .quad 0
181
182save_gdt: .word 0
183 .quad 0
184func_rt_ptr: .quad 0
185
186 .global efi_gdt64
187efi_gdt64:
188 .word efi_gdt64_end - efi_gdt64
189 .long 0 /* Filled out by user */
190 .word 0
191 .quad 0x0000000000000000 /* NULL descriptor */
192 .quad 0x00af9a000000ffff /* __KERNEL_CS */
193 .quad 0x00cf92000000ffff /* __KERNEL_DS */
194 .quad 0x0080890000000000 /* TS descriptor */
195 .quad 0x0000000000000000 /* TS continued */
196efi_gdt64_end:
diff --git a/arch/x86/boot/compressed/misc.c b/arch/x86/boot/compressed/misc.c
index a950864a64da..5903089c818f 100644
--- a/arch/x86/boot/compressed/misc.c
+++ b/arch/x86/boot/compressed/misc.c
@@ -401,7 +401,8 @@ asmlinkage __visible void *decompress_kernel(void *rmode, memptr heap,
401 * the entire decompressed kernel plus relocation table, or the 401 * the entire decompressed kernel plus relocation table, or the
402 * entire decompressed kernel plus .bss and .brk sections. 402 * entire decompressed kernel plus .bss and .brk sections.
403 */ 403 */
404 output = choose_kernel_location(input_data, input_len, output, 404 output = choose_kernel_location(real_mode, input_data, input_len,
405 output,
405 output_len > run_size ? output_len 406 output_len > run_size ? output_len
406 : run_size); 407 : run_size);
407 408
diff --git a/arch/x86/boot/compressed/misc.h b/arch/x86/boot/compressed/misc.h
index 04477d68403f..ee3576b2666b 100644
--- a/arch/x86/boot/compressed/misc.h
+++ b/arch/x86/boot/compressed/misc.h
@@ -57,7 +57,8 @@ int cmdline_find_option_bool(const char *option);
57 57
58#if CONFIG_RANDOMIZE_BASE 58#if CONFIG_RANDOMIZE_BASE
59/* aslr.c */ 59/* aslr.c */
60unsigned char *choose_kernel_location(unsigned char *input, 60unsigned char *choose_kernel_location(struct boot_params *params,
61 unsigned char *input,
61 unsigned long input_size, 62 unsigned long input_size,
62 unsigned char *output, 63 unsigned char *output,
63 unsigned long output_size); 64 unsigned long output_size);
@@ -65,7 +66,8 @@ unsigned char *choose_kernel_location(unsigned char *input,
65bool has_cpuflag(int flag); 66bool has_cpuflag(int flag);
66#else 67#else
67static inline 68static inline
68unsigned char *choose_kernel_location(unsigned char *input, 69unsigned char *choose_kernel_location(struct boot_params *params,
70 unsigned char *input,
69 unsigned long input_size, 71 unsigned long input_size,
70 unsigned char *output, 72 unsigned char *output,
71 unsigned long output_size) 73 unsigned long output_size)