aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2015-02-18 08:40:40 -0500
committerIngo Molnar <mingo@kernel.org>2015-02-18 08:40:40 -0500
commit829bf7af647e489caa494cebdb2e4d455ec4644a (patch)
treef8980bea7e8e62130cd477dd2ab32b54353448ab /arch/x86
parente07e0d4cb0c4bfe822ec8491cc06269096a38bea (diff)
parent43a9f69692b232d1c64c913a27507eb14a1c47fd (diff)
Merge tag 'efi-urgent' of git://git.kernel.org/pub/scm/linux/kernel/git/mfleming/efi into x86/urgent
Pull EFI fixes from Matt Fleming: " - Leave a valid 64-bit IDT installed during runtime EFI mixed mode calls to avoid triple faults if an NMI/MCE is received. - Revert Ard's change to the libstub get_memory_map() that went into the v3.20 merge window because it causes boot regressions on Qemu and Xen. " Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'arch/x86')
-rw-r--r--arch/x86/boot/compressed/Makefile1
-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/platform/efi/efi_stub_64.S161
-rw-r--r--arch/x86/platform/efi/efi_thunk_64.S121
5 files changed, 301 insertions, 203 deletions
diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile
index ad754b4411f7..8bd44e8ee6e2 100644
--- a/arch/x86/boot/compressed/Makefile
+++ b/arch/x86/boot/compressed/Makefile
@@ -49,6 +49,7 @@ $(obj)/eboot.o: KBUILD_CFLAGS += -fshort-wchar -mno-red-zone
49 49
50vmlinux-objs-$(CONFIG_EFI_STUB) += $(obj)/eboot.o $(obj)/efi_stub_$(BITS).o \ 50vmlinux-objs-$(CONFIG_EFI_STUB) += $(obj)/eboot.o $(obj)/efi_stub_$(BITS).o \
51 $(objtree)/drivers/firmware/efi/libstub/lib.a 51 $(objtree)/drivers/firmware/efi/libstub/lib.a
52vmlinux-objs-$(CONFIG_EFI_MIXED) += $(obj)/efi_thunk_$(BITS).o
52 53
53$(obj)/vmlinux: $(vmlinux-objs-y) FORCE 54$(obj)/vmlinux: $(vmlinux-objs-y) FORCE
54 $(call if_changed,ld) 55 $(call if_changed,ld)
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/platform/efi/efi_stub_64.S b/arch/x86/platform/efi/efi_stub_64.S
index 5fcda7272550..86d0f9e08dd9 100644
--- a/arch/x86/platform/efi/efi_stub_64.S
+++ b/arch/x86/platform/efi/efi_stub_64.S
@@ -91,167 +91,6 @@ ENTRY(efi_call)
91 ret 91 ret
92ENDPROC(efi_call) 92ENDPROC(efi_call)
93 93
94#ifdef CONFIG_EFI_MIXED
95
96/*
97 * We run this function from the 1:1 mapping.
98 *
99 * This function must be invoked with a 1:1 mapped stack.
100 */
101ENTRY(__efi64_thunk)
102 movl %ds, %eax
103 push %rax
104 movl %es, %eax
105 push %rax
106 movl %ss, %eax
107 push %rax
108
109 subq $32, %rsp
110 movl %esi, 0x0(%rsp)
111 movl %edx, 0x4(%rsp)
112 movl %ecx, 0x8(%rsp)
113 movq %r8, %rsi
114 movl %esi, 0xc(%rsp)
115 movq %r9, %rsi
116 movl %esi, 0x10(%rsp)
117
118 sgdt save_gdt(%rip)
119
120 leaq 1f(%rip), %rbx
121 movq %rbx, func_rt_ptr(%rip)
122
123 /* Switch to gdt with 32-bit segments */
124 movl 64(%rsp), %eax
125 lgdt (%rax)
126
127 leaq efi_enter32(%rip), %rax
128 pushq $__KERNEL_CS
129 pushq %rax
130 lretq
131
1321: addq $32, %rsp
133
134 lgdt save_gdt(%rip)
135
136 pop %rbx
137 movl %ebx, %ss
138 pop %rbx
139 movl %ebx, %es
140 pop %rbx
141 movl %ebx, %ds
142
143 /*
144 * Convert 32-bit status code into 64-bit.
145 */
146 test %rax, %rax
147 jz 1f
148 movl %eax, %ecx
149 andl $0x0fffffff, %ecx
150 andl $0xf0000000, %eax
151 shl $32, %rax
152 or %rcx, %rax
1531:
154 ret
155ENDPROC(__efi64_thunk)
156
157ENTRY(efi_exit32)
158 movq func_rt_ptr(%rip), %rax
159 push %rax
160 mov %rdi, %rax
161 ret
162ENDPROC(efi_exit32)
163
164 .code32
165/*
166 * EFI service pointer must be in %edi.
167 *
168 * The stack should represent the 32-bit calling convention.
169 */
170ENTRY(efi_enter32)
171 movl $__KERNEL_DS, %eax
172 movl %eax, %ds
173 movl %eax, %es
174 movl %eax, %ss
175
176 /* Reload pgtables */
177 movl %cr3, %eax
178 movl %eax, %cr3
179
180 /* Disable paging */
181 movl %cr0, %eax
182 btrl $X86_CR0_PG_BIT, %eax
183 movl %eax, %cr0
184
185 /* Disable long mode via EFER */
186 movl $MSR_EFER, %ecx
187 rdmsr
188 btrl $_EFER_LME, %eax
189 wrmsr
190
191 call *%edi
192
193 /* We must preserve return value */
194 movl %eax, %edi
195
196 /*
197 * Some firmware will return with interrupts enabled. Be sure to
198 * disable them before we switch GDTs.
199 */
200 cli
201
202 movl 68(%esp), %eax
203 movl %eax, 2(%eax)
204 lgdtl (%eax)
205
206 movl %cr4, %eax
207 btsl $(X86_CR4_PAE_BIT), %eax
208 movl %eax, %cr4
209
210 movl %cr3, %eax
211 movl %eax, %cr3
212
213 movl $MSR_EFER, %ecx
214 rdmsr
215 btsl $_EFER_LME, %eax
216 wrmsr
217
218 xorl %eax, %eax
219 lldt %ax
220
221 movl 72(%esp), %eax
222 pushl $__KERNEL_CS
223 pushl %eax
224
225 /* Enable paging */
226 movl %cr0, %eax
227 btsl $X86_CR0_PG_BIT, %eax
228 movl %eax, %cr0
229 lret
230ENDPROC(efi_enter32)
231
232 .data
233 .balign 8
234 .global efi32_boot_gdt
235efi32_boot_gdt: .word 0
236 .quad 0
237
238save_gdt: .word 0
239 .quad 0
240func_rt_ptr: .quad 0
241
242 .global efi_gdt64
243efi_gdt64:
244 .word efi_gdt64_end - efi_gdt64
245 .long 0 /* Filled out by user */
246 .word 0
247 .quad 0x0000000000000000 /* NULL descriptor */
248 .quad 0x00af9a000000ffff /* __KERNEL_CS */
249 .quad 0x00cf92000000ffff /* __KERNEL_DS */
250 .quad 0x0080890000000000 /* TS descriptor */
251 .quad 0x0000000000000000 /* TS continued */
252efi_gdt64_end:
253#endif /* CONFIG_EFI_MIXED */
254
255 .data 94 .data
256ENTRY(efi_scratch) 95ENTRY(efi_scratch)
257 .fill 3,8,0 96 .fill 3,8,0
diff --git a/arch/x86/platform/efi/efi_thunk_64.S b/arch/x86/platform/efi/efi_thunk_64.S
index 8806fa73e6e6..ff85d28c50f2 100644
--- a/arch/x86/platform/efi/efi_thunk_64.S
+++ b/arch/x86/platform/efi/efi_thunk_64.S
@@ -1,9 +1,26 @@
1/* 1/*
2 * Copyright (C) 2014 Intel Corporation; author Matt Fleming 2 * Copyright (C) 2014 Intel Corporation; author Matt Fleming
3 *
4 * Support for invoking 32-bit EFI runtime services from a 64-bit
5 * kernel.
6 *
7 * The below thunking functions are only used after ExitBootServices()
8 * has been called. This simplifies things considerably as compared with
9 * the early EFI thunking because we can leave all the kernel state
10 * intact (GDT, IDT, etc) and simply invoke the the 32-bit EFI runtime
11 * services from __KERNEL32_CS. This means we can continue to service
12 * interrupts across an EFI mixed mode call.
13 *
14 * We do however, need to handle the fact that we're running in a full
15 * 64-bit virtual address space. Things like the stack and instruction
16 * addresses need to be accessible by the 32-bit firmware, so we rely on
17 * using the identity mappings in the EFI page table to access the stack
18 * and kernel text (see efi_setup_page_tables()).
3 */ 19 */
4 20
5#include <linux/linkage.h> 21#include <linux/linkage.h>
6#include <asm/page_types.h> 22#include <asm/page_types.h>
23#include <asm/segment.h>
7 24
8 .text 25 .text
9 .code64 26 .code64
@@ -33,14 +50,6 @@ ENTRY(efi64_thunk)
33 leaq efi_exit32(%rip), %rbx 50 leaq efi_exit32(%rip), %rbx
34 subq %rax, %rbx 51 subq %rax, %rbx
35 movl %ebx, 8(%rsp) 52 movl %ebx, 8(%rsp)
36 leaq efi_gdt64(%rip), %rbx
37 subq %rax, %rbx
38 movl %ebx, 2(%ebx)
39 movl %ebx, 4(%rsp)
40 leaq efi_gdt32(%rip), %rbx
41 subq %rax, %rbx
42 movl %ebx, 2(%ebx)
43 movl %ebx, (%rsp)
44 53
45 leaq __efi64_thunk(%rip), %rbx 54 leaq __efi64_thunk(%rip), %rbx
46 subq %rax, %rbx 55 subq %rax, %rbx
@@ -52,14 +61,92 @@ ENTRY(efi64_thunk)
52 retq 61 retq
53ENDPROC(efi64_thunk) 62ENDPROC(efi64_thunk)
54 63
55 .data 64/*
56efi_gdt32: 65 * We run this function from the 1:1 mapping.
57 .word efi_gdt32_end - efi_gdt32 66 *
58 .long 0 /* Filled out above */ 67 * This function must be invoked with a 1:1 mapped stack.
59 .word 0 68 */
60 .quad 0x0000000000000000 /* NULL descriptor */ 69ENTRY(__efi64_thunk)
61 .quad 0x00cf9a000000ffff /* __KERNEL_CS */ 70 movl %ds, %eax
62 .quad 0x00cf93000000ffff /* __KERNEL_DS */ 71 push %rax
63efi_gdt32_end: 72 movl %es, %eax
73 push %rax
74 movl %ss, %eax
75 push %rax
76
77 subq $32, %rsp
78 movl %esi, 0x0(%rsp)
79 movl %edx, 0x4(%rsp)
80 movl %ecx, 0x8(%rsp)
81 movq %r8, %rsi
82 movl %esi, 0xc(%rsp)
83 movq %r9, %rsi
84 movl %esi, 0x10(%rsp)
85
86 leaq 1f(%rip), %rbx
87 movq %rbx, func_rt_ptr(%rip)
88
89 /* Switch to 32-bit descriptor */
90 pushq $__KERNEL32_CS
91 leaq efi_enter32(%rip), %rax
92 pushq %rax
93 lretq
94
951: addq $32, %rsp
96
97 pop %rbx
98 movl %ebx, %ss
99 pop %rbx
100 movl %ebx, %es
101 pop %rbx
102 movl %ebx, %ds
64 103
104 /*
105 * Convert 32-bit status code into 64-bit.
106 */
107 test %rax, %rax
108 jz 1f
109 movl %eax, %ecx
110 andl $0x0fffffff, %ecx
111 andl $0xf0000000, %eax
112 shl $32, %rax
113 or %rcx, %rax
1141:
115 ret
116ENDPROC(__efi64_thunk)
117
118ENTRY(efi_exit32)
119 movq func_rt_ptr(%rip), %rax
120 push %rax
121 mov %rdi, %rax
122 ret
123ENDPROC(efi_exit32)
124
125 .code32
126/*
127 * EFI service pointer must be in %edi.
128 *
129 * The stack should represent the 32-bit calling convention.
130 */
131ENTRY(efi_enter32)
132 movl $__KERNEL_DS, %eax
133 movl %eax, %ds
134 movl %eax, %es
135 movl %eax, %ss
136
137 call *%edi
138
139 /* We must preserve return value */
140 movl %eax, %edi
141
142 movl 72(%esp), %eax
143 pushl $__KERNEL_CS
144 pushl %eax
145
146 lret
147ENDPROC(efi_enter32)
148
149 .data
150 .balign 8
151func_rt_ptr: .quad 0
65efi_saved_sp: .quad 0 152efi_saved_sp: .quad 0