diff options
author | Ingo Molnar <mingo@kernel.org> | 2015-02-18 08:40:40 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2015-02-18 08:40:40 -0500 |
commit | 829bf7af647e489caa494cebdb2e4d455ec4644a (patch) | |
tree | f8980bea7e8e62130cd477dd2ab32b54353448ab /arch/x86 | |
parent | e07e0d4cb0c4bfe822ec8491cc06269096a38bea (diff) | |
parent | 43a9f69692b232d1c64c913a27507eb14a1c47fd (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/Makefile | 1 | ||||
-rw-r--r-- | arch/x86/boot/compressed/efi_stub_64.S | 25 | ||||
-rw-r--r-- | arch/x86/boot/compressed/efi_thunk_64.S | 196 | ||||
-rw-r--r-- | arch/x86/platform/efi/efi_stub_64.S | 161 | ||||
-rw-r--r-- | arch/x86/platform/efi/efi_thunk_64.S | 121 |
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 | ||
50 | vmlinux-objs-$(CONFIG_EFI_STUB) += $(obj)/eboot.o $(obj)/efi_stub_$(BITS).o \ | 50 | vmlinux-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 |
52 | vmlinux-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 | ||
10 | ENTRY(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 | ||
29 | ENDPROC(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 | ||
25 | ENTRY(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 | |||
73 | 1: 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 | ||
94 | 1: | ||
95 | addq $8, %rsp | ||
96 | pop %rbx | ||
97 | pop %rbp | ||
98 | ret | ||
99 | ENDPROC(efi64_thunk) | ||
100 | |||
101 | ENTRY(efi_exit32) | ||
102 | movq func_rt_ptr(%rip), %rax | ||
103 | push %rax | ||
104 | mov %rdi, %rax | ||
105 | ret | ||
106 | ENDPROC(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 | */ | ||
114 | ENTRY(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 | ||
174 | ENDPROC(efi_enter32) | ||
175 | |||
176 | .data | ||
177 | .balign 8 | ||
178 | .global efi32_boot_gdt | ||
179 | efi32_boot_gdt: .word 0 | ||
180 | .quad 0 | ||
181 | |||
182 | save_gdt: .word 0 | ||
183 | .quad 0 | ||
184 | func_rt_ptr: .quad 0 | ||
185 | |||
186 | .global efi_gdt64 | ||
187 | efi_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 */ | ||
196 | efi_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 |
92 | ENDPROC(efi_call) | 92 | ENDPROC(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 | */ | ||
101 | ENTRY(__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 | |||
132 | 1: 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 | ||
153 | 1: | ||
154 | ret | ||
155 | ENDPROC(__efi64_thunk) | ||
156 | |||
157 | ENTRY(efi_exit32) | ||
158 | movq func_rt_ptr(%rip), %rax | ||
159 | push %rax | ||
160 | mov %rdi, %rax | ||
161 | ret | ||
162 | ENDPROC(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 | */ | ||
170 | ENTRY(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 | ||
230 | ENDPROC(efi_enter32) | ||
231 | |||
232 | .data | ||
233 | .balign 8 | ||
234 | .global efi32_boot_gdt | ||
235 | efi32_boot_gdt: .word 0 | ||
236 | .quad 0 | ||
237 | |||
238 | save_gdt: .word 0 | ||
239 | .quad 0 | ||
240 | func_rt_ptr: .quad 0 | ||
241 | |||
242 | .global efi_gdt64 | ||
243 | efi_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 */ | ||
252 | efi_gdt64_end: | ||
253 | #endif /* CONFIG_EFI_MIXED */ | ||
254 | |||
255 | .data | 94 | .data |
256 | ENTRY(efi_scratch) | 95 | ENTRY(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 |
53 | ENDPROC(efi64_thunk) | 62 | ENDPROC(efi64_thunk) |
54 | 63 | ||
55 | .data | 64 | /* |
56 | efi_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 */ | 69 | ENTRY(__efi64_thunk) |
61 | .quad 0x00cf9a000000ffff /* __KERNEL_CS */ | 70 | movl %ds, %eax |
62 | .quad 0x00cf93000000ffff /* __KERNEL_DS */ | 71 | push %rax |
63 | efi_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 | |||
95 | 1: 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 | ||
114 | 1: | ||
115 | ret | ||
116 | ENDPROC(__efi64_thunk) | ||
117 | |||
118 | ENTRY(efi_exit32) | ||
119 | movq func_rt_ptr(%rip), %rax | ||
120 | push %rax | ||
121 | mov %rdi, %rax | ||
122 | ret | ||
123 | ENDPROC(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 | */ | ||
131 | ENTRY(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 | ||
147 | ENDPROC(efi_enter32) | ||
148 | |||
149 | .data | ||
150 | .balign 8 | ||
151 | func_rt_ptr: .quad 0 | ||
65 | efi_saved_sp: .quad 0 | 152 | efi_saved_sp: .quad 0 |