15
15
*/
16
16
17
17
#include <linux/linkage.h>
18
- #include <asm/asm-offsets .h>
18
+ #include <asm/desc_defs .h>
19
19
#include <asm/msr.h>
20
20
#include <asm/page_types.h>
21
21
#include <asm/pgtable_types.h>
22
22
#include <asm/processor-flags.h>
23
23
#include <asm/segment.h>
24
- #include <asm/setup.h>
25
24
26
25
.code64
27
26
.text
28
- /*
29
- * When booting in 64-bit mode on 32-bit EFI firmware, startup_64_mixed_mode()
30
- * is the first thing that runs after switching to long mode. Depending on
31
- * whether the EFI handover protocol or the compat entry point was used to
32
- * enter the kernel, it will either branch to the common 64-bit EFI stub
33
- * entrypoint efi_stub_entry() directly, or via the 64-bit EFI PE/COFF
34
- * entrypoint efi_pe_entry(). In the former case, the bootloader must provide a
35
- * struct bootparams pointer as the third argument, so the presence of such a
36
- * pointer is used to disambiguate.
37
- *
38
- * +--------------+
39
- * +------------------+ +------------+ +------>| efi_pe_entry |
40
- * | efi32_pe_entry |---->| | | +-----------+--+
41
- * +------------------+ | | +------+----------------+ |
42
- * | startup_32 |---->| startup_64_mixed_mode | |
43
- * +------------------+ | | +------+----------------+ |
44
- * | efi32_stub_entry |---->| | | |
45
- * +------------------+ +------------+ | |
46
- * V |
47
- * +------------+ +----------------+ |
48
- * | startup_64 |<----| efi_stub_entry |<--------+
49
- * +------------+ +----------------+
50
- */
51
- SYM_FUNC_START(startup_64_mixed_mode)
52
- lea efi32_boot_args(%rip ), %rdx
53
- mov 0 (%rdx ), %edi
54
- mov 4 (%rdx ), %esi
55
-
56
- leaq (pte + 5 * PAGE_SIZE)(%rip ), %rax
57
- movq %rax , %cr3 // reload after startup_32
58
-
59
- /* Switch to the firmware's stack */
60
- movl efi32_boot_sp(%rip ), %esp
61
- andl $~7 , %esp
62
-
63
- mov 8 (%rdx ), %edx // saved bootparams pointer
64
- call efi_stub_entry
65
- SYM_FUNC_END(startup_64_mixed_mode)
66
-
67
27
SYM_FUNC_START(__efi64_thunk)
68
28
push %rbp
69
29
push %rbx
70
30
71
- movl %ds , %eax
72
- push %rax
73
- movl %es , %eax
74
- push %rax
75
- movl %ss , %eax
76
- push %rax
77
-
78
31
/* Copy args passed on stack */
79
- movq 0x30 (%rsp ), %rbp
80
- movq 0x38 (%rsp ), %rbx
81
- movq 0x40 (%rsp ), %rax
32
+ movq 0x18 (%rsp ), %rbp
33
+ movq 0x20 (%rsp ), %rbx
34
+ movq 0x28 (%rsp ), %rax
82
35
83
36
/*
84
37
* Convert x86-64 ABI params to i386 ABI
@@ -93,44 +46,14 @@ SYM_FUNC_START(__efi64_thunk)
93
46
movl %ebx , 0x18 (%rsp )
94
47
movl %eax , 0x1c (%rsp )
95
48
96
- leaq 0x20 (%rsp ), %rbx
97
- sgdt (%rbx )
98
- sidt 16 (%rbx )
99
-
100
49
leaq 1f(%rip ), %rbp
50
+ movl %cs , %ebx
101
51
102
- /*
103
- * Switch to IDT and GDT with 32-bit segments. These are the firmware
104
- * GDT and IDT that were installed when the kernel started executing.
105
- * The pointers were saved by the efi32_entry() routine below.
106
- *
107
- * Pass the saved DS selector to the 32-bit code, and use far return to
108
- * restore the saved CS selector.
109
- */
110
- lidt efi32_boot_idt(%rip )
111
- lgdt efi32_boot_gdt(%rip )
112
-
113
- movzwl efi32_boot_ds(%rip ), %edx
114
- movzwq efi32_boot_cs(%rip ), %rax
115
- pushq %rax
116
- leaq efi_enter32(%rip ), %rax
117
- pushq %rax
118
- lretq
52
+ ljmpl *efi32_call(%rip )
119
53
120
54
1: addq $64 , %rsp
121
55
movq %rdi , %rax
122
56
123
- pop %rbx
124
- movl %ebx , %ss
125
- pop %rbx
126
- movl %ebx , %es
127
- pop %rbx
128
- movl %ebx , %ds
129
- /* Clear out 32-bit selector from FS and GS */
130
- xorl %ebx , %ebx
131
- movl %ebx , %fs
132
- movl %ebx , %gs
133
-
134
57
pop %rbx
135
58
pop %rbp
136
59
RET
@@ -141,7 +64,6 @@ SYM_FUNC_END(__efi64_thunk)
141
64
SYM_FUNC_START(efi32_stub_entry)
142
65
call 1f
143
66
1: popl %ecx
144
- leal (efi32_boot_args - 1b)(%ecx ), %ebx
145
67
146
68
/* Clear BSS */
147
69
xorl %eax , %eax
@@ -153,11 +75,8 @@ SYM_FUNC_START(efi32_stub_entry)
153
75
rep stosl
154
76
155
77
add $0x4 , %esp /* Discard return address */
156
- popl %ecx
157
- popl %edx
158
- popl %esi
159
- movl %esi , 8 (%ebx )
160
- jmp efi32_entry
78
+ movl 8 (%esp ), %ebx /* struct boot_params pointer */
79
+ jmp efi32_startup
161
80
SYM_FUNC_END(efi32_stub_entry)
162
81
#endif
163
82
@@ -167,13 +86,6 @@ SYM_FUNC_END(efi32_stub_entry)
167
86
* The stack should represent the 32-bit calling convention.
168
87
*/
169
88
SYM_FUNC_START_LOCAL (efi_enter32)
170
- /* Load firmware selector into data and stack segment registers */
171
- movl %edx , %ds
172
- movl %edx , %es
173
- movl %edx , %fs
174
- movl %edx , %gs
175
- movl %edx , %ss
176
-
177
89
/* Disable paging */
178
90
movl %cr0 , %eax
179
91
btrl $X86_CR0_PG_BIT, %eax
@@ -190,21 +102,9 @@ SYM_FUNC_START_LOCAL(efi_enter32)
190
102
/* We must preserve return value */
191
103
movl %eax , %edi
192
104
193
- /*
194
- * Some firmware will return with interrupts enabled. Be sure to
195
- * disable them before we switch GDTs and IDTs.
196
- */
197
- cli
198
-
199
- lidtl 16 (%ebx )
200
- lgdtl (%ebx )
201
-
202
- xorl %eax , %eax
203
- lldt %ax
204
-
205
105
call efi32_enable_long_mode
206
106
207
- pushl $__KERNEL_CS
107
+ pushl %ebx
208
108
pushl %ebp
209
109
lret
210
110
SYM_FUNC_END(efi_enter32)
@@ -230,50 +130,56 @@ SYM_FUNC_START_LOCAL(efi32_enable_long_mode)
230
130
SYM_FUNC_END(efi32_enable_long_mode)
231
131
232
132
/*
233
- * This is the common EFI stub entry point for mixed mode.
133
+ * This is the common EFI stub entry point for mixed mode. It sets up the GDT
134
+ * and page tables needed for 64-bit execution, after which it calls the
135
+ * common 64-bit EFI entrypoint efi_stub_entry().
234
136
*
235
- * Arguments: %ecx image handle
236
- * %edx EFI system table pointer
137
+ * Arguments: 0(%esp) image handle
138
+ * 4(%esp) EFI system table pointer
139
+ * %ebx struct boot_params pointer (or NULL)
237
140
*
238
141
* Since this is the point of no return for ordinary execution, no registers
239
142
* are considered live except for the function parameters. [Note that the EFI
240
143
* stub may still exit and return to the firmware using the Exit() EFI boot
241
144
* service.]
242
145
*/
243
- SYM_FUNC_START_LOCAL (efi32_entry)
244
- call 1f
245
- 1: pop %ebx
246
-
247
- /* Save firmware GDTR and code/data selectors */
248
- sgdtl (efi32_boot_gdt - 1b)(%ebx )
249
- movw %cs , (efi32_boot_cs - 1b)(%ebx )
250
- movw %ds , (efi32_boot_ds - 1b)(%ebx )
251
-
252
- /* Store firmware IDT descriptor */
253
- sidtl (efi32_boot_idt - 1b)(%ebx )
254
-
255
- /* Store firmware stack pointer */
256
- movl %esp , (efi32_boot_sp - 1b)(%ebx )
257
-
258
- /* Store boot arguments */
259
- leal (efi32_boot_args - 1b)(%ebx ), %ebx
260
- movl %ecx , 0 (%ebx )
261
- movl %edx , 4 (%ebx )
262
- movb $0x0 , 12 (%ebx ) // efi_is64
263
-
264
- /*
265
- * Allocate some memory for a temporary struct boot_params, which only
266
- * needs the minimal pieces that startup_32() relies on.
267
- */
268
- subl $PARAM_SIZE, %esp
269
- movl %esp , %esi
270
- movl $PAGE_SIZE, BP_kernel_alignment(%esi )
271
- movl $_end - 1b, BP_init_size(%esi )
272
- subl $startup_32 - 1b, BP_init_size(%esi )
146
+ SYM_FUNC_START_LOCAL (efi32_startup)
147
+ movl %esp , %ebp
148
+
149
+ subl $8 , %esp
150
+ sgdtl (%esp ) /* Save GDT descriptor to the stack */
151
+ movl 2 (%esp ), %esi /* Existing GDT pointer */
152
+ movzwl (%esp ), %ecx /* Existing GDT limit */
153
+ inc %ecx /* Existing GDT size */
154
+ andl $~7 , %ecx /* Ensure size is multiple of 8 */
155
+
156
+ subl %ecx , %esp /* Allocate new GDT */
157
+ andl $~15 , %esp /* Realign the stack */
158
+ movl %esp , %edi /* New GDT address */
159
+ leal 7 (%ecx ), %eax /* New GDT limit */
160
+ pushw %cx /* Push 64-bit CS (for LJMP below) */
161
+ pushl %edi /* Push new GDT address */
162
+ pushw %ax /* Push new GDT limit */
163
+
164
+ /* Copy GDT to the stack and add a 64-bit code segment at the end */
165
+ movl $GDT_ENTRY(DESC_CODE64, 0 , 0xfffff ) & 0xffffffff , (%edi ,%ecx )
166
+ movl $GDT_ENTRY(DESC_CODE64, 0 , 0xfffff ) >> 32 , 4 (%edi ,%ecx )
167
+ shrl $2 , %ecx
168
+ cld
169
+ rep movsl /* Copy the firmware GDT */
170
+ lgdtl (%esp ) /* Switch to the new GDT */
273
171
274
172
call 1f
275
173
1: pop %edi
276
174
175
+ /* Record mixed mode entry */
176
+ movb $0x0 , (efi_is64 - 1b)(%edi )
177
+
178
+ /* Set up indirect far call to re-enter 32-bit mode */
179
+ leal (efi32_call - 1b)(%edi ), %eax
180
+ addl %eax , (%eax )
181
+ movw %cs , 4 (%eax )
182
+
277
183
/* Disable paging */
278
184
movl %cr0 , %eax
279
185
btrl $X86_CR0_PG_BIT, %eax
@@ -297,8 +203,17 @@ SYM_FUNC_START_LOCAL(efi32_entry)
297
203
movl %edx , (%eax )
298
204
movl %eax , %cr3
299
205
300
- jmp startup_32
301
- SYM_FUNC_END(efi32_entry)
206
+ call efi32_enable_long_mode
207
+
208
+ /* Set up far jump to 64-bit mode (CS is already on the stack) */
209
+ leal (efi_stub_entry - 1b)(%edi ), %eax
210
+ movl %eax , 2 (%esp )
211
+
212
+ movl 0 (%ebp ), %edi
213
+ movl 4 (%ebp ), %esi
214
+ movl %ebx , %edx
215
+ ljmpl *2 (%esp )
216
+ SYM_FUNC_END(efi32_startup)
302
217
303
218
/*
304
219
* efi_status_t efi32_pe_entry(efi_handle_t image_handle,
@@ -313,10 +228,8 @@ SYM_FUNC_START(efi32_pe_entry)
313
228
btl $29 , %edx // check long mode bit
314
229
jnc 1f
315
230
leal 8 (%esp ), %esp // preserve stack alignment
316
- movl (%esp ), %ecx // image_handle
317
- movl 4 (%esp ), %edx // sys_table
318
- jmp efi32_entry // pass %ecx, %edx
319
- // no other registers remain live
231
+ xor %ebx , %ebx // no struct boot_params pointer
232
+ jmp efi32_startup // only ESP and EBX remain live
320
233
1: movl $0x80000003 , %eax // EFI_UNSUPPORTED
321
234
popl %ebx
322
235
RET
@@ -332,20 +245,10 @@ SYM_FUNC_END(efi64_stub_entry)
332
245
333
246
.data
334
247
.balign 8
335
- SYM_DATA_START_LOCAL (efi32_boot_gdt)
336
- .word 0
337
- .quad 0
338
- SYM_DATA_END(efi32_boot_gdt)
339
-
340
- SYM_DATA_START_LOCAL (efi32_boot_idt)
341
- .word 0
342
- .quad 0
343
- SYM_DATA_END(efi32_boot_idt)
344
-
345
- SYM_DATA_LOCAL (efi32_boot_cs, .word 0 )
346
- SYM_DATA_LOCAL (efi32_boot_ds, .word 0 )
347
- SYM_DATA_LOCAL (efi32_boot_sp, .long 0 )
348
- SYM_DATA_LOCAL (efi32_boot_args, .long 0 , 0 , 0 )
248
+ SYM_DATA_START_LOCAL (efi32_call)
249
+ .long efi_enter32 - .
250
+ .word 0x0
251
+ SYM_DATA_END(efi32_call)
349
252
SYM_DATA(efi_is64, .byte 1 )
350
253
351
254
.bss
0 commit comments