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