Merge tag 'kvm-s390-next-5.6-1' of git://git.kernel.org/pub/scm/linux/kernel/git...
[sfrench/cifs-2.6.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 before we make EFI serivce calls,
9  * since the firmware's 32-bit IDT is still currently installed and it
10  * needs to be able to service interrupts.
11  *
12  * On the plus side, we don't have to worry about mangling 64-bit
13  * addresses into 32-bits because we're executing with an identity
14  * mapped pagetable and haven't transitioned to 64-bit virtual addresses
15  * yet.
16  */
17
18 #include <linux/linkage.h>
19 #include <asm/msr.h>
20 #include <asm/page_types.h>
21 #include <asm/processor-flags.h>
22 #include <asm/segment.h>
23
24         .code64
25         .text
26 SYM_FUNC_START(__efi64_thunk)
27         push    %rbp
28         push    %rbx
29
30         leaq    1f(%rip), %rbp
31         leaq    efi_gdt64(%rip), %rbx
32         movl    %ebx, 2(%rbx)           /* Fixup the gdt base address */
33
34         movl    %ds, %eax
35         push    %rax
36         movl    %es, %eax
37         push    %rax
38         movl    %ss, %eax
39         push    %rax
40
41         /*
42          * Convert x86-64 ABI params to i386 ABI
43          */
44         subq    $32, %rsp
45         movl    %esi, 0x0(%rsp)
46         movl    %edx, 0x4(%rsp)
47         movl    %ecx, 0x8(%rsp)
48         movl    %r8d, 0xc(%rsp)
49         movl    %r9d, 0x10(%rsp)
50
51         sgdt    0x14(%rsp)
52
53         /*
54          * Switch to gdt with 32-bit segments. This is the firmware GDT
55          * that was installed when the kernel started executing. This
56          * pointer was saved at the EFI stub entry point in head_64.S.
57          */
58         leaq    efi32_boot_gdt(%rip), %rax
59         lgdt    (%rax)
60
61         pushq   $__KERNEL_CS
62         leaq    efi_enter32(%rip), %rax
63         pushq   %rax
64         lretq
65
66 1:      lgdt    0x14(%rsp)
67         addq    $32, %rsp
68         movq    %rdi, %rax
69
70         pop     %rbx
71         movl    %ebx, %ss
72         pop     %rbx
73         movl    %ebx, %es
74         pop     %rbx
75         movl    %ebx, %ds
76
77         /*
78          * Convert 32-bit status code into 64-bit.
79          */
80         roll    $1, %eax
81         rorq    $1, %rax
82
83         pop     %rbx
84         pop     %rbp
85         ret
86 SYM_FUNC_END(__efi64_thunk)
87
88         .code32
89 /*
90  * EFI service pointer must be in %edi.
91  *
92  * The stack should represent the 32-bit calling convention.
93  */
94 SYM_FUNC_START_LOCAL(efi_enter32)
95         movl    $__KERNEL_DS, %eax
96         movl    %eax, %ds
97         movl    %eax, %es
98         movl    %eax, %ss
99
100         /* Reload pgtables */
101         movl    %cr3, %eax
102         movl    %eax, %cr3
103
104         /* Disable paging */
105         movl    %cr0, %eax
106         btrl    $X86_CR0_PG_BIT, %eax
107         movl    %eax, %cr0
108
109         /* Disable long mode via EFER */
110         movl    $MSR_EFER, %ecx
111         rdmsr
112         btrl    $_EFER_LME, %eax
113         wrmsr
114
115         call    *%edi
116
117         /* We must preserve return value */
118         movl    %eax, %edi
119
120         /*
121          * Some firmware will return with interrupts enabled. Be sure to
122          * disable them before we switch GDTs.
123          */
124         cli
125
126         lgdtl   (%ebx)
127
128         movl    %cr4, %eax
129         btsl    $(X86_CR4_PAE_BIT), %eax
130         movl    %eax, %cr4
131
132         movl    %cr3, %eax
133         movl    %eax, %cr3
134
135         movl    $MSR_EFER, %ecx
136         rdmsr
137         btsl    $_EFER_LME, %eax
138         wrmsr
139
140         xorl    %eax, %eax
141         lldt    %ax
142
143         pushl   $__KERNEL_CS
144         pushl   %ebp
145
146         /* Enable paging */
147         movl    %cr0, %eax
148         btsl    $X86_CR0_PG_BIT, %eax
149         movl    %eax, %cr0
150         lret
151 SYM_FUNC_END(efi_enter32)
152
153         .data
154         .balign 8
155 SYM_DATA_START(efi32_boot_gdt)
156         .word   0
157         .quad   0
158 SYM_DATA_END(efi32_boot_gdt)
159
160 SYM_DATA_START(efi_gdt64)
161         .word   efi_gdt64_end - efi_gdt64
162         .long   0                       /* Filled out by user */
163         .word   0
164         .quad   0x0000000000000000      /* NULL descriptor */
165         .quad   0x00af9a000000ffff      /* __KERNEL_CS */
166         .quad   0x00cf92000000ffff      /* __KERNEL_DS */
167         .quad   0x0080890000000000      /* TS descriptor */
168         .quad   0x0000000000000000      /* TS continued */
169 SYM_DATA_END_LABEL(efi_gdt64, SYM_L_LOCAL, efi_gdt64_end)