Skip to content

Commit a1b87d5

Browse files
ardbiesheuvelbp3tk0v
authored andcommitted
x86/efistub: Avoid legacy decompressor when doing EFI boot
The bare metal decompressor code was never really intended to run in a hosted environment such as the EFI boot services, and does a few things that are becoming problematic in the context of EFI boot now that the logo requirements are getting tighter: EFI executables will no longer be allowed to consist of a single executable section that is mapped with read, write and execute permissions if they are intended for use in a context where Secure Boot is enabled (and where Microsoft's set of certificates is used, i.e., every x86 PC built to run Windows). To avoid stepping on reserved memory before having inspected the E820 tables, and to ensure the correct placement when running a kernel build that is non-relocatable, the bare metal decompressor moves its own executable image to the end of the allocation that was reserved for it, in order to perform the decompression in place. This means the region in question requires both write and execute permissions, which either need to be given upfront (which EFI will no longer permit), or need to be applied on demand using the existing page fault handling framework. However, the physical placement of the kernel is usually randomized anyway, and even if it isn't, a dedicated decompression output buffer can be allocated anywhere in memory using EFI APIs when still running in the boot services, given that EFI support already implies a relocatable kernel. This means that decompression in place is never necessary, nor is moving the compressed image from one end to the other. Since EFI already maps all of memory 1:1, it is also unnecessary to create new page tables or handle page faults when decompressing the kernel. That means there is also no need to replace the special exception handlers for SEV. Generally, there is little need to do any of the things that the decompressor does beyond - initialize SEV encryption, if needed, - perform the 4/5 level paging switch, if needed, - decompress the kernel - relocate the kernel So do all of this from the EFI stub code, and avoid the bare metal decompressor altogether. Signed-off-by: Ard Biesheuvel <[email protected]> Signed-off-by: Borislav Petkov (AMD) <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 31c77a5 commit a1b87d5

File tree

7 files changed

+84
-191
lines changed

7 files changed

+84
-191
lines changed

arch/x86/boot/compressed/Makefile

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,11 @@ LDFLAGS_vmlinux += -z noexecstack
7474
ifeq ($(CONFIG_LD_IS_BFD),y)
7575
LDFLAGS_vmlinux += $(call ld-option,--no-warn-rwx-segments)
7676
endif
77+
ifeq ($(CONFIG_EFI_STUB),y)
78+
# ensure that the static EFI stub library will be pulled in, even if it is
79+
# never referenced explicitly from the startup code
80+
LDFLAGS_vmlinux += -u efi_pe_entry
81+
endif
7782
LDFLAGS_vmlinux += -T
7883

7984
hostprogs := mkpiggy

arch/x86/boot/compressed/efi_mixed.S

Lines changed: 0 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -269,19 +269,13 @@ SYM_FUNC_START_LOCAL(efi32_entry)
269269
jmp startup_32
270270
SYM_FUNC_END(efi32_entry)
271271

272-
#define ST32_boottime 60 // offsetof(efi_system_table_32_t, boottime)
273-
#define BS32_handle_protocol 88 // offsetof(efi_boot_services_32_t, handle_protocol)
274-
#define LI32_image_base 32 // offsetof(efi_loaded_image_32_t, image_base)
275-
276272
/*
277273
* efi_status_t efi32_pe_entry(efi_handle_t image_handle,
278274
* efi_system_table_32_t *sys_table)
279275
*/
280276
SYM_FUNC_START(efi32_pe_entry)
281277
pushl %ebp
282278
movl %esp, %ebp
283-
pushl %eax // dummy push to allocate loaded_image
284-
285279
pushl %ebx // save callee-save registers
286280
pushl %edi
287281

@@ -290,48 +284,8 @@ SYM_FUNC_START(efi32_pe_entry)
290284
movl $0x80000003, %eax // EFI_UNSUPPORTED
291285
jnz 2f
292286

293-
call 1f
294-
1: pop %ebx
295-
296-
/* Get the loaded image protocol pointer from the image handle */
297-
leal -4(%ebp), %eax
298-
pushl %eax // &loaded_image
299-
leal (loaded_image_proto - 1b)(%ebx), %eax
300-
pushl %eax // pass the GUID address
301-
pushl 8(%ebp) // pass the image handle
302-
303-
/*
304-
* Note the alignment of the stack frame.
305-
* sys_table
306-
* handle <-- 16-byte aligned on entry by ABI
307-
* return address
308-
* frame pointer
309-
* loaded_image <-- local variable
310-
* saved %ebx <-- 16-byte aligned here
311-
* saved %edi
312-
* &loaded_image
313-
* &loaded_image_proto
314-
* handle <-- 16-byte aligned for call to handle_protocol
315-
*/
316-
317-
movl 12(%ebp), %eax // sys_table
318-
movl ST32_boottime(%eax), %eax // sys_table->boottime
319-
call *BS32_handle_protocol(%eax) // sys_table->boottime->handle_protocol
320-
addl $12, %esp // restore argument space
321-
testl %eax, %eax
322-
jnz 2f
323-
324287
movl 8(%ebp), %ecx // image_handle
325288
movl 12(%ebp), %edx // sys_table
326-
movl -4(%ebp), %esi // loaded_image
327-
movl LI32_image_base(%esi), %esi // loaded_image->image_base
328-
leal (startup_32 - 1b)(%ebx), %ebp // runtime address of startup_32
329-
/*
330-
* We need to set the image_offset variable here since startup_32() will
331-
* use it before we get to the 64-bit efi_pe_entry() in C code.
332-
*/
333-
subl %esi, %ebp // calculate image_offset
334-
movl %ebp, (image_offset - 1b)(%ebx) // save image_offset
335289
xorl %esi, %esi
336290
jmp efi32_entry // pass %ecx, %edx, %esi
337291
// no other registers remain live
@@ -350,15 +304,6 @@ SYM_FUNC_START_NOALIGN(efi64_stub_entry)
350304
SYM_FUNC_END(efi64_stub_entry)
351305
#endif
352306

353-
.section ".rodata"
354-
/* EFI loaded image protocol GUID */
355-
.balign 4
356-
SYM_DATA_START_LOCAL(loaded_image_proto)
357-
.long 0x5b1b31a1
358-
.word 0x9562, 0x11d2
359-
.byte 0x8e, 0x3f, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b
360-
SYM_DATA_END(loaded_image_proto)
361-
362307
.data
363308
.balign 8
364309
SYM_DATA_START_LOCAL(efi32_boot_gdt)

arch/x86/boot/compressed/head_32.S

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -84,19 +84,6 @@ SYM_FUNC_START(startup_32)
8484

8585
#ifdef CONFIG_RELOCATABLE
8686
leal startup_32@GOTOFF(%edx), %ebx
87-
88-
#ifdef CONFIG_EFI_STUB
89-
/*
90-
* If we were loaded via the EFI LoadImage service, startup_32() will be at an
91-
* offset to the start of the space allocated for the image. efi_pe_entry() will
92-
* set up image_offset to tell us where the image actually starts, so that we
93-
* can use the full available buffer.
94-
* image_offset = startup_32 - image_base
95-
* Otherwise image_offset will be zero and has no effect on the calculations.
96-
*/
97-
subl image_offset@GOTOFF(%edx), %ebx
98-
#endif
99-
10087
movl BP_kernel_alignment(%esi), %eax
10188
decl %eax
10289
addl %eax, %ebx

arch/x86/boot/compressed/head_64.S

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -146,19 +146,6 @@ SYM_FUNC_START(startup_32)
146146

147147
#ifdef CONFIG_RELOCATABLE
148148
movl %ebp, %ebx
149-
150-
#ifdef CONFIG_EFI_STUB
151-
/*
152-
* If we were loaded via the EFI LoadImage service, startup_32 will be at an
153-
* offset to the start of the space allocated for the image. efi_pe_entry will
154-
* set up image_offset to tell us where the image actually starts, so that we
155-
* can use the full available buffer.
156-
* image_offset = startup_32 - image_base
157-
* Otherwise image_offset will be zero and has no effect on the calculations.
158-
*/
159-
subl rva(image_offset)(%ebp), %ebx
160-
#endif
161-
162149
movl BP_kernel_alignment(%esi), %eax
163150
decl %eax
164151
addl %eax, %ebx
@@ -335,20 +322,6 @@ SYM_CODE_START(startup_64)
335322
/* Start with the delta to where the kernel will run at. */
336323
#ifdef CONFIG_RELOCATABLE
337324
leaq startup_32(%rip) /* - $startup_32 */, %rbp
338-
339-
#ifdef CONFIG_EFI_STUB
340-
/*
341-
* If we were loaded via the EFI LoadImage service, startup_32 will be at an
342-
* offset to the start of the space allocated for the image. efi_pe_entry will
343-
* set up image_offset to tell us where the image actually starts, so that we
344-
* can use the full available buffer.
345-
* image_offset = startup_32 - image_base
346-
* Otherwise image_offset will be zero and has no effect on the calculations.
347-
*/
348-
movl image_offset(%rip), %eax
349-
subq %rax, %rbp
350-
#endif
351-
352325
movl BP_kernel_alignment(%rsi), %eax
353326
decl %eax
354327
addq %rax, %rbp

arch/x86/include/asm/efi.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ static inline void efi_fpu_end(void)
9090
}
9191

9292
#ifdef CONFIG_X86_32
93+
#define EFI_X86_KERNEL_ALLOC_LIMIT (SZ_512M - 1)
94+
9395
#define arch_efi_call_virt_setup() \
9496
({ \
9597
efi_fpu_begin(); \
@@ -103,8 +105,7 @@ static inline void efi_fpu_end(void)
103105
})
104106

105107
#else /* !CONFIG_X86_32 */
106-
107-
#define EFI_LOADER_SIGNATURE "EL64"
108+
#define EFI_X86_KERNEL_ALLOC_LIMIT EFI_ALLOC_LIMIT
108109

109110
extern asmlinkage u64 __efi_call(void *fp, ...);
110111

@@ -218,6 +219,8 @@ efi_status_t efi_set_virtual_address_map(unsigned long memory_map_size,
218219

219220
#ifdef CONFIG_EFI_MIXED
220221

222+
#define EFI_ALLOC_LIMIT (efi_is_64bit() ? ULONG_MAX : U32_MAX)
223+
221224
#define ARCH_HAS_EFISTUB_WRAPPERS
222225

223226
static inline bool efi_is_64bit(void)

arch/x86/include/asm/sev.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ static __always_inline void sev_es_nmi_complete(void)
164164
__sev_es_nmi_complete();
165165
}
166166
extern int __init sev_es_efi_map_ghcbs(pgd_t *pgd);
167+
extern void sev_enable(struct boot_params *bp);
167168

168169
static inline int rmpadjust(unsigned long vaddr, bool rmp_psize, unsigned long attrs)
169170
{
@@ -218,6 +219,7 @@ static inline void sev_es_ist_exit(void) { }
218219
static inline int sev_es_setup_ap_jump_table(struct real_mode_header *rmh) { return 0; }
219220
static inline void sev_es_nmi_complete(void) { }
220221
static inline int sev_es_efi_map_ghcbs(pgd_t *pgd) { return 0; }
222+
static inline void sev_enable(struct boot_params *bp) { }
221223
static inline int pvalidate(unsigned long vaddr, bool rmp_psize, bool validate) { return 0; }
222224
static inline int rmpadjust(unsigned long vaddr, bool rmp_psize, unsigned long attrs) { return 0; }
223225
static inline void setup_ghcb(void) { }

0 commit comments

Comments
 (0)