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