~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/x86/boot/compressed/efi_mixed.S

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php