From ac1c5d1b9578041a7f93db72d526ed66fcd3edcd Mon Sep 17 00:00:00 2001 From: mintsuki Date: Sat, 14 Jan 2023 12:49:22 +0100 Subject: [PATCH] efi/chainload: Support passing of command lines. Addresses #244 --- CONFIG.md | 2 +- common/menu.c | 4 ++-- common/protos/chainload.c | 23 +++++++++++++++++++---- common/protos/chainload.h | 4 ++-- common/protos/chainload_next.c | 13 +++++++------ common/protos/chainload_next.h | 2 +- 6 files changed, 32 insertions(+), 16 deletions(-) diff --git a/CONFIG.md b/CONFIG.md index 3bc6d24a..e3fd2a4f 100644 --- a/CONFIG.md +++ b/CONFIG.md @@ -97,7 +97,7 @@ Editor control options. *Locally assignable (non protocol specific)* keys are: * `COMMENT` - An optional comment string that will be displayed by the bootloader on the menu when an entry is selected. * `PROTOCOL` - The boot protocol that will be used to boot the kernel. Valid protocols are: `linux`, `limine`, `chainload`, `chainload_next`, `multiboot` (or `multiboot1`), and `multiboot2`. -* `CMDLINE` - The command line string to be passed to the kernel. Can be omitted. +* `CMDLINE` - The command line string to be passed to the kernel/executable. Can be omitted. * `KERNEL_CMDLINE` - Alias of `CMDLINE`. *Locally assignable (protocol specific)* keys are: diff --git a/common/menu.c b/common/menu.c index fe7a6a64..c8bd5bc8 100644 --- a/common/menu.c +++ b/common/menu.c @@ -975,9 +975,9 @@ noreturn void boot(char *config) { print("Multiboot 2 is not available on aarch64.\n\n"); #endif } else if (!strcmp(proto, "chainload_next")) { - chainload_next(config); + chainload_next(config, cmdline); } else if (!strcmp(proto, "chainload")) { - chainload(config); + chainload(config, cmdline); } panic(true, "Unsupported protocol specified for kernel."); diff --git a/common/protos/chainload.c b/common/protos/chainload.c index 3d4ddbdf..5e0040dd 100644 --- a/common/protos/chainload.c +++ b/common/protos/chainload.c @@ -72,7 +72,9 @@ noreturn static void spinup(uint8_t drive) { __builtin_unreachable(); } -noreturn void chainload(char *config) { +noreturn void chainload(char *config, char *cmdline) { + (void)cmdline; + uint64_t val; int part; { @@ -188,7 +190,7 @@ void bios_chainload_volume(struct volume *p) { #elif defined (UEFI) -noreturn void chainload(char *config) { +noreturn void chainload(char *config, char *cmdline) { char *image_path = config_get_value(config, 0, "IMAGE_PATH"); if (image_path == NULL) panic(true, "chainload: IMAGE_PATH not specified"); @@ -197,10 +199,10 @@ noreturn void chainload(char *config) { if ((image = uri_open(image_path)) == NULL) panic(true, "chainload: Failed to open image with path `%s`. Is the path correct?", image_path); - efi_chainload_file(config, image); + efi_chainload_file(config, cmdline, image); } -noreturn void efi_chainload_file(char *config, struct file_handle *image) { +noreturn void efi_chainload_file(char *config, char *cmdline, struct file_handle *image) { EFI_STATUS status; EFI_HANDLE efi_part_handle = image->efi_part_handle; @@ -228,6 +230,16 @@ noreturn void efi_chainload_file(char *config, struct file_handle *image) { size_t fb_count; fb_init(&fbinfo, &fb_count, req_width, req_height, req_bpp); + size_t cmdline_len = strlen(cmdline); + CHAR16 *new_cmdline; + status = gBS->AllocatePool(EfiLoaderData, cmdline_len * sizeof(CHAR16), (void **)&new_cmdline); + if (status) { + panic(true, "chainload: Allocation failure"); + } + for (size_t i = 0; i < cmdline_len + 1; i++) { + new_cmdline[i] = cmdline[i]; + } + pmm_release_uefi_mem(); MEMMAP_DEVICE_PATH memdev_path[2]; @@ -270,6 +282,9 @@ noreturn void efi_chainload_file(char *config, struct file_handle *image) { new_handle_loaded_image->DeviceHandle = efi_part_handle; } + new_handle_loaded_image->LoadOptionsSize = cmdline_len; + new_handle_loaded_image->LoadOptions = new_cmdline; + UINTN exit_data_size = 0; CHAR16 *exit_data = NULL; EFI_STATUS exit_status = gBS->StartImage(new_handle, &exit_data_size, &exit_data); diff --git a/common/protos/chainload.h b/common/protos/chainload.h index b930e897..cb0bce69 100644 --- a/common/protos/chainload.h +++ b/common/protos/chainload.h @@ -3,11 +3,11 @@ #include -noreturn void chainload(char *config); +noreturn void chainload(char *config, char *cmdline); #if defined (UEFI) #include -noreturn void efi_chainload_file(char *config, struct file_handle *image); +noreturn void efi_chainload_file(char *config, char *cmdline, struct file_handle *image); #endif #if defined (BIOS) diff --git a/common/protos/chainload_next.c b/common/protos/chainload_next.c index 4d4b5a19..09e39b39 100644 --- a/common/protos/chainload_next.c +++ b/common/protos/chainload_next.c @@ -8,14 +8,15 @@ #include #if defined (BIOS) -static void try(char *config, struct volume *v) { +static void try(char *config, char *cmdline, struct volume *v) { (void)config; + (void)cmdline; bios_chainload_volume(v); } #endif #if defined (UEFI) -static void try(char *config, struct volume *v) { +static void try(char *config, char *cmdline, struct volume *v) { for (int i = 0; i <= v->max_partition + 1; i++) { struct file_handle *image; struct volume *p = volume_get_by_coord(v->is_optical, v->index, i); @@ -28,12 +29,12 @@ static void try(char *config, struct volume *v) { } case_insensitive_fopen = old_cif; - efi_chainload_file(config, image); + efi_chainload_file(config, cmdline, image); } } #endif -noreturn void chainload_next(char *config) { +noreturn void chainload_next(char *config, char *cmdline) { bool wrap = false; for (int i = boot_volume->is_optical ? 0 : (wrap = true, boot_volume->index + 1); boot_volume->is_optical ? true : i != boot_volume->index; i++) { @@ -47,7 +48,7 @@ noreturn void chainload_next(char *config) { } } - try(config, v); + try(config, cmdline, v); } wrap = false; @@ -63,7 +64,7 @@ noreturn void chainload_next(char *config) { } } - try(config, v); + try(config, cmdline, v); } panic(true, "chainload_next: No other bootable device"); diff --git a/common/protos/chainload_next.h b/common/protos/chainload_next.h index 61d2be0f..2f4a4e26 100644 --- a/common/protos/chainload_next.h +++ b/common/protos/chainload_next.h @@ -3,6 +3,6 @@ #include -noreturn void chainload_next(char *config); +noreturn void chainload_next(char *config, char *cmdline); #endif