Merge tag 'dt-5.15' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc
[linux-2.6-microblaze.git] / arch / x86 / boot / compressed / efi_thunk_64.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 SYM_FUNC_START(__efi64_thunk)
26         push    %rbp
27         push    %rbx
28
29         leaq    1f(%rip), %rbp
30
31         movl    %ds, %eax
32         push    %rax
33         movl    %es, %eax
34         push    %rax
35         movl    %ss, %eax
36         push    %rax
37
38         /*
39          * Convert x86-64 ABI params to i386 ABI
40          */
41         subq    $64, %rsp
42         movl    %esi, 0x0(%rsp)
43         movl    %edx, 0x4(%rsp)
44         movl    %ecx, 0x8(%rsp)
45         movl    %r8d, 0xc(%rsp)
46         movl    %r9d, 0x10(%rsp)
47
48         leaq    0x14(%rsp), %rbx
49         sgdt    (%rbx)
50
51         addq    $16, %rbx
52         sidt    (%rbx)
53
54         /*
55          * Switch to IDT and GDT with 32-bit segments. This is the firmware GDT
56          * and IDT that was installed when the kernel started executing. The
57          * pointers were saved at the EFI stub entry point in head_64.S.
58          *
59          * Pass the saved DS selector to the 32-bit code, and use far return to
60          * restore the saved CS selector.
61          */
62         leaq    efi32_boot_idt(%rip), %rax
63         lidt    (%rax)
64         leaq    efi32_boot_gdt(%rip), %rax
65         lgdt    (%rax)
66
67         movzwl  efi32_boot_ds(%rip), %edx
68         movzwq  efi32_boot_cs(%rip), %rax
69         pushq   %rax
70         leaq    efi_enter32(%rip), %rax
71         pushq   %rax
72         lretq
73
74 1:      addq    $64, %rsp
75         movq    %rdi, %rax
76
77         pop     %rbx
78         movl    %ebx, %ss
79         pop     %rbx
80         movl    %ebx, %es
81         pop     %rbx
82         movl    %ebx, %ds
83         /* Clear out 32-bit selector from FS and GS */
84         xorl    %ebx, %ebx
85         movl    %ebx, %fs
86         movl    %ebx, %gs
87
88         /*
89          * Convert 32-bit status code into 64-bit.
90          */
91         roll    $1, %eax
92         rorq    $1, %rax
93
94         pop     %rbx
95         pop     %rbp
96         ret
97 SYM_FUNC_END(__efi64_thunk)
98
99         .code32
100 /*
101  * EFI service pointer must be in %edi.
102  *
103  * The stack should represent the 32-bit calling convention.
104  */
105 SYM_FUNC_START_LOCAL(efi_enter32)
106         /* Load firmware selector into data and stack segment registers */
107         movl    %edx, %ds
108         movl    %edx, %es
109         movl    %edx, %fs
110         movl    %edx, %gs
111         movl    %edx, %ss
112
113         /* Reload pgtables */
114         movl    %cr3, %eax
115         movl    %eax, %cr3
116
117         /* Disable paging */
118         movl    %cr0, %eax
119         btrl    $X86_CR0_PG_BIT, %eax
120         movl    %eax, %cr0
121
122         /* Disable long mode via EFER */
123         movl    $MSR_EFER, %ecx
124         rdmsr
125         btrl    $_EFER_LME, %eax
126         wrmsr
127
128         call    *%edi
129
130         /* We must preserve return value */
131         movl    %eax, %edi
132
133         /*
134          * Some firmware will return with interrupts enabled. Be sure to
135          * disable them before we switch GDTs and IDTs.
136          */
137         cli
138
139         lidtl   (%ebx)
140         subl    $16, %ebx
141
142         lgdtl   (%ebx)
143
144         movl    %cr4, %eax
145         btsl    $(X86_CR4_PAE_BIT), %eax
146         movl    %eax, %cr4
147
148         movl    %cr3, %eax
149         movl    %eax, %cr3
150
151         movl    $MSR_EFER, %ecx
152         rdmsr
153         btsl    $_EFER_LME, %eax
154         wrmsr
155
156         xorl    %eax, %eax
157         lldt    %ax
158
159         pushl   $__KERNEL_CS
160         pushl   %ebp
161
162         /* Enable paging */
163         movl    %cr0, %eax
164         btsl    $X86_CR0_PG_BIT, %eax
165         movl    %eax, %cr0
166         lret
167 SYM_FUNC_END(efi_enter32)
168
169         .data
170         .balign 8
171 SYM_DATA_START(efi32_boot_gdt)
172         .word   0
173         .quad   0
174 SYM_DATA_END(efi32_boot_gdt)
175
176 SYM_DATA_START(efi32_boot_idt)
177         .word   0
178         .quad   0
179 SYM_DATA_END(efi32_boot_idt)
180
181 SYM_DATA_START(efi32_boot_cs)
182         .word   0
183 SYM_DATA_END(efi32_boot_cs)
184
185 SYM_DATA_START(efi32_boot_ds)
186         .word   0
187 SYM_DATA_END(efi32_boot_ds)