diff mbox series

[kvm-unit-tests,RFC,16/17] x86 UEFI: Add support for parameter passing

Message ID 20220303071907.650203-17-zhenzhong.duan@intel.com (mailing list archive)
State New, archived
Headers show
Series X86: TDX framework support | expand

Commit Message

Duan, Zhenzhong March 3, 2022, 7:19 a.m. UTC
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@intel.com>
Reviewed-by: Yu Zhang <yu.c.zhang@intel.com>
---
 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 mbox series

Patch

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