[PATCH v4 04/20] drivers: firmware: efi: use cmdline building function

Christophe Leroy
2021-04-02T15:18:05Z

Use cmdline building function in EFI.

EFI cannot use pr_err() and doesn't have a .init.data section,
so use the __cmdline_build() internal function and provides
both a source and a destination.

Remove the handling of too long command lines as it is handled
by the generic CMDLINE.

Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
v4: New
---
.../firmware/efi/libstub/efi-stub-helper.c | 35 ++++++++++---------
drivers/firmware/efi/libstub/efi-stub.c | 23 +++---------
drivers/firmware/efi/libstub/efistub.h | 2 +-
drivers/firmware/efi/libstub/x86-stub.c | 18 +++-------
4 files changed, 29 insertions(+), 49 deletions(-)

diff --git a/drivers/firmware/efi/libstub/efi-stub-helper.c b/drivers/firmware/efi/libstub/efi-stub-helper.c
index aa8da0a49829..9f60d471d650 100644
--- a/drivers/firmware/efi/libstub/efi-stub-helper.c
+++ b/drivers/firmware/efi/libstub/efi-stub-helper.c
@@ -13,6 +13,7 @@
#include <linux/efi.h>
#include <linux/kernel.h>
#include <linux/printk.h> /* For CONSOLE_LOGLEVEL_* */
+#include <linux/cmdline.h>
#include <asm/efi.h>
#include <asm/setup.h>

@@ -339,13 +340,13 @@ void efi_apply_loadoptions_quirk(const void **load_options, int *load_options_si
* Size of memory allocated return in *cmd_line_len.
* Returns NULL on error.
*/
-char *efi_convert_cmdline(efi_loaded_image_t *image, int *cmd_line_len)
+char *efi_convert_cmdline(efi_loaded_image_t *image)
{
const u16 *s2;
- unsigned long cmdline_addr = 0;
+ unsigned long cmdline_addr = 0, options_addr = 0;
int options_chars = efi_table_attr(image, load_options_size);
const u16 *options = efi_table_attr(image, load_options);
- int options_bytes = 0, safe_options_bytes = 0; /* UTF-8 bytes */
+ int options_bytes = 0; /* UTF-8 bytes */
bool in_quote = false;
efi_status_t status;

@@ -354,16 +355,12 @@ char *efi_convert_cmdline(efi_loaded_image_t *image, int *cmd_line_len)

if (options) {
s2 = options;
- while (options_bytes < COMMAND_LINE_SIZE && options_chars--) {
+ while (options_chars--) {
u16 c = *s2++;

if (c < 0x80) {
if (c == L'\0' || c == L'\n')
break;
- if (c == L'"')
- in_quote = !in_quote;
- else if (!in_quote && isspace((char)c))
- safe_options_bytes = options_bytes;

options_bytes++;
continue;
@@ -395,24 +392,30 @@ char *efi_convert_cmdline(efi_loaded_image_t *image, int *cmd_line_len)
}
}
}
- if (options_bytes >= COMMAND_LINE_SIZE) {
- options_bytes = safe_options_bytes;
- efi_err("Command line is too long: truncated to %d bytes\n",
- options_bytes);
- }
}

options_bytes++; /* NUL termination */

status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, options_bytes,
- (void **)&cmdline_addr);
+ (void **)&options_addr);
if (status != EFI_SUCCESS)
return NULL;

- snprintf((char *)cmdline_addr, options_bytes, "%.*ls",
+ snprintf((char *)options_addr, options_bytes, "%.*ls",
options_bytes - 1, options);

- *cmd_line_len = options_bytes;
+ status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, COMMAND_LINE_SIZE,
+ (void **)&cmdline_addr);
+ if (status != EFI_SUCCESS) {
+ efi_bs_call(free_pool, (void *)options_addr);
+ return NULL;
+ }
+
+ if (!__cmdline_build((char *)cmdline_addr, (char *)options_addr))
+ efi_err("Command line is too long\n");
+
+ efi_bs_call(free_pool, (void *)cmdline_addr);
+
return (char *)cmdline_addr;
}

diff --git a/drivers/firmware/efi/libstub/efi-stub.c b/drivers/firmware/efi/libstub/efi-stub.c
index 26e69788f27a..b79ee76f2e95 100644
--- a/drivers/firmware/efi/libstub/efi-stub.c
+++ b/drivers/firmware/efi/libstub/efi-stub.c
@@ -127,7 +127,6 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
unsigned long fdt_addr = 0; /* Original DTB */
unsigned long fdt_size = 0;
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;
@@ -165,29 +164,17 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
* 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);
+ cmdline_ptr = efi_convert_cmdline(image);
if (!cmdline_ptr) {
efi_err("getting command line via LOADED_IMAGE_PROTOCOL\n");
status = EFI_OUT_OF_RESOURCES;
goto fail;
}

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

efi_info("Booting Linux Kernel...\n");
diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h
index cde0a2ef507d..2f872c48b20b 100644
--- a/drivers/firmware/efi/libstub/efistub.h
+++ b/drivers/firmware/efi/libstub/efistub.h
@@ -780,7 +780,7 @@ void efi_free(unsigned long size, unsigned long addr);

void efi_apply_loadoptions_quirk(const void **load_options, int *load_options_size);

-char *efi_convert_cmdline(efi_loaded_image_t *image, int *cmd_line_len);
+char *efi_convert_cmdline(efi_loaded_image_t *image);

efi_status_t efi_get_memory_map(struct efi_boot_memmap *map);

diff --git a/drivers/firmware/efi/libstub/x86-stub.c b/drivers/firmware/efi/libstub/x86-stub.c
index 28659276b6ba..0f6a33149ef7 100644
--- a/drivers/firmware/efi/libstub/x86-stub.c
+++ b/drivers/firmware/efi/libstub/x86-stub.c
@@ -359,7 +359,6 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
struct setup_header *hdr;
void *image_base;
efi_guid_t proto = LOADED_IMAGE_PROTOCOL_GUID;
- int options_size = 0;
efi_status_t status;
char *cmdline_ptr;

@@ -404,7 +403,7 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
hdr->type_of_loader = 0x21;

/* Convert unicode cmdline to ascii */
- cmdline_ptr = efi_convert_cmdline(image, &options_size);
+ cmdline_ptr = efi_convert_cmdline(image);
if (!cmdline_ptr)
goto fail;

@@ -674,6 +673,8 @@ unsigned long efi_main(efi_handle_t handle,
unsigned long buffer_start, buffer_end;
struct setup_header *hdr = &boot_params->hdr;
efi_status_t status;
+ unsigned long cmdline_paddr = ((u64)hdr->cmd_line_ptr |
+ ((u64)boot_params->ext_cmd_line_ptr << 32));

efi_system_table = sys_table_arg;

@@ -735,22 +736,11 @@ unsigned long efi_main(efi_handle_t handle,
image_offset = 0;
}

-#ifdef CONFIG_CMDLINE_BOOL
- status = efi_parse_options(CONFIG_CMDLINE);
+ status = efi_parse_options((char *)cmdline_paddr);
if (status != EFI_SUCCESS) {
efi_err("Failed to parse options\n");
goto fail;
}
-#endif
- if (!IS_ENABLED(CONFIG_CMDLINE_FORCE)) {
- unsigned long cmdline_paddr = ((u64)hdr->cmd_line_ptr |
- ((u64)boot_params->ext_cmd_line_ptr << 32));
- status = efi_parse_options((char *)cmdline_paddr);
- if (status != EFI_SUCCESS) {
- efi_err("Failed to parse options\n");
- goto fail;
- }
- }

/*
* At this point, an initrd may already have been loaded by the
--
2.25.0