f4e22ef774ab6b4a0702d0e608007a994cec3fbe
[sfrench/cifs-2.6.git] / arch / x86 / boot / compressed / efi_mixed.S
1 /* SPDX-License-Identifier: GPL-2.0 */
2 /*
3  * Copyright (C) 2014, 2015 Intel Corporation; author Matt Fleming
4  *
5  * Early support for invoking 32-bit EFI services from a 64-bit kernel.
6  *
7  * Because this thunking occurs before ExitBootServices() we have to
8  * restore the firmware's 32-bit GDT and IDT before we make EFI service
9  * calls.
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 identity
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 /*
26  * When booting in 64-bit mode on 32-bit EFI firmware, startup_64_mixed_mode()
27  * is the first thing that runs after switching to long mode. Depending on
28  * whether the EFI handover protocol or the compat entry point was used to
29  * enter the kernel, it will either branch to the common 64-bit EFI stub
30  * entrypoint efi_stub_entry() directly, or via the 64-bit EFI PE/COFF
31  * entrypoint efi_pe_entry(). In the former case, the bootloader must provide a
32  * struct bootparams pointer as the third argument, so the presence of such a
33  * pointer is used to disambiguate.
34  *
35  *                                                             +--------------+
36  *  +------------------+     +------------+            +------>| efi_pe_entry |
37  *  | efi32_pe_entry   |---->|            |            |       +-----------+--+
38  *  +------------------+     |            |     +------+----------------+  |
39  *                           | startup_32 |---->| startup_64_mixed_mode |  |
40  *  +------------------+     |            |     +------+----------------+  |
41  *  | efi32_stub_entry |---->|            |            |                   |
42  *  +------------------+     +------------+            |                   |
43  *                                                     V                   |
44  *                           +------------+     +----------------+         |
45  *                           | startup_64 |<----| efi_stub_entry |<--------+
46  *                           +------------+     +----------------+
47  */
48 SYM_FUNC_START(startup_64_mixed_mode)
49         lea     efi32_boot_args(%rip), %rdx
50         mov     0(%rdx), %edi
51         mov     4(%rdx), %esi
52 #ifdef CONFIG_EFI_HANDOVER_PROTOCOL
53         mov     8(%rdx), %edx           // saved bootparams pointer
54         test    %edx, %edx
55         jnz     efi_stub_entry
56 #endif
57         /*
58          * efi_pe_entry uses MS calling convention, which requires 32 bytes of
59          * shadow space on the stack even if all arguments are passed in
60          * registers. We also need an additional 8 bytes for the space that
61          * would be occupied by the return address, and this also results in
62          * the correct stack alignment for entry.
63          */
64         sub     $40, %rsp
65         mov     %rdi, %rcx              // MS calling convention
66         mov     %rsi, %rdx
67         jmp     efi_pe_entry
68 SYM_FUNC_END(startup_64_mixed_mode)
69
70 SYM_FUNC_START(__efi64_thunk)
71         push    %rbp
72         push    %rbx
73
74         movl    %ds, %eax
75         push    %rax
76         movl    %es, %eax
77         push    %rax
78         movl    %ss, %eax
79         push    %rax
80
81         /* Copy args passed on stack */
82         movq    0x30(%rsp), %rbp
83         movq    0x38(%rsp), %rbx
84         movq    0x40(%rsp), %rax
85
86         /*
87          * Convert x86-64 ABI params to i386 ABI
88          */
89         subq    $64, %rsp
90         movl    %esi, 0x0(%rsp)
91         movl    %edx, 0x4(%rsp)
92         movl    %ecx, 0x8(%rsp)
93         movl    %r8d, 0xc(%rsp)
94         movl    %r9d, 0x10(%rsp)
95         movl    %ebp, 0x14(%rsp)
96         movl    %ebx, 0x18(%rsp)
97         movl    %eax, 0x1c(%rsp)
98
99         leaq    0x20(%rsp), %rbx
100         sgdt    (%rbx)
101         sidt    16(%rbx)
102
103         leaq    1f(%rip), %rbp
104
105         /*
106          * Switch to IDT and GDT with 32-bit segments. These are the firmware
107          * GDT and IDT that were installed when the kernel started executing.
108          * The pointers were saved by the efi32_entry() routine below.
109          *
110          * Pass the saved DS selector to the 32-bit code, and use far return to
111          * restore the saved CS selector.
112          */
113         lidt    efi32_boot_idt(%rip)
114         lgdt    efi32_boot_gdt(%rip)
115
116         movzwl  efi32_boot_ds(%rip), %edx
117         movzwq  efi32_boot_cs(%rip), %rax
118         pushq   %rax
119         leaq    efi_enter32(%rip), %rax
120         pushq   %rax
121         lretq
122
123 1:      addq    $64, %rsp
124         movq    %rdi, %rax
125
126         pop     %rbx
127         movl    %ebx, %ss
128         pop     %rbx
129         movl    %ebx, %es
130         pop     %rbx
131         movl    %ebx, %ds
132         /* Clear out 32-bit selector from FS and GS */
133         xorl    %ebx, %ebx
134         movl    %ebx, %fs
135         movl    %ebx, %gs
136
137         pop     %rbx
138         pop     %rbp
139         RET
140 SYM_FUNC_END(__efi64_thunk)
141
142         .code32
143 #ifdef CONFIG_EFI_HANDOVER_PROTOCOL
144 SYM_FUNC_START(efi32_stub_entry)
145         call    1f
146 1:      popl    %ecx
147
148         /* Clear BSS */
149         xorl    %eax, %eax
150         leal    (_bss - 1b)(%ecx), %edi
151         leal    (_ebss - 1b)(%ecx), %ecx
152         subl    %edi, %ecx
153         shrl    $2, %ecx
154         cld
155         rep     stosl
156
157         add     $0x4, %esp              /* Discard return address */
158         popl    %ecx
159         popl    %edx
160         popl    %esi
161         jmp     efi32_entry
162 SYM_FUNC_END(efi32_stub_entry)
163 #endif
164
165 /*
166  * EFI service pointer must be in %edi.
167  *
168  * The stack should represent the 32-bit calling convention.
169  */
170 SYM_FUNC_START_LOCAL(efi_enter32)
171         /* Load firmware selector into data and stack segment registers */
172         movl    %edx, %ds
173         movl    %edx, %es
174         movl    %edx, %fs
175         movl    %edx, %gs
176         movl    %edx, %ss
177
178         /* Reload pgtables */
179         movl    %cr3, %eax
180         movl    %eax, %cr3
181
182         /* Disable paging */
183         movl    %cr0, %eax
184         btrl    $X86_CR0_PG_BIT, %eax
185         movl    %eax, %cr0
186
187         /* Disable long mode via EFER */
188         movl    $MSR_EFER, %ecx
189         rdmsr
190         btrl    $_EFER_LME, %eax
191         wrmsr
192
193         call    *%edi
194
195         /* We must preserve return value */
196         movl    %eax, %edi
197
198         /*
199          * Some firmware will return with interrupts enabled. Be sure to
200          * disable them before we switch GDTs and IDTs.
201          */
202         cli
203
204         lidtl   16(%ebx)
205         lgdtl   (%ebx)
206
207         movl    %cr4, %eax
208         btsl    $(X86_CR4_PAE_BIT), %eax
209         movl    %eax, %cr4
210
211         movl    %cr3, %eax
212         movl    %eax, %cr3
213
214         movl    $MSR_EFER, %ecx
215         rdmsr
216         btsl    $_EFER_LME, %eax
217         wrmsr
218
219         xorl    %eax, %eax
220         lldt    %ax
221
222         pushl   $__KERNEL_CS
223         pushl   %ebp
224
225         /* Enable paging */
226         movl    %cr0, %eax
227         btsl    $X86_CR0_PG_BIT, %eax
228         movl    %eax, %cr0
229         lret
230 SYM_FUNC_END(efi_enter32)
231
232 /*
233  * This is the common EFI stub entry point for mixed mode.
234  *
235  * Arguments:   %ecx    image handle
236  *              %edx    EFI system table pointer
237  *              %esi    struct bootparams pointer (or NULL when not using
238  *                      the EFI handover protocol)
239  *
240  * Since this is the point of no return for ordinary execution, no registers
241  * are considered live except for the function parameters. [Note that the EFI
242  * stub may still exit and return to the firmware using the Exit() EFI boot
243  * service.]
244  */
245 SYM_FUNC_START_LOCAL(efi32_entry)
246         call    1f
247 1:      pop     %ebx
248
249         /* Save firmware GDTR and code/data selectors */
250         sgdtl   (efi32_boot_gdt - 1b)(%ebx)
251         movw    %cs, (efi32_boot_cs - 1b)(%ebx)
252         movw    %ds, (efi32_boot_ds - 1b)(%ebx)
253
254         /* Store firmware IDT descriptor */
255         sidtl   (efi32_boot_idt - 1b)(%ebx)
256
257         /* Store boot arguments */
258         leal    (efi32_boot_args - 1b)(%ebx), %ebx
259         movl    %ecx, 0(%ebx)
260         movl    %edx, 4(%ebx)
261         movl    %esi, 8(%ebx)
262         movb    $0x0, 12(%ebx)          // efi_is64
263
264         /* Disable paging */
265         movl    %cr0, %eax
266         btrl    $X86_CR0_PG_BIT, %eax
267         movl    %eax, %cr0
268
269         jmp     startup_32
270 SYM_FUNC_END(efi32_entry)
271
272 /*
273  * efi_status_t efi32_pe_entry(efi_handle_t image_handle,
274  *                             efi_system_table_32_t *sys_table)
275  */
276 SYM_FUNC_START(efi32_pe_entry)
277         pushl   %ebp
278         movl    %esp, %ebp
279         pushl   %ebx                            // save callee-save registers
280         pushl   %edi
281
282         call    verify_cpu                      // check for long mode support
283         testl   %eax, %eax
284         movl    $0x80000003, %eax               // EFI_UNSUPPORTED
285         jnz     2f
286
287         movl    8(%ebp), %ecx                   // image_handle
288         movl    12(%ebp), %edx                  // sys_table
289         xorl    %esi, %esi
290         jmp     efi32_entry                     // pass %ecx, %edx, %esi
291                                                 // no other registers remain live
292
293 2:      popl    %edi                            // restore callee-save registers
294         popl    %ebx
295         leave
296         RET
297 SYM_FUNC_END(efi32_pe_entry)
298
299 #ifdef CONFIG_EFI_HANDOVER_PROTOCOL
300         .org    efi32_stub_entry + 0x200
301         .code64
302 SYM_FUNC_START_NOALIGN(efi64_stub_entry)
303         jmp     efi_handover_entry
304 SYM_FUNC_END(efi64_stub_entry)
305 #endif
306
307         .data
308         .balign 8
309 SYM_DATA_START_LOCAL(efi32_boot_gdt)
310         .word   0
311         .quad   0
312 SYM_DATA_END(efi32_boot_gdt)
313
314 SYM_DATA_START_LOCAL(efi32_boot_idt)
315         .word   0
316         .quad   0
317 SYM_DATA_END(efi32_boot_idt)
318
319 SYM_DATA_LOCAL(efi32_boot_cs, .word 0)
320 SYM_DATA_LOCAL(efi32_boot_ds, .word 0)
321 SYM_DATA_LOCAL(efi32_boot_args, .long 0, 0, 0)
322 SYM_DATA(efi_is64, .byte 1)