UEFI supports command line in unicode format, translate it into ascii format and pass to main() as parameters. Only support general characters with ascii < 0x80. Signed-off-by: Zhenzhong Duan <zhenzhong.duan@xxxxxxxxx> Reviewed-by: Yu Zhang <yu.c.zhang@xxxxxxxxx> --- lib/argv.c | 2 +- lib/argv.h | 1 + lib/efi.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++ lib/linux/efi.h | 18 ++++++++++++ 4 files changed, 93 insertions(+), 1 deletion(-) diff --git a/lib/argv.c b/lib/argv.c index 0312d74011d3..4d5c318a4bc4 100644 --- a/lib/argv.c +++ b/lib/argv.c @@ -44,7 +44,7 @@ void __setup_args(void) __argc = argv - __argv; } -static void setup_args(const char *args) +void setup_args(const char *args) { if (!args) return; diff --git a/lib/argv.h b/lib/argv.h index 1fd746dc2177..0fa7772549da 100644 --- a/lib/argv.h +++ b/lib/argv.h @@ -9,6 +9,7 @@ #define _ARGV_H_ extern void __setup_args(void); +extern void setup_args(const char *args); extern void setup_args_progname(const char *args); extern void setup_env(char *env, int size); extern void add_setup_arg(const char *arg); diff --git a/lib/efi.c b/lib/efi.c index 64cc9789274e..69dbfa1d1f24 100644 --- a/lib/efi.c +++ b/lib/efi.c @@ -10,6 +10,7 @@ #include "efi.h" #include <libcflat.h> #include <asm/setup.h> +#include <argv.h> /* From lib/argv.c */ extern int __argc, __envc; @@ -96,6 +97,72 @@ static void efi_exit(efi_status_t code) efi_rs_call(reset_system, EFI_RESET_SHUTDOWN, code, 0, NULL); } +/* + * Convert the unicode UEFI command line to ASCII, only support ascii < 0x80. + * Size of memory allocated return in *cmd_line_len. + */ +static efi_status_t efi_convert_cmdline(efi_loaded_image_t *image, + char **cmd_line_ptr, int *cmd_line_len) +{ + char *cmdline_addr = 0; + int options_chars = image->load_options_size; + const u16 *options = image->load_options; + int options_bytes = 0; + efi_status_t status; + + if (!options || !options_chars) + return EFI_NOT_FOUND; + + options_chars /= sizeof(*options); + status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, options_chars + 1, + (void **)&cmdline_addr); + if (status != EFI_SUCCESS) + return status; + + while (options_bytes < options_chars) { + if (options[options_bytes] >= 0x80) + return EFI_UNSUPPORTED; + + cmdline_addr[options_bytes] = (char)options[options_bytes]; + options_bytes++; + } + + /* + * UEFI command line should already includes NUL termination, + * just in case. + */ + cmdline_addr[options_bytes] = '\0'; + + *cmd_line_len = options_bytes; + *cmd_line_ptr = (char *)cmdline_addr; + return EFI_SUCCESS; +} + +static efi_status_t setup_efi_args(efi_handle_t handle) +{ + efi_guid_t proto = LOADED_IMAGE_PROTOCOL_GUID; + efi_loaded_image_t *image = NULL; + char *cmdline_ptr; + int options_size = 0; + efi_status_t status; + + status = efi_bs_call(handle_protocol, handle, &proto, (void **)&image); + if (status != EFI_SUCCESS) { + printf("Failed to get handle for LOADED_IMAGE_PROTOCOL\n"); + return status; + } + + status = efi_convert_cmdline(image, &cmdline_ptr, &options_size); + + if (status != EFI_SUCCESS && status != EFI_NOT_FOUND) + return status; + + if (status == EFI_SUCCESS) + setup_args(cmdline_ptr); + + return EFI_SUCCESS; +} + efi_status_t efi_main(efi_handle_t handle, efi_system_table_t *sys_tab) { int ret; @@ -104,6 +171,12 @@ efi_status_t efi_main(efi_handle_t handle, efi_system_table_t *sys_tab) efi_system_table = sys_tab; + status = setup_efi_args(handle); + if (status != EFI_SUCCESS) { + printf("Failed to get efi parameters\n"); + goto efi_main_error; + } + /* Memory map struct values */ efi_memory_desc_t *map = NULL; unsigned long map_size = 0, desc_size = 0, key = 0, buff_size = 0; diff --git a/lib/linux/efi.h b/lib/linux/efi.h index df9fa7974d87..8b9fa06f84ba 100644 --- a/lib/linux/efi.h +++ b/lib/linux/efi.h @@ -59,6 +59,7 @@ typedef guid_t efi_guid_t; (c) & 0xff, ((c) >> 8) & 0xff, d } } #define ACPI_TABLE_GUID EFI_GUID(0xeb9d2d30, 0x2d88, 0x11d3, 0x9a, 0x16, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d) +#define LOADED_IMAGE_PROTOCOL_GUID EFI_GUID(0x5b1b31a1, 0x9562, 0x11d2, 0x8e, 0x3f, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b) typedef struct { efi_guid_t guid; @@ -417,6 +418,23 @@ struct efi_boot_memmap { unsigned long *buff_size; }; +#define __aligned_u64 u64 __attribute__((aligned(8))) +typedef struct { + u32 revision; + efi_handle_t parent_handle; + efi_system_table_t *system_table; + efi_handle_t device_handle; + void *file_path; + void *reserved; + u32 load_options_size; + void *load_options; + void *image_base; + __aligned_u64 image_size; + unsigned int image_code_type; + unsigned int image_data_type; + efi_status_t (__efiapi *unload)(efi_handle_t image_handle); +} efi_loaded_image_t; + /* * efi_memdesc_ptr - get the n-th EFI memmap descriptor * @map: the start of efi memmap -- 2.25.1