:: commit 2ef15c15e45fa929bdcb6df7084459f846343e63

mintsuki <mintsuki@protonmail.com> — 2023-01-14 11:49

parents: 3152b05a26

efi/chainload: Support passing of command lines. Addresses #244

diff --git a/CONFIG.md b/CONFIG.md
index b5cf75b0..34a326ba 100644
--- a/CONFIG.md
+++ b/CONFIG.md
@@ -95,7 +95,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 fb4e2b67..60a40d1e 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 24aa695b..c1066dfa 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;
@@ -231,6 +233,16 @@ noreturn void efi_chainload_file(char *config, struct file_handle *image) {
     if (!fb_init(&fbinfo, req_width, req_height, req_bpp))
         panic(true, "chainload: Unable to set video mode");
 
+    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];
@@ -273,6 +285,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 <stdnoreturn.h>
 
-noreturn void chainload(char *config);
+noreturn void chainload(char *config, char *cmdline);
 
 #if defined (UEFI)
 #include <fs/file.h>
-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 <lib/part.h>
 
 #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 <stdnoreturn.h>
 
-noreturn void chainload_next(char *config);
+noreturn void chainload_next(char *config, char *cmdline);
 
 #endif
tab: 248 wrap: offon