Skip to content

Commit

Permalink
efi: libstub: Factor out EFI stub entrypoint into separate file
Browse files Browse the repository at this point in the history
In preparation for allowing the EFI zboot decompressor to reuse most of
the EFI stub machinery, factor out the actual EFI PE/COFF entrypoint
into a separate file.

Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
  • Loading branch information
Ard Biesheuvel committed Nov 9, 2022
1 parent da8dd0c commit 42c8ea3
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 64 deletions.
2 changes: 1 addition & 1 deletion drivers/firmware/efi/libstub/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ $(obj)/lib-%.o: $(srctree)/lib/%.c FORCE
$(call if_changed_rule,cc_o_c)

lib-$(CONFIG_EFI_GENERIC_STUB) += efi-stub.o string.o intrinsics.o systable.o \
screen_info.o
screen_info.o efi-stub-entry.o

lib-$(CONFIG_ARM) += arm32-stub.o
lib-$(CONFIG_ARM64) += arm64-stub.o arm64-entry.o
Expand Down
65 changes: 65 additions & 0 deletions drivers/firmware/efi/libstub/efi-stub-entry.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// SPDX-License-Identifier: GPL-2.0-only

#include <linux/efi.h>
#include <asm/efi.h>

#include "efistub.h"

/*
* EFI entry point for the generic EFI stub used by ARM, arm64, RISC-V and
* LoongArch. This is the entrypoint that is described in the PE/COFF header
* of the core kernel.
*/
efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
efi_system_table_t *systab)
{
efi_loaded_image_t *image;
efi_status_t status;
unsigned long image_addr;
unsigned long image_size = 0;
/* addr/point and size pairs for memory management*/
char *cmdline_ptr = NULL;
efi_guid_t loaded_image_proto = LOADED_IMAGE_PROTOCOL_GUID;
unsigned long reserve_addr = 0;
unsigned long reserve_size = 0;

WRITE_ONCE(efi_system_table, systab);

/* Check if we were booted by the EFI firmware */
if (efi_system_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
return EFI_INVALID_PARAMETER;

/*
* Get a handle to the loaded image protocol. This is used to get
* information about the running image, such as size and the command
* line.
*/
status = efi_bs_call(handle_protocol, handle, &loaded_image_proto,
(void *)&image);
if (status != EFI_SUCCESS) {
efi_err("Failed to get loaded image protocol\n");
return status;
}

status = efi_handle_cmdline(image, &cmdline_ptr);
if (status != EFI_SUCCESS)
return status;

efi_info("Booting Linux Kernel...\n");

status = handle_kernel_image(&image_addr, &image_size,
&reserve_addr,
&reserve_size,
image, handle);
if (status != EFI_SUCCESS) {
efi_err("Failed to relocate kernel\n");
return status;
}

status = efi_stub_common(handle, image, image_addr, cmdline_ptr);

efi_free(image_size, image_addr);
efi_free(reserve_size, reserve_addr);

return status;
}
89 changes: 26 additions & 63 deletions drivers/firmware/efi/libstub/efi-stub.c
Original file line number Diff line number Diff line change
Expand Up @@ -115,61 +115,21 @@ static u32 get_supported_rt_services(void)
return supported;
}

/*
* EFI entry point for the arm/arm64 EFI stubs. This is the entrypoint
* that is described in the PE/COFF header. Most of the code is the same
* for both archictectures, with the arch-specific code provided in the
* handle_kernel_image() function.
*/
efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
efi_system_table_t *sys_table_arg)
efi_status_t efi_handle_cmdline(efi_loaded_image_t *image, char **cmdline_ptr)
{
efi_loaded_image_t *image;
efi_status_t status;
unsigned long image_addr;
unsigned long image_size = 0;
/* addr/point and size pairs for memory management*/
char *cmdline_ptr = NULL;
int cmdline_size = 0;
efi_guid_t loaded_image_proto = LOADED_IMAGE_PROTOCOL_GUID;
unsigned long reserve_addr = 0;
unsigned long reserve_size = 0;
struct screen_info *si;

efi_system_table = sys_table_arg;

/* Check if we were booted by the EFI firmware */
if (efi_system_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) {
status = EFI_INVALID_PARAMETER;
goto fail;
}

status = check_platform_features();
if (status != EFI_SUCCESS)
goto fail;

/*
* Get a handle to the loaded image protocol. This is used to get
* information about the running image, such as size and the command
* line.
*/
status = efi_bs_call(handle_protocol, handle, &loaded_image_proto,
(void *)&image);
if (status != EFI_SUCCESS) {
efi_err("Failed to get loaded image protocol\n");
goto fail;
}
efi_status_t status;
char *cmdline;

/*
* Get the command line from EFI, using the LOADED_IMAGE
* protocol. We are going to copy the command line into the
* device tree, so this can be allocated anywhere.
*/
cmdline_ptr = efi_convert_cmdline(image, &cmdline_size);
if (!cmdline_ptr) {
cmdline = efi_convert_cmdline(image, &cmdline_size);
if (!cmdline) {
efi_err("getting command line via LOADED_IMAGE_PROTOCOL\n");
status = EFI_OUT_OF_RESOURCES;
goto fail;
return EFI_OUT_OF_RESOURCES;
}

if (IS_ENABLED(CONFIG_CMDLINE_EXTEND) ||
Expand All @@ -183,25 +143,34 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
}

if (!IS_ENABLED(CONFIG_CMDLINE_FORCE) && cmdline_size > 0) {
status = efi_parse_options(cmdline_ptr);
status = efi_parse_options(cmdline);
if (status != EFI_SUCCESS) {
efi_err("Failed to parse options\n");
goto fail_free_cmdline;
}
}

efi_info("Booting Linux Kernel...\n");
*cmdline_ptr = cmdline;
return EFI_SUCCESS;

si = setup_graphics();
fail_free_cmdline:
efi_bs_call(free_pool, cmdline_ptr);
return status;
}

status = handle_kernel_image(&image_addr, &image_size,
&reserve_addr,
&reserve_size,
image, handle);
if (status != EFI_SUCCESS) {
efi_err("Failed to relocate kernel\n");
goto fail_free_screeninfo;
}
efi_status_t efi_stub_common(efi_handle_t handle,
efi_loaded_image_t *image,
unsigned long image_addr,
char *cmdline_ptr)
{
struct screen_info *si;
efi_status_t status;

status = check_platform_features();
if (status != EFI_SUCCESS)
return status;

si = setup_graphics();

efi_retrieve_tpm2_eventlog();

Expand All @@ -221,13 +190,7 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,

status = efi_boot_kernel(handle, image, image_addr, cmdline_ptr);

efi_free(image_size, image_addr);
efi_free(reserve_size, reserve_addr);
fail_free_screeninfo:
free_screen_info(si);
fail_free_cmdline:
efi_bs_call(free_pool, cmdline_ptr);
fail:
return status;
}

Expand Down
8 changes: 8 additions & 0 deletions drivers/firmware/efi/libstub/efistub.h
Original file line number Diff line number Diff line change
Expand Up @@ -958,6 +958,14 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
efi_loaded_image_t *image,
efi_handle_t image_handle);

/* shared entrypoint between the normal stub and the zboot stub */
efi_status_t efi_stub_common(efi_handle_t handle,
efi_loaded_image_t *image,
unsigned long image_addr,
char *cmdline_ptr);

efi_status_t efi_handle_cmdline(efi_loaded_image_t *image, char **cmdline_ptr);

asmlinkage void __noreturn efi_enter_kernel(unsigned long entrypoint,
unsigned long fdt_addr,
unsigned long fdt_size);
Expand Down

0 comments on commit 42c8ea3

Please sign in to comment.