Pull request for UEFI sub-system for efi-2021-04-rc1-2
* Provide a test tool for initial RAM disk provided via load file2 protocol. * Make more items configurable to reduce code size: * Boot manager * EFI_DT_FIXUP_PROTOCOL * EFI_DEVICE_PATH_UTILITIES_PROTOCOL * Bug fixes * avoid EFI runtime symbols in global symbol table -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEbcT5xx8ppvoGt20zxIHbvCwFGsQFAmAIHfIACgkQxIHbvCwF GsSz8g/+No9xNYiAK1pY0Fjus6ZSfBhMCY9NGwkEkyzFwXZG+ckmlWwMd+auk8Oz noU5vVBkr4JdrdpACdgiCdCeAfsYwxPy7/GulgVMLpptMlrLfbOhA/n7uOzhAilV QDt3BouOuvW+sVlxoxD2FNkpw4vFS6CasFgBj1+tWunARoXqIRxD4MbFp1zwApHb qC67jomsDS6MvQtrebZ3Erqkp67W0RVtD6X4KGq8+6g+8akVAan5zl7/gPj9Z8h6 M1AXG/pLqDMrG+3RFGMyqncPOlxPVL85BQAAJVB8/SQcAQ726R4z/ia+3VBFBWWf N9rmzNJ9KnbAr3OHZnfqYITe/E2xgiRVqTYl5IL8701E41qhEjRiBWFF+U+QG/8b 3IByp4FZXVbVxjsjK8dIi5aTmBvznwb0HcrlcbwJRonTvBCBOZCVIoAn2PalZUFW 4zc4hGaoWVTdwRXaiiQKQuAfA52B3tfPqfWyUsm1E+crf/JYngstQe4A88FDorV6 ozISWNXb5RzYdNluewJl2c1rfWcUiWHbbnKMt+YbDvE4OTy6lbJC9oY0mNfPE7nK 7cq/Tk8WNhrMIv95nqzDBCv78naa0iQF5P+tHk6/r3IJ/wFFyD6f4ZvGijvCK+9o vgnmK0kz9Qd53m+g4L54xpTsyoCXaU2N9zzD1QgwV3HjW2JyjxY= =yVF7 -----END PGP SIGNATURE----- Merge tag 'efi-2021-04-rc1-2' of https://gitlab.denx.de/u-boot/custodians/u-boot-efi Pull request for UEFI sub-system for efi-2021-04-rc1-2 * Provide a test tool for initial RAM disk provided via load file2 protocol. * Make more items configurable to reduce code size: * Boot manager * EFI_DT_FIXUP_PROTOCOL * EFI_DEVICE_PATH_UTILITIES_PROTOCOL * Bug fixes * avoid EFI runtime symbols in global symbol table
This commit is contained in:
commit
404bbc809d
@ -631,10 +631,12 @@ static int do_bootefi(struct cmd_tbl *cmdtp, int flag, int argc,
|
||||
else if (ret != EFI_SUCCESS)
|
||||
return CMD_RET_FAILURE;
|
||||
|
||||
if (!strcmp(argv[1], "bootmgr"))
|
||||
return do_efibootmgr();
|
||||
if (IS_ENABLED(CONFIG_CMD_BOOTEFI_BOOTMGR)) {
|
||||
if (!strcmp(argv[1], "bootmgr"))
|
||||
return do_efibootmgr();
|
||||
}
|
||||
#ifdef CONFIG_CMD_BOOTEFI_SELFTEST
|
||||
else if (!strcmp(argv[1], "selftest"))
|
||||
if (!strcmp(argv[1], "selftest"))
|
||||
return do_efi_selftest();
|
||||
#endif
|
||||
|
||||
@ -657,11 +659,14 @@ static char bootefi_help_text[] =
|
||||
" Use environment variable efi_selftest to select a single test.\n"
|
||||
" Use 'setenv efi_selftest list' to enumerate all tests.\n"
|
||||
#endif
|
||||
#ifdef CONFIG_CMD_BOOTEFI_BOOTMGR
|
||||
"bootefi bootmgr [fdt address]\n"
|
||||
" - load and boot EFI payload based on BootOrder/BootXXXX variables.\n"
|
||||
"\n"
|
||||
" If specified, the device tree located at <fdt address> gets\n"
|
||||
" exposed as EFI configuration table.\n";
|
||||
" exposed as EFI configuration table.\n"
|
||||
#endif
|
||||
;
|
||||
#endif
|
||||
|
||||
U_BOOT_CMD(
|
||||
|
@ -1367,8 +1367,8 @@ static int do_efi_boot_opt(struct cmd_tbl *cmdtp, int flag,
|
||||
*
|
||||
* efidebug test bootmgr
|
||||
*/
|
||||
static int do_efi_test_bootmgr(struct cmd_tbl *cmdtp, int flag,
|
||||
int argc, char * const argv[])
|
||||
static __maybe_unused int do_efi_test_bootmgr(struct cmd_tbl *cmdtp, int flag,
|
||||
int argc, char * const argv[])
|
||||
{
|
||||
efi_handle_t image;
|
||||
efi_uintn_t exit_data_size = 0;
|
||||
@ -1392,8 +1392,10 @@ static int do_efi_test_bootmgr(struct cmd_tbl *cmdtp, int flag,
|
||||
}
|
||||
|
||||
static struct cmd_tbl cmd_efidebug_test_sub[] = {
|
||||
#ifdef CONFIG_CMD_BOOTEFI_BOOTMGR
|
||||
U_BOOT_CMD_MKENT(bootmgr, CONFIG_SYS_MAXARGS, 1, do_efi_test_bootmgr,
|
||||
"", ""),
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1581,8 +1583,10 @@ static char efidebug_help_text[] =
|
||||
" - show UEFI memory map\n"
|
||||
"efidebug tables\n"
|
||||
" - show UEFI configuration tables\n"
|
||||
#ifdef CONFIG_CMD_BOOTEFI_BOOTMGR
|
||||
"efidebug test bootmgr\n"
|
||||
" - run simple bootmgr for test\n"
|
||||
#endif
|
||||
"efidebug query [-nv][-bs][-rt][-at]\n"
|
||||
" - show size of UEFI variables store\n";
|
||||
#endif
|
||||
|
@ -123,14 +123,20 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#define BOOTENV_SHARED_EFI \
|
||||
#ifdef CONFIG_CMD_BOOTEFI_BOOTMGR
|
||||
#define BOOTENV_EFI_BOOTMGR \
|
||||
"boot_efi_bootmgr=" \
|
||||
"if fdt addr ${fdt_addr_r}; then " \
|
||||
"bootefi bootmgr ${fdt_addr_r};" \
|
||||
"else " \
|
||||
"bootefi bootmgr;" \
|
||||
"fi\0" \
|
||||
"fi\0"
|
||||
#else
|
||||
#define BOOTENV_EFI_BOOTMGR
|
||||
#endif
|
||||
|
||||
#define BOOTENV_SHARED_EFI \
|
||||
BOOTENV_EFI_BOOTMGR \
|
||||
\
|
||||
"boot_efi_binary=" \
|
||||
"load ${devtype} ${devnum}:${distro_bootpart} " \
|
||||
|
@ -1693,10 +1693,6 @@ struct efi_driver_binding_protocol {
|
||||
efi_handle_t driver_binding_handle;
|
||||
};
|
||||
|
||||
/* Deprecated version of the Unicode collation protocol */
|
||||
#define EFI_UNICODE_COLLATION_PROTOCOL_GUID \
|
||||
EFI_GUID(0x1d85cd7f, 0xf43d, 0x11d2, \
|
||||
0x9a, 0x0c, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d)
|
||||
/* Current version of the Unicode collation protocol */
|
||||
#define EFI_UNICODE_COLLATION_PROTOCOL2_GUID \
|
||||
EFI_GUID(0xa4c751fc, 0x23ae, 0x4c3e, \
|
||||
|
@ -147,9 +147,6 @@ extern const struct efi_device_path_to_text_protocol efi_device_path_to_text;
|
||||
/* implementation of the EFI_DEVICE_PATH_UTILITIES_PROTOCOL */
|
||||
extern const struct efi_device_path_utilities_protocol
|
||||
efi_device_path_utilities;
|
||||
/* deprecated version of the EFI_UNICODE_COLLATION_PROTOCOL */
|
||||
extern const struct efi_unicode_collation_protocol
|
||||
efi_unicode_collation_protocol;
|
||||
/* current version of the EFI_UNICODE_COLLATION_PROTOCOL */
|
||||
extern const struct efi_unicode_collation_protocol
|
||||
efi_unicode_collation_protocol2;
|
||||
@ -564,7 +561,7 @@ struct efi_file_handle *efi_file_from_path(struct efi_device_path *fp);
|
||||
* @size: size in bytes
|
||||
* Return: size in pages
|
||||
*/
|
||||
#define efi_size_in_pages(size) ((size + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT)
|
||||
#define efi_size_in_pages(size) (((size) + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT)
|
||||
/* Generic EFI memory allocator, call this to get memory */
|
||||
void *efi_alloc(uint64_t len, int memory_type);
|
||||
/* More specific EFI memory allocator, called by EFI payloads */
|
||||
|
@ -306,4 +306,15 @@ efi_status_t __efi_runtime EFIAPI
|
||||
efi_get_next_variable_name_runtime(efi_uintn_t *variable_name_size,
|
||||
u16 *variable_name, efi_guid_t *guid);
|
||||
|
||||
/**
|
||||
* efi_var_buf_update() - udpate memory buffer for variables
|
||||
*
|
||||
* @var_buf: source buffer
|
||||
*
|
||||
* This function copies to the memory buffer for UEFI variables. Call this
|
||||
* function in ExitBootServices() if memory backed variables are only used
|
||||
* at runtime to fill the buffer.
|
||||
*/
|
||||
void efi_var_buf_update(struct efi_var_file *var_buf);
|
||||
|
||||
#endif
|
||||
|
@ -27,6 +27,14 @@ config EFI_LOADER
|
||||
|
||||
if EFI_LOADER
|
||||
|
||||
config CMD_BOOTEFI_BOOTMGR
|
||||
bool "UEFI Boot Manager"
|
||||
default y
|
||||
help
|
||||
Select this option if you want to select the UEFI binary to be booted
|
||||
via UEFI variables Boot####, BootOrder, and BootNext. This enables the
|
||||
'bootefi bootmgr' command.
|
||||
|
||||
config EFI_SETUP_EARLY
|
||||
bool
|
||||
default n
|
||||
@ -200,6 +208,21 @@ config EFI_DEVICE_PATH_TO_TEXT
|
||||
The device path to text protocol converts device nodes and paths to
|
||||
human readable strings.
|
||||
|
||||
config EFI_DEVICE_PATH_UTIL
|
||||
bool "Device path utilities protocol"
|
||||
default y
|
||||
help
|
||||
The device path utilities protocol creates and manipulates device
|
||||
paths and device nodes. It is required to run the EFI Shell.
|
||||
|
||||
config EFI_DT_FIXUP
|
||||
bool "Device tree fixup protocol"
|
||||
depends on !GENERATE_ACPI_TABLE
|
||||
default y
|
||||
help
|
||||
The EFI device-tree fix-up protocol provides a function to let the
|
||||
firmware apply fix-ups. This may be used by boot loaders.
|
||||
|
||||
config EFI_LOADER_HII
|
||||
bool "HII protocols"
|
||||
default y
|
||||
@ -229,17 +252,6 @@ config EFI_UNICODE_CAPITALIZATION
|
||||
set, only the the correct handling of the letters of the codepage
|
||||
used by the FAT file system is ensured.
|
||||
|
||||
config EFI_UNICODE_COLLATION_PROTOCOL
|
||||
bool "Deprecated version of the Unicode collation protocol"
|
||||
default n
|
||||
help
|
||||
In EFI 1.10 a version of the Unicode collation protocol using ISO
|
||||
639-2 language codes existed. This protocol is not part of the UEFI
|
||||
specification any longer. Unfortunately it is required to run the
|
||||
UEFI Self Certification Test (SCT) II, version 2.6, 2017.
|
||||
|
||||
Choose this option for testing only. It is bound to be removed.
|
||||
|
||||
endif
|
||||
|
||||
config EFI_LOADER_BOUNCE_BUFFER
|
||||
|
@ -21,20 +21,21 @@ targets += helloworld.o
|
||||
endif
|
||||
|
||||
obj-$(CONFIG_CMD_BOOTEFI_HELLO) += helloworld_efi.o
|
||||
obj-y += efi_bootmgr.o
|
||||
obj-$(CONFIG_CMD_BOOTEFI_BOOTMGR) += efi_bootmgr.o
|
||||
obj-y += efi_boottime.o
|
||||
obj-$(CONFIG_EFI_HAVE_CAPSULE_SUPPORT) += efi_capsule.o
|
||||
obj-$(CONFIG_EFI_CAPSULE_FIRMWARE) += efi_firmware.o
|
||||
obj-y += efi_console.o
|
||||
obj-y += efi_device_path.o
|
||||
obj-$(CONFIG_EFI_DEVICE_PATH_TO_TEXT) += efi_device_path_to_text.o
|
||||
obj-y += efi_device_path_utilities.o
|
||||
obj-$(CONFIG_EFI_DEVICE_PATH_UTIL) += efi_device_path_utilities.o
|
||||
ifeq ($(CONFIG_GENERATE_ACPI_TABLE),)
|
||||
obj-y += efi_dt_fixup.o
|
||||
endif
|
||||
obj-y += efi_file.o
|
||||
obj-$(CONFIG_EFI_LOADER_HII) += efi_hii.o
|
||||
obj-y += efi_image_loader.o
|
||||
obj-y += efi_load_options.o
|
||||
obj-y += efi_memory.o
|
||||
obj-y += efi_root_node.o
|
||||
obj-y += efi_runtime.o
|
||||
|
@ -30,141 +30,6 @@ static const struct efi_runtime_services *rs;
|
||||
* should do normal or recovery boot.
|
||||
*/
|
||||
|
||||
/**
|
||||
* efi_set_load_options() - set the load options of a loaded image
|
||||
*
|
||||
* @handle: the image handle
|
||||
* @load_options_size: size of load options
|
||||
* @load_options: pointer to load options
|
||||
* Return: status code
|
||||
*/
|
||||
efi_status_t efi_set_load_options(efi_handle_t handle,
|
||||
efi_uintn_t load_options_size,
|
||||
void *load_options)
|
||||
{
|
||||
struct efi_loaded_image *loaded_image_info;
|
||||
efi_status_t ret;
|
||||
|
||||
ret = EFI_CALL(systab.boottime->open_protocol(
|
||||
handle,
|
||||
&efi_guid_loaded_image,
|
||||
(void **)&loaded_image_info,
|
||||
efi_root, NULL,
|
||||
EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL));
|
||||
if (ret != EFI_SUCCESS)
|
||||
return EFI_INVALID_PARAMETER;
|
||||
|
||||
loaded_image_info->load_options = load_options;
|
||||
loaded_image_info->load_options_size = load_options_size;
|
||||
|
||||
return EFI_CALL(systab.boottime->close_protocol(handle,
|
||||
&efi_guid_loaded_image,
|
||||
efi_root, NULL));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* efi_deserialize_load_option() - parse serialized data
|
||||
*
|
||||
* Parse serialized data describing a load option and transform it to the
|
||||
* efi_load_option structure.
|
||||
*
|
||||
* @lo: pointer to target
|
||||
* @data: serialized data
|
||||
* @size: size of the load option, on return size of the optional data
|
||||
* Return: status code
|
||||
*/
|
||||
efi_status_t efi_deserialize_load_option(struct efi_load_option *lo, u8 *data,
|
||||
efi_uintn_t *size)
|
||||
{
|
||||
efi_uintn_t len;
|
||||
|
||||
len = sizeof(u32);
|
||||
if (*size < len + 2 * sizeof(u16))
|
||||
return EFI_INVALID_PARAMETER;
|
||||
lo->attributes = get_unaligned_le32(data);
|
||||
data += len;
|
||||
*size -= len;
|
||||
|
||||
len = sizeof(u16);
|
||||
lo->file_path_length = get_unaligned_le16(data);
|
||||
data += len;
|
||||
*size -= len;
|
||||
|
||||
lo->label = (u16 *)data;
|
||||
len = u16_strnlen(lo->label, *size / sizeof(u16) - 1);
|
||||
if (lo->label[len])
|
||||
return EFI_INVALID_PARAMETER;
|
||||
len = (len + 1) * sizeof(u16);
|
||||
if (*size < len)
|
||||
return EFI_INVALID_PARAMETER;
|
||||
data += len;
|
||||
*size -= len;
|
||||
|
||||
len = lo->file_path_length;
|
||||
if (*size < len)
|
||||
return EFI_INVALID_PARAMETER;
|
||||
lo->file_path = (struct efi_device_path *)data;
|
||||
if (efi_dp_check_length(lo->file_path, len) < 0)
|
||||
return EFI_INVALID_PARAMETER;
|
||||
data += len;
|
||||
*size -= len;
|
||||
|
||||
lo->optional_data = data;
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* efi_serialize_load_option() - serialize load option
|
||||
*
|
||||
* Serialize efi_load_option structure into byte stream for BootXXXX.
|
||||
*
|
||||
* @data: buffer for serialized data
|
||||
* @lo: load option
|
||||
* Return: size of allocated buffer
|
||||
*/
|
||||
unsigned long efi_serialize_load_option(struct efi_load_option *lo, u8 **data)
|
||||
{
|
||||
unsigned long label_len;
|
||||
unsigned long size;
|
||||
u8 *p;
|
||||
|
||||
label_len = (u16_strlen(lo->label) + 1) * sizeof(u16);
|
||||
|
||||
/* total size */
|
||||
size = sizeof(lo->attributes);
|
||||
size += sizeof(lo->file_path_length);
|
||||
size += label_len;
|
||||
size += lo->file_path_length;
|
||||
if (lo->optional_data)
|
||||
size += (utf8_utf16_strlen((const char *)lo->optional_data)
|
||||
+ 1) * sizeof(u16);
|
||||
p = malloc(size);
|
||||
if (!p)
|
||||
return 0;
|
||||
|
||||
/* copy data */
|
||||
*data = p;
|
||||
memcpy(p, &lo->attributes, sizeof(lo->attributes));
|
||||
p += sizeof(lo->attributes);
|
||||
|
||||
memcpy(p, &lo->file_path_length, sizeof(lo->file_path_length));
|
||||
p += sizeof(lo->file_path_length);
|
||||
|
||||
memcpy(p, lo->label, label_len);
|
||||
p += label_len;
|
||||
|
||||
memcpy(p, lo->file_path, lo->file_path_length);
|
||||
p += lo->file_path_length;
|
||||
|
||||
if (lo->optional_data) {
|
||||
utf8_utf16_strcpy((u16 **)&p, (const char *)lo->optional_data);
|
||||
p += sizeof(u16); /* size of trailing \0 */
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* get_var() - get UEFI variable
|
||||
*
|
||||
|
@ -10,16 +10,6 @@
|
||||
#include <efi_loader.h>
|
||||
#include <mapmem.h>
|
||||
|
||||
static efi_status_t EFIAPI efi_dt_fixup(struct efi_dt_fixup_protocol *this,
|
||||
void *dtb,
|
||||
efi_uintn_t *buffer_size,
|
||||
u32 flags);
|
||||
|
||||
struct efi_dt_fixup_protocol efi_dt_fixup_prot = {
|
||||
.revision = EFI_DT_FIXUP_PROTOCOL_REVISION,
|
||||
.fixup = efi_dt_fixup
|
||||
};
|
||||
|
||||
const efi_guid_t efi_guid_dt_fixup_protocol = EFI_DT_FIXUP_PROTOCOL_GUID;
|
||||
|
||||
/**
|
||||
@ -102,10 +92,21 @@ void efi_carve_out_dt_rsv(void *fdt)
|
||||
}
|
||||
}
|
||||
|
||||
static efi_status_t EFIAPI efi_dt_fixup(struct efi_dt_fixup_protocol *this,
|
||||
void *dtb,
|
||||
efi_uintn_t *buffer_size,
|
||||
u32 flags)
|
||||
/**
|
||||
* efi_dt_fixup() - fix up device tree
|
||||
*
|
||||
* This function implements the Fixup() service of the
|
||||
* EFI Device Tree Fixup Protocol.
|
||||
*
|
||||
* @this: instance of the protocol
|
||||
* @dtb: device tree provided by caller
|
||||
* @buffer_size: size of buffer for the device tree including free space
|
||||
* @flags: bit field designating action to be performed
|
||||
* Return: status code
|
||||
*/
|
||||
static efi_status_t __maybe_unused EFIAPI
|
||||
efi_dt_fixup(struct efi_dt_fixup_protocol *this, void *dtb,
|
||||
efi_uintn_t *buffer_size, u32 flags)
|
||||
{
|
||||
efi_status_t ret;
|
||||
size_t required_size;
|
||||
@ -158,3 +159,8 @@ static efi_status_t EFIAPI efi_dt_fixup(struct efi_dt_fixup_protocol *this,
|
||||
out:
|
||||
return EFI_EXIT(ret);
|
||||
}
|
||||
|
||||
struct efi_dt_fixup_protocol efi_dt_fixup_prot = {
|
||||
.revision = EFI_DT_FIXUP_PROTOCOL_REVISION,
|
||||
.fixup = efi_dt_fixup
|
||||
};
|
||||
|
149
lib/efi_loader/efi_load_options.c
Normal file
149
lib/efi_loader/efi_load_options.c
Normal file
@ -0,0 +1,149 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* EFI boot manager
|
||||
*
|
||||
* Copyright (c) 2018 AKASHI Takahiro, et.al.
|
||||
*/
|
||||
|
||||
#define LOG_CATEGORY LOGC_EFI
|
||||
|
||||
#include <common.h>
|
||||
#include <charset.h>
|
||||
#include <log.h>
|
||||
#include <malloc.h>
|
||||
#include <efi_loader.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
/**
|
||||
* efi_set_load_options() - set the load options of a loaded image
|
||||
*
|
||||
* @handle: the image handle
|
||||
* @load_options_size: size of load options
|
||||
* @load_options: pointer to load options
|
||||
* Return: status code
|
||||
*/
|
||||
efi_status_t efi_set_load_options(efi_handle_t handle,
|
||||
efi_uintn_t load_options_size,
|
||||
void *load_options)
|
||||
{
|
||||
struct efi_loaded_image *loaded_image_info;
|
||||
efi_status_t ret;
|
||||
|
||||
ret = EFI_CALL(systab.boottime->open_protocol(
|
||||
handle,
|
||||
&efi_guid_loaded_image,
|
||||
(void **)&loaded_image_info,
|
||||
efi_root, NULL,
|
||||
EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL));
|
||||
if (ret != EFI_SUCCESS)
|
||||
return EFI_INVALID_PARAMETER;
|
||||
|
||||
loaded_image_info->load_options = load_options;
|
||||
loaded_image_info->load_options_size = load_options_size;
|
||||
|
||||
return EFI_CALL(systab.boottime->close_protocol(handle,
|
||||
&efi_guid_loaded_image,
|
||||
efi_root, NULL));
|
||||
}
|
||||
|
||||
/**
|
||||
* efi_deserialize_load_option() - parse serialized data
|
||||
*
|
||||
* Parse serialized data describing a load option and transform it to the
|
||||
* efi_load_option structure.
|
||||
*
|
||||
* @lo: pointer to target
|
||||
* @data: serialized data
|
||||
* @size: size of the load option, on return size of the optional data
|
||||
* Return: status code
|
||||
*/
|
||||
efi_status_t efi_deserialize_load_option(struct efi_load_option *lo, u8 *data,
|
||||
efi_uintn_t *size)
|
||||
{
|
||||
efi_uintn_t len;
|
||||
|
||||
len = sizeof(u32);
|
||||
if (*size < len + 2 * sizeof(u16))
|
||||
return EFI_INVALID_PARAMETER;
|
||||
lo->attributes = get_unaligned_le32(data);
|
||||
data += len;
|
||||
*size -= len;
|
||||
|
||||
len = sizeof(u16);
|
||||
lo->file_path_length = get_unaligned_le16(data);
|
||||
data += len;
|
||||
*size -= len;
|
||||
|
||||
lo->label = (u16 *)data;
|
||||
len = u16_strnlen(lo->label, *size / sizeof(u16) - 1);
|
||||
if (lo->label[len])
|
||||
return EFI_INVALID_PARAMETER;
|
||||
len = (len + 1) * sizeof(u16);
|
||||
if (*size < len)
|
||||
return EFI_INVALID_PARAMETER;
|
||||
data += len;
|
||||
*size -= len;
|
||||
|
||||
len = lo->file_path_length;
|
||||
if (*size < len)
|
||||
return EFI_INVALID_PARAMETER;
|
||||
lo->file_path = (struct efi_device_path *)data;
|
||||
if (efi_dp_check_length(lo->file_path, len) < 0)
|
||||
return EFI_INVALID_PARAMETER;
|
||||
data += len;
|
||||
*size -= len;
|
||||
|
||||
lo->optional_data = data;
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* efi_serialize_load_option() - serialize load option
|
||||
*
|
||||
* Serialize efi_load_option structure into byte stream for BootXXXX.
|
||||
*
|
||||
* @data: buffer for serialized data
|
||||
* @lo: load option
|
||||
* Return: size of allocated buffer
|
||||
*/
|
||||
unsigned long efi_serialize_load_option(struct efi_load_option *lo, u8 **data)
|
||||
{
|
||||
unsigned long label_len;
|
||||
unsigned long size;
|
||||
u8 *p;
|
||||
|
||||
label_len = (u16_strlen(lo->label) + 1) * sizeof(u16);
|
||||
|
||||
/* total size */
|
||||
size = sizeof(lo->attributes);
|
||||
size += sizeof(lo->file_path_length);
|
||||
size += label_len;
|
||||
size += lo->file_path_length;
|
||||
if (lo->optional_data)
|
||||
size += (utf8_utf16_strlen((const char *)lo->optional_data)
|
||||
+ 1) * sizeof(u16);
|
||||
p = malloc(size);
|
||||
if (!p)
|
||||
return 0;
|
||||
|
||||
/* copy data */
|
||||
*data = p;
|
||||
memcpy(p, &lo->attributes, sizeof(lo->attributes));
|
||||
p += sizeof(lo->attributes);
|
||||
|
||||
memcpy(p, &lo->file_path_length, sizeof(lo->file_path_length));
|
||||
p += sizeof(lo->file_path_length);
|
||||
|
||||
memcpy(p, lo->label, label_len);
|
||||
p += label_len;
|
||||
|
||||
memcpy(p, lo->file_path, lo->file_path_length);
|
||||
p += lo->file_path_length;
|
||||
|
||||
if (lo->optional_data) {
|
||||
utf8_utf16_strcpy((u16 **)&p, (const char *)lo->optional_data);
|
||||
p += sizeof(u16); /* size of trailing \0 */
|
||||
}
|
||||
return size;
|
||||
}
|
@ -58,21 +58,17 @@ efi_status_t efi_root_node_register(void)
|
||||
&efi_guid_device_path_to_text_protocol,
|
||||
(void *)&efi_device_path_to_text,
|
||||
#endif
|
||||
#ifdef CONFIG_EFI_DEVICE_PATH_UTIL
|
||||
/* Device path utilities protocol */
|
||||
&efi_guid_device_path_utilities_protocol,
|
||||
(void *)&efi_device_path_utilities,
|
||||
#if !CONFIG_IS_ENABLED(GENERATE_ACPI_TABLE)
|
||||
#endif
|
||||
#ifdef CONFIG_EFI_DT_FIXUP
|
||||
/* Device-tree fix-up protocol */
|
||||
&efi_guid_dt_fixup_protocol,
|
||||
(void *)&efi_dt_fixup_prot,
|
||||
#endif
|
||||
#if CONFIG_IS_ENABLED(EFI_UNICODE_COLLATION_PROTOCOL2)
|
||||
#if CONFIG_IS_ENABLED(EFI_UNICODE_COLLATION_PROTOCOL)
|
||||
/* Deprecated Unicode collation protocol */
|
||||
&efi_guid_unicode_collation_protocol,
|
||||
(void *)&efi_unicode_collation_protocol,
|
||||
#endif
|
||||
/* Current Unicode collation protocol */
|
||||
&efi_guid_unicode_collation_protocol2,
|
||||
(void *)&efi_unicode_collation_protocol2,
|
||||
#endif
|
||||
|
@ -38,7 +38,7 @@ const efi_guid_t efi_guid_unicode_collation_protocol2 =
|
||||
* @s2: second string
|
||||
*
|
||||
* This function implements the StriColl() service of the
|
||||
* EFI_UNICODE_COLLATION_PROTOCOL.
|
||||
* EFI_UNICODE_COLLATION_PROTOCOL2.
|
||||
*
|
||||
* See the Unified Extensible Firmware Interface (UEFI) specification for
|
||||
* details.
|
||||
@ -179,7 +179,7 @@ static bool metai_match(const u16 *string, const u16 *pattern)
|
||||
* - [<char1>-<char2>] matches any character in the range
|
||||
*
|
||||
* This function implements the MetaMatch() service of the
|
||||
* EFI_UNICODE_COLLATION_PROTOCOL.
|
||||
* EFI_UNICODE_COLLATION_PROTOCOL2.
|
||||
*
|
||||
* Return: true if the string is matched.
|
||||
*/
|
||||
@ -204,7 +204,7 @@ static bool EFIAPI efi_metai_match(struct efi_unicode_collation_protocol *this,
|
||||
* same number of words this does not pose a problem.
|
||||
*
|
||||
* This function implements the StrLwr() service of the
|
||||
* EFI_UNICODE_COLLATION_PROTOCOL.
|
||||
* EFI_UNICODE_COLLATION_PROTOCOL2.
|
||||
*/
|
||||
static void EFIAPI efi_str_lwr(struct efi_unicode_collation_protocol *this,
|
||||
u16 *string)
|
||||
@ -225,7 +225,7 @@ static void EFIAPI efi_str_lwr(struct efi_unicode_collation_protocol *this,
|
||||
* same number of words this does not pose a problem.
|
||||
*
|
||||
* This function implements the StrUpr() service of the
|
||||
* EFI_UNICODE_COLLATION_PROTOCOL.
|
||||
* EFI_UNICODE_COLLATION_PROTOCOL2.
|
||||
*/
|
||||
static void EFIAPI efi_str_upr(struct efi_unicode_collation_protocol *this,
|
||||
u16 *string)
|
||||
@ -245,7 +245,7 @@ static void EFIAPI efi_str_upr(struct efi_unicode_collation_protocol *this,
|
||||
* @string: converted string
|
||||
*
|
||||
* This function implements the FatToStr() service of the
|
||||
* EFI_UNICODE_COLLATION_PROTOCOL.
|
||||
* EFI_UNICODE_COLLATION_PROTOCOL2.
|
||||
*/
|
||||
static void EFIAPI efi_fat_to_str(struct efi_unicode_collation_protocol *this,
|
||||
efi_uintn_t fat_size, char *fat, u16 *string)
|
||||
@ -276,7 +276,7 @@ static void EFIAPI efi_fat_to_str(struct efi_unicode_collation_protocol *this,
|
||||
* @fat: converted string
|
||||
*
|
||||
* This function implements the StrToFat() service of the
|
||||
* EFI_UNICODE_COLLATION_PROTOCOL.
|
||||
* EFI_UNICODE_COLLATION_PROTOCOL2.
|
||||
*
|
||||
* Return: true if an illegal character was substituted by '_'.
|
||||
*/
|
||||
@ -337,30 +337,3 @@ const struct efi_unicode_collation_protocol efi_unicode_collation_protocol2 = {
|
||||
.str_to_fat = efi_str_to_fat,
|
||||
.supported_languages = "en",
|
||||
};
|
||||
|
||||
/*
|
||||
* In EFI 1.10 a version of the Unicode collation protocol using ISO 639-2
|
||||
* language codes existed. This protocol is not part of the UEFI specification
|
||||
* any longer. Unfortunately it is required to run the UEFI Self Certification
|
||||
* Test (SCT) II, version 2.6, 2017. So we implement it here for the sole
|
||||
* purpose of running the SCT. It can be removed when a compliant SCT is
|
||||
* available.
|
||||
*/
|
||||
#if CONFIG_IS_ENABLED(EFI_UNICODE_COLLATION_PROTOCOL)
|
||||
|
||||
/* GUID of the EFI_UNICODE_COLLATION_PROTOCOL */
|
||||
const efi_guid_t efi_guid_unicode_collation_protocol =
|
||||
EFI_UNICODE_COLLATION_PROTOCOL_GUID;
|
||||
|
||||
const struct efi_unicode_collation_protocol efi_unicode_collation_protocol = {
|
||||
.stri_coll = efi_stri_coll,
|
||||
.metai_match = efi_metai_match,
|
||||
.str_lwr = efi_str_lwr,
|
||||
.str_upr = efi_str_upr,
|
||||
.fat_to_str = efi_fat_to_str,
|
||||
.str_to_fat = efi_str_to_fat,
|
||||
/* ISO 639-2 language code */
|
||||
.supported_languages = "eng",
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -10,7 +10,13 @@
|
||||
#include <efi_variable.h>
|
||||
#include <u-boot/crc.h>
|
||||
|
||||
struct efi_var_file __efi_runtime_data *efi_var_buf;
|
||||
/*
|
||||
* The variables efi_var_file and efi_var_entry must be static to avoid
|
||||
* referencing them via the global offset table (section .got). The GOT
|
||||
* is neither mapped as EfiRuntimeServicesData nor do we support its
|
||||
* relocation during SetVirtualAddressMap().
|
||||
*/
|
||||
static struct efi_var_file __efi_runtime_data *efi_var_buf;
|
||||
static struct efi_var_entry __efi_runtime_data *efi_current_var;
|
||||
|
||||
/**
|
||||
@ -339,3 +345,8 @@ efi_get_next_variable_name_mem(efi_uintn_t *variable_name_size,
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
void efi_var_buf_update(struct efi_var_file *var_buf)
|
||||
{
|
||||
memcpy(efi_var_buf, var_buf, EFI_VAR_BUF_SIZE);
|
||||
}
|
||||
|
@ -702,7 +702,7 @@ void efi_variables_boot_exit_notify(void)
|
||||
if (ret != EFI_SUCCESS)
|
||||
log_err("Can't populate EFI variables. No runtime variables will be available\n");
|
||||
else
|
||||
memcpy(efi_var_buf, var_buf, len);
|
||||
efi_var_buf_update(var_buf);
|
||||
free(var_buf);
|
||||
|
||||
/* Update runtime service table */
|
||||
|
@ -14,6 +14,8 @@ CFLAGS_efi_selftest_miniapp_exit.o := $(CFLAGS_EFI) -Os -ffreestanding
|
||||
CFLAGS_REMOVE_efi_selftest_miniapp_exit.o := $(CFLAGS_NON_EFI)
|
||||
CFLAGS_efi_selftest_miniapp_return.o := $(CFLAGS_EFI) -Os -ffreestanding
|
||||
CFLAGS_REMOVE_efi_selftest_miniapp_return.o := $(CFLAGS_NON_EFI)
|
||||
CFLAGS_initrddump_exit.o := $(CFLAGS_EFI) -Os -ffreestanding
|
||||
CFLAGS_REMOVE_initrddump.o := $(CFLAGS_NON_EFI)
|
||||
|
||||
obj-y += \
|
||||
efi_selftest.o \
|
||||
@ -78,8 +80,13 @@ efi_selftest_miniapp_exception.efi \
|
||||
efi_selftest_miniapp_exit.efi \
|
||||
efi_selftest_miniapp_return.efi
|
||||
|
||||
always += \
|
||||
dtbdump.efi
|
||||
ifeq ($(CONFIG_GENERATE_ACPI_TABLE),)
|
||||
always += dtbdump.efi
|
||||
endif
|
||||
|
||||
ifdef CONFIG_EFI_LOAD_FILE2_INITRD
|
||||
always += initrddump.efi
|
||||
endif
|
||||
|
||||
$(obj)/efi_miniapp_file_image_exception.h: $(obj)/efi_selftest_miniapp_exception.efi
|
||||
$(obj)/../../tools/file2include $(obj)/efi_selftest_miniapp_exception.efi > \
|
||||
|
@ -28,6 +28,16 @@ static struct efi_system_table *systable;
|
||||
static const efi_guid_t efi_dt_fixup_protocol_guid = EFI_DT_FIXUP_PROTOCOL_GUID;
|
||||
static const efi_guid_t efi_file_info_guid = EFI_FILE_INFO_GUID;
|
||||
|
||||
/**
|
||||
* print() - print string
|
||||
*
|
||||
* @string: text
|
||||
*/
|
||||
static void print(u16 *string)
|
||||
{
|
||||
cout->output_string(cout, string);
|
||||
}
|
||||
|
||||
/**
|
||||
* error() - print error string
|
||||
*
|
||||
@ -36,12 +46,56 @@ static const efi_guid_t efi_file_info_guid = EFI_FILE_INFO_GUID;
|
||||
static void error(u16 *string)
|
||||
{
|
||||
cout->set_attribute(cout, EFI_LIGHTRED | EFI_BACKGROUND_BLACK);
|
||||
cout->output_string(cout, string);
|
||||
print(string);
|
||||
cout->set_attribute(cout, EFI_LIGHTBLUE | EFI_BACKGROUND_BLACK);
|
||||
}
|
||||
|
||||
/**
|
||||
* input() - read string from console
|
||||
* efi_input_yn() - get answer to yes/no question
|
||||
*
|
||||
* Return:
|
||||
* y or Y
|
||||
* EFI_SUCCESS
|
||||
* n or N
|
||||
* EFI_ACCESS_DENIED
|
||||
* ESC
|
||||
* EFI_ABORTED
|
||||
*/
|
||||
static efi_status_t efi_input_yn(void)
|
||||
{
|
||||
struct efi_input_key key = {0};
|
||||
efi_uintn_t index;
|
||||
efi_status_t ret;
|
||||
|
||||
/* Drain the console input */
|
||||
ret = cin->reset(cin, true);
|
||||
for (;;) {
|
||||
ret = bs->wait_for_event(1, &cin->wait_for_key, &index);
|
||||
if (ret != EFI_SUCCESS)
|
||||
continue;
|
||||
ret = cin->read_key_stroke(cin, &key);
|
||||
if (ret != EFI_SUCCESS)
|
||||
continue;
|
||||
switch (key.scan_code) {
|
||||
case 0x17: /* Escape */
|
||||
return EFI_ABORTED;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
/* Convert to lower case */
|
||||
switch (key.unicode_char | 0x20) {
|
||||
case 'y':
|
||||
return EFI_SUCCESS;
|
||||
case 'n':
|
||||
return EFI_ACCESS_DENIED;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* efi_input() - read string from console
|
||||
*
|
||||
* @buffer: input buffer
|
||||
* @buffer_size: buffer size
|
||||
@ -67,7 +121,7 @@ static efi_status_t efi_input(u16 *buffer, efi_uintn_t buffer_size)
|
||||
continue;
|
||||
switch (key.scan_code) {
|
||||
case 0x17: /* Escape */
|
||||
cout->output_string(cout, L"\nAborted\n");
|
||||
print(L"\r\nAborted\r\n");
|
||||
return EFI_ABORTED;
|
||||
default:
|
||||
break;
|
||||
@ -76,12 +130,12 @@ static efi_status_t efi_input(u16 *buffer, efi_uintn_t buffer_size)
|
||||
case 0x08: /* Backspace */
|
||||
if (pos) {
|
||||
buffer[pos--] = 0;
|
||||
cout->output_string(cout, L"\b \b");
|
||||
print(L"\b \b");
|
||||
}
|
||||
break;
|
||||
case 0x0a: /* Linefeed */
|
||||
case 0x0d: /* Carriage return */
|
||||
cout->output_string(cout, L"\n");
|
||||
print(L"\r\n");
|
||||
return EFI_SUCCESS;
|
||||
default:
|
||||
break;
|
||||
@ -94,7 +148,7 @@ static efi_status_t efi_input(u16 *buffer, efi_uintn_t buffer_size)
|
||||
*outbuf = key.unicode_char;
|
||||
buffer[pos++] = key.unicode_char;
|
||||
buffer[pos] = 0;
|
||||
cout->output_string(cout, outbuf);
|
||||
print(outbuf);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -171,9 +225,9 @@ bool starts_with(u16 *string, u16 *keyword)
|
||||
*/
|
||||
void do_help(void)
|
||||
{
|
||||
error(L"load <dtb> - load device-tree from file\n");
|
||||
error(L"save <dtb> - save device-tree to file\n");
|
||||
error(L"exit - exit the shell\n");
|
||||
error(L"load <dtb> - load device-tree from file\r\n");
|
||||
error(L"save <dtb> - save device-tree to file\r\n");
|
||||
error(L"exit - exit the shell\r\n");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -198,7 +252,7 @@ efi_status_t do_load(u16 *filename)
|
||||
ret = bs->locate_protocol(&efi_dt_fixup_protocol_guid, NULL,
|
||||
(void **)&dt_fixup_prot);
|
||||
if (ret != EFI_SUCCESS) {
|
||||
error(L"Device-tree fix-up protocol not found\n");
|
||||
error(L"Device-tree fix-up protocol not found\r\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -208,7 +262,7 @@ efi_status_t do_load(u16 *filename)
|
||||
(void **)&loaded_image, NULL, NULL,
|
||||
EFI_OPEN_PROTOCOL_GET_PROTOCOL);
|
||||
if (ret != EFI_SUCCESS) {
|
||||
error(L"Loaded image protocol not found\n");
|
||||
error(L"Loaded image protocol not found\r\n");
|
||||
return ret;
|
||||
}
|
||||
/* Open the simple file system protocol */
|
||||
@ -217,57 +271,57 @@ efi_status_t do_load(u16 *filename)
|
||||
(void **)&file_system, NULL, NULL,
|
||||
EFI_OPEN_PROTOCOL_GET_PROTOCOL);
|
||||
if (ret != EFI_SUCCESS) {
|
||||
error(L"Failed to open simple file system protocol\n");
|
||||
error(L"Failed to open simple file system protocol\r\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Open volume */
|
||||
ret = file_system->open_volume(file_system, &root);
|
||||
if (ret != EFI_SUCCESS) {
|
||||
error(L"Failed to open volume\n");
|
||||
error(L"Failed to open volume\r\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Open file */
|
||||
ret = root->open(root, &file, filename, EFI_FILE_MODE_READ, 0);
|
||||
if (ret != EFI_SUCCESS) {
|
||||
error(L"File not found\n");
|
||||
error(L"File not found\r\n");
|
||||
goto out;
|
||||
}
|
||||
/* Get file size */
|
||||
buffer_size = 0;
|
||||
ret = file->getinfo(file, &efi_file_info_guid, &buffer_size, NULL);
|
||||
if (ret != EFI_BUFFER_TOO_SMALL) {
|
||||
error(L"Can't get file info size\n");
|
||||
error(L"Can't get file info size\r\n");
|
||||
goto out;
|
||||
}
|
||||
ret = bs->allocate_pool(EFI_LOADER_DATA, buffer_size, (void **)&info);
|
||||
if (ret != EFI_SUCCESS) {
|
||||
error(L"Out of memory\n");
|
||||
error(L"Out of memory\r\n");
|
||||
goto out;
|
||||
}
|
||||
ret = file->getinfo(file, &efi_file_info_guid, &buffer_size, info);
|
||||
if (ret != EFI_SUCCESS) {
|
||||
error(L"Can't get file info\n");
|
||||
error(L"Can't get file info\r\n");
|
||||
goto out;
|
||||
}
|
||||
buffer_size = info->file_size;
|
||||
pages = efi_size_in_pages(buffer_size);
|
||||
ret = bs->free_pool(info);
|
||||
if (ret != EFI_SUCCESS)
|
||||
error(L"Can't free memory pool\n");
|
||||
error(L"Can't free memory pool\r\n");
|
||||
/* Read file */
|
||||
ret = bs->allocate_pages(EFI_ALLOCATE_ANY_PAGES,
|
||||
EFI_ACPI_RECLAIM_MEMORY,
|
||||
pages, &addr);
|
||||
if (ret != EFI_SUCCESS) {
|
||||
error(L"Out of memory\n");
|
||||
error(L"Out of memory\r\n");
|
||||
goto out;
|
||||
}
|
||||
dtb = (struct fdt_header *)(uintptr_t)addr;
|
||||
ret = file->read(file, &buffer_size, dtb);
|
||||
if (ret != EFI_SUCCESS) {
|
||||
error(L"Can't read file\n");
|
||||
error(L"Can't read file\r\n");
|
||||
goto out;
|
||||
}
|
||||
/* Fixup file, expecting EFI_BUFFER_TOO_SMALL */
|
||||
@ -278,24 +332,24 @@ efi_status_t do_load(u16 *filename)
|
||||
/* Read file into larger buffer */
|
||||
ret = bs->free_pages(addr, pages);
|
||||
if (ret != EFI_SUCCESS)
|
||||
error(L"Can't free memory pages\n");
|
||||
error(L"Can't free memory pages\r\n");
|
||||
pages = efi_size_in_pages(buffer_size);
|
||||
ret = bs->allocate_pages(EFI_ALLOCATE_ANY_PAGES,
|
||||
EFI_ACPI_RECLAIM_MEMORY,
|
||||
pages, &addr);
|
||||
if (ret != EFI_SUCCESS) {
|
||||
error(L"Out of memory\n");
|
||||
error(L"Out of memory\r\n");
|
||||
goto out;
|
||||
}
|
||||
dtb = (struct fdt_header *)(uintptr_t)addr;
|
||||
ret = file->setpos(file, 0);
|
||||
if (ret != EFI_SUCCESS) {
|
||||
error(L"Can't position file\n");
|
||||
error(L"Can't position file\r\n");
|
||||
goto out;
|
||||
}
|
||||
ret = file->read(file, &buffer_size, dtb);
|
||||
if (ret != EFI_SUCCESS) {
|
||||
error(L"Can't read file\n");
|
||||
error(L"Can't read file\r\n");
|
||||
goto out;
|
||||
}
|
||||
buffer_size = pages << EFI_PAGE_SHIFT;
|
||||
@ -305,24 +359,24 @@ efi_status_t do_load(u16 *filename)
|
||||
EFI_DT_INSTALL_TABLE);
|
||||
}
|
||||
if (ret == EFI_SUCCESS)
|
||||
cout->output_string(cout, L"device-tree installed\n");
|
||||
print(L"device-tree installed\r\n");
|
||||
else
|
||||
error(L"Device-tree fix-up failed\n");
|
||||
error(L"Device-tree fix-up failed\r\n");
|
||||
out:
|
||||
if (addr) {
|
||||
ret2 = bs->free_pages(addr, pages);
|
||||
if (ret2 != EFI_SUCCESS)
|
||||
error(L"Can't free memory pages\n");
|
||||
error(L"Can't free memory pages\r\n");
|
||||
}
|
||||
if (file) {
|
||||
ret2 = file->close(file);
|
||||
if (ret2 != EFI_SUCCESS)
|
||||
error(L"Can't close file\n");
|
||||
error(L"Can't close file\r\n");
|
||||
}
|
||||
if (root) {
|
||||
ret2 = root->close(root);
|
||||
if (ret2 != EFI_SUCCESS)
|
||||
error(L"Can't close volume\n");
|
||||
error(L"Can't close volume\r\n");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@ -344,11 +398,11 @@ efi_status_t do_save(u16 *filename)
|
||||
|
||||
dtb = get_dtb(systable);
|
||||
if (!dtb) {
|
||||
error(L"DTB not found\n");
|
||||
error(L"DTB not found\r\n");
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
if (f2h(dtb->magic) != FDT_MAGIC) {
|
||||
error(L"Wrong device tree magic\n");
|
||||
error(L"Wrong device tree magic\r\n");
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
dtb_size = f2h(dtb->totalsize);
|
||||
@ -359,7 +413,7 @@ efi_status_t do_save(u16 *filename)
|
||||
(void **)&loaded_image, NULL, NULL,
|
||||
EFI_OPEN_PROTOCOL_GET_PROTOCOL);
|
||||
if (ret != EFI_SUCCESS) {
|
||||
error(L"Loaded image protocol not found\n");
|
||||
error(L"Loaded image protocol not found\r\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -369,16 +423,30 @@ efi_status_t do_save(u16 *filename)
|
||||
(void **)&file_system, NULL, NULL,
|
||||
EFI_OPEN_PROTOCOL_GET_PROTOCOL);
|
||||
if (ret != EFI_SUCCESS) {
|
||||
error(L"Failed to open simple file system protocol\n");
|
||||
error(L"Failed to open simple file system protocol\r\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Open volume */
|
||||
ret = file_system->open_volume(file_system, &root);
|
||||
if (ret != EFI_SUCCESS) {
|
||||
error(L"Failed to open volume\n");
|
||||
error(L"Failed to open volume\r\n");
|
||||
return ret;
|
||||
}
|
||||
/* Check if file already exists */
|
||||
ret = root->open(root, &file, filename, EFI_FILE_MODE_READ, 0);
|
||||
if (ret == EFI_SUCCESS) {
|
||||
file->close(file);
|
||||
print(L"Overwrite existing file (y/n)? ");
|
||||
ret = efi_input_yn();
|
||||
print(L"\r\n");
|
||||
if (ret != EFI_SUCCESS) {
|
||||
root->close(root);
|
||||
error(L"Aborted by user\r\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* Create file */
|
||||
ret = root->open(root, &file, filename,
|
||||
EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE |
|
||||
@ -387,16 +455,16 @@ efi_status_t do_save(u16 *filename)
|
||||
/* Write file */
|
||||
ret = file->write(file, &dtb_size, dtb);
|
||||
if (ret != EFI_SUCCESS)
|
||||
error(L"Failed to write file\n");
|
||||
error(L"Failed to write file\r\n");
|
||||
file->close(file);
|
||||
} else {
|
||||
error(L"Failed to open file\n");
|
||||
error(L"Failed to open file\r\n");
|
||||
}
|
||||
root->close(root);
|
||||
|
||||
if (ret == EFI_SUCCESS) {
|
||||
cout->output_string(cout, filename);
|
||||
cout->output_string(cout, L" written\n");
|
||||
print(filename);
|
||||
print(L" written\r\n");
|
||||
}
|
||||
|
||||
return ret;
|
||||
@ -422,7 +490,7 @@ efi_status_t EFIAPI efi_main(efi_handle_t image_handle,
|
||||
cout->set_attribute(cout, EFI_LIGHTBLUE | EFI_BACKGROUND_BLACK);
|
||||
cout->clear_screen(cout);
|
||||
cout->set_attribute(cout, EFI_WHITE | EFI_BACKGROUND_BLACK);
|
||||
cout->output_string(cout, L"DTB Dump\n========\n\n");
|
||||
print(L"DTB Dump\r\n========\r\n\r\n");
|
||||
cout->set_attribute(cout, EFI_LIGHTBLUE | EFI_BACKGROUND_BLACK);
|
||||
|
||||
for (;;) {
|
||||
@ -430,7 +498,7 @@ efi_status_t EFIAPI efi_main(efi_handle_t image_handle,
|
||||
u16 *pos;
|
||||
efi_uintn_t ret;
|
||||
|
||||
cout->output_string(cout, L"=> ");
|
||||
print(L"=> ");
|
||||
ret = efi_input(command, sizeof(command));
|
||||
if (ret == EFI_ABORTED)
|
||||
break;
|
||||
|
@ -46,11 +46,10 @@ static void mac(void *pointer, u16 **buf)
|
||||
/*
|
||||
* printx() - print hexadecimal number to an u16 string
|
||||
*
|
||||
* @pointer: pointer
|
||||
* @p: value to print
|
||||
* @prec: minimum number of digits to print
|
||||
* @buf: pointer to buffer address,
|
||||
* on return position of terminating zero word
|
||||
* @size: size of value to be printed in bytes
|
||||
*/
|
||||
static void printx(u64 p, int prec, u16 **buf)
|
||||
{
|
||||
|
449
lib/efi_selftest/initrddump.c
Normal file
449
lib/efi_selftest/initrddump.c
Normal file
@ -0,0 +1,449 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2020, Heinrich Schuchardt <xypron.glpk@gmx.de>
|
||||
*
|
||||
* initrddump.efi saves the initial RAM disk provided via the
|
||||
* EFI_LOAD_FILE2_PROTOCOL.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <efi_api.h>
|
||||
#include <efi_load_initrd.h>
|
||||
|
||||
#define BUFFER_SIZE 64
|
||||
#define ESC 0x17
|
||||
|
||||
#define efi_size_in_pages(size) (((size) + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT)
|
||||
|
||||
static struct efi_system_table *systable;
|
||||
static struct efi_boot_services *bs;
|
||||
static struct efi_simple_text_output_protocol *cerr;
|
||||
static struct efi_simple_text_output_protocol *cout;
|
||||
static struct efi_simple_text_input_protocol *cin;
|
||||
static const efi_guid_t loaded_image_guid = EFI_LOADED_IMAGE_PROTOCOL_GUID;
|
||||
static const efi_guid_t guid_simple_file_system_protocol =
|
||||
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID;
|
||||
static const efi_guid_t load_file2_guid = EFI_LOAD_FILE2_PROTOCOL_GUID;
|
||||
static efi_handle_t handle;
|
||||
|
||||
/*
|
||||
* Device path defined by Linux to identify the handle providing the
|
||||
* EFI_LOAD_FILE2_PROTOCOL used for loading the initial ramdisk.
|
||||
*/
|
||||
static const struct efi_initrd_dp initrd_dp = {
|
||||
.vendor = {
|
||||
{
|
||||
DEVICE_PATH_TYPE_MEDIA_DEVICE,
|
||||
DEVICE_PATH_SUB_TYPE_VENDOR_PATH,
|
||||
sizeof(initrd_dp.vendor),
|
||||
},
|
||||
EFI_INITRD_MEDIA_GUID,
|
||||
},
|
||||
.end = {
|
||||
DEVICE_PATH_TYPE_END,
|
||||
DEVICE_PATH_SUB_TYPE_END,
|
||||
sizeof(initrd_dp.end),
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* print() - print string
|
||||
*
|
||||
* @string: text
|
||||
*/
|
||||
static void print(u16 *string)
|
||||
{
|
||||
cout->output_string(cout, string);
|
||||
}
|
||||
|
||||
/**
|
||||
* error() - print error string
|
||||
*
|
||||
* @string: error text
|
||||
*/
|
||||
static void error(u16 *string)
|
||||
{
|
||||
cout->set_attribute(cout, EFI_LIGHTRED | EFI_BACKGROUND_BLACK);
|
||||
print(string);
|
||||
cout->set_attribute(cout, EFI_LIGHTBLUE | EFI_BACKGROUND_BLACK);
|
||||
}
|
||||
|
||||
/*
|
||||
* printx() - print hexadecimal number
|
||||
*
|
||||
* @val: value to print;
|
||||
* @prec: minimum number of digits to print
|
||||
*/
|
||||
static void printx(u64 val, u32 prec)
|
||||
{
|
||||
int i;
|
||||
u16 c;
|
||||
u16 buf[16];
|
||||
u16 *pos = buf;
|
||||
|
||||
for (i = 2 * sizeof(val) - 1; i >= 0; --i) {
|
||||
c = (val >> (4 * i)) & 0x0f;
|
||||
if (c || pos != buf || !i || i < prec) {
|
||||
c += '0';
|
||||
if (c > '9')
|
||||
c += 'a' - '9' - 1;
|
||||
*pos++ = c;
|
||||
}
|
||||
}
|
||||
*pos = 0;
|
||||
print(buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* efi_input_yn() - get answer to yes/no question
|
||||
*
|
||||
* Return:
|
||||
* y or Y
|
||||
* EFI_SUCCESS
|
||||
* n or N
|
||||
* EFI_ACCESS_DENIED
|
||||
* ESC
|
||||
* EFI_ABORTED
|
||||
*/
|
||||
static efi_status_t efi_input_yn(void)
|
||||
{
|
||||
struct efi_input_key key = {0};
|
||||
efi_uintn_t index;
|
||||
efi_status_t ret;
|
||||
|
||||
/* Drain the console input */
|
||||
ret = cin->reset(cin, true);
|
||||
for (;;) {
|
||||
ret = bs->wait_for_event(1, &cin->wait_for_key, &index);
|
||||
if (ret != EFI_SUCCESS)
|
||||
continue;
|
||||
ret = cin->read_key_stroke(cin, &key);
|
||||
if (ret != EFI_SUCCESS)
|
||||
continue;
|
||||
switch (key.scan_code) {
|
||||
case 0x17: /* Escape */
|
||||
return EFI_ABORTED;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
/* Convert to lower case */
|
||||
switch (key.unicode_char | 0x20) {
|
||||
case 'y':
|
||||
return EFI_SUCCESS;
|
||||
case 'n':
|
||||
return EFI_ACCESS_DENIED;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* efi_input() - read string from console
|
||||
*
|
||||
* @buffer: input buffer
|
||||
* @buffer_size: buffer size
|
||||
* Return: status code
|
||||
*/
|
||||
static efi_status_t efi_input(u16 *buffer, efi_uintn_t buffer_size)
|
||||
{
|
||||
struct efi_input_key key = {0};
|
||||
efi_uintn_t index;
|
||||
efi_uintn_t pos = 0;
|
||||
u16 outbuf[2] = L" ";
|
||||
efi_status_t ret;
|
||||
|
||||
/* Drain the console input */
|
||||
ret = cin->reset(cin, true);
|
||||
*buffer = 0;
|
||||
for (;;) {
|
||||
ret = bs->wait_for_event(1, &cin->wait_for_key, &index);
|
||||
if (ret != EFI_SUCCESS)
|
||||
continue;
|
||||
ret = cin->read_key_stroke(cin, &key);
|
||||
if (ret != EFI_SUCCESS)
|
||||
continue;
|
||||
switch (key.scan_code) {
|
||||
case 0x17: /* Escape */
|
||||
print(L"\r\nAborted\r\n");
|
||||
return EFI_ABORTED;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
switch (key.unicode_char) {
|
||||
case 0x08: /* Backspace */
|
||||
if (pos) {
|
||||
buffer[pos--] = 0;
|
||||
print(L"\b \b");
|
||||
}
|
||||
break;
|
||||
case 0x0a: /* Linefeed */
|
||||
case 0x0d: /* Carriage return */
|
||||
print(L"\r\n");
|
||||
return EFI_SUCCESS;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
/* Ignore surrogate codes */
|
||||
if (key.unicode_char >= 0xD800 && key.unicode_char <= 0xDBFF)
|
||||
continue;
|
||||
if (key.unicode_char >= 0x20 &&
|
||||
pos < buffer_size - 1) {
|
||||
*outbuf = key.unicode_char;
|
||||
buffer[pos++] = key.unicode_char;
|
||||
buffer[pos] = 0;
|
||||
print(outbuf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* skip_whitespace() - skip over leading whitespace
|
||||
*
|
||||
* @pos: UTF-16 string
|
||||
* Return: pointer to first non-whitespace
|
||||
*/
|
||||
static u16 *skip_whitespace(u16 *pos)
|
||||
{
|
||||
for (; *pos && *pos <= 0x20; ++pos)
|
||||
;
|
||||
return pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* starts_with() - check if @string starts with @keyword
|
||||
*
|
||||
* @string: string to search for keyword
|
||||
* @keyword: keyword to be searched
|
||||
* Return: true fi @string starts with the keyword
|
||||
*/
|
||||
static bool starts_with(u16 *string, u16 *keyword)
|
||||
{
|
||||
for (; *keyword; ++string, ++keyword) {
|
||||
if (*string != *keyword)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* do_help() - print help
|
||||
*/
|
||||
static void do_help(void)
|
||||
{
|
||||
error(L"load - show length and CRC32 of initial RAM disk\r\n");
|
||||
error(L"save <initrd> - save initial RAM disk to file\r\n");
|
||||
error(L"exit - exit the shell\r\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* get_initrd() - read initial RAM disk via EFI_LOAD_FILE2_PROTOCOL
|
||||
*
|
||||
* @initrd: on return buffer with initial RAM disk
|
||||
* @initrd_size: size of initial RAM disk
|
||||
* Return: status code
|
||||
*/
|
||||
static efi_status_t get_initrd(void **initrd, efi_uintn_t *initrd_size)
|
||||
{
|
||||
struct efi_device_path *dp = (struct efi_device_path *)&initrd_dp;
|
||||
struct efi_load_file_protocol *load_file2_prot;
|
||||
u64 buffer;
|
||||
efi_handle_t handle;
|
||||
efi_status_t ret;
|
||||
|
||||
*initrd = NULL;
|
||||
*initrd_size = 0;
|
||||
ret = bs->locate_device_path(&load_file2_guid, &dp, &handle);
|
||||
if (ret != EFI_SUCCESS) {
|
||||
error(L"Load File2 protocol not found\r\n");
|
||||
return ret;
|
||||
}
|
||||
ret = bs->handle_protocol(handle, &load_file2_guid,
|
||||
(void **)&load_file2_prot);
|
||||
ret = load_file2_prot->load_file(load_file2_prot, dp, false,
|
||||
initrd_size, NULL);
|
||||
if (ret != EFI_BUFFER_TOO_SMALL) {
|
||||
error(L"Load File2 protocol does not provide file length\r\n");
|
||||
return EFI_LOAD_ERROR;
|
||||
}
|
||||
ret = bs->allocate_pages(EFI_ALLOCATE_ANY_PAGES, EFI_LOADER_DATA,
|
||||
efi_size_in_pages(*initrd_size), &buffer);
|
||||
if (ret != EFI_SUCCESS) {
|
||||
error(L"Out of memory\r\n");
|
||||
return ret;
|
||||
}
|
||||
*initrd = (void *)buffer;
|
||||
ret = load_file2_prot->load_file(load_file2_prot, dp, false,
|
||||
initrd_size, *initrd);
|
||||
if (ret != EFI_SUCCESS) {
|
||||
error(L"Load File2 protocol failed to provide file\r\n");
|
||||
bs->free_pages(buffer, efi_size_in_pages(*initrd_size));
|
||||
return EFI_LOAD_ERROR;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* do_load() - load initial RAM disk and display CRC32 and length
|
||||
*
|
||||
* @filename: file name
|
||||
* Return: status code
|
||||
*/
|
||||
static efi_status_t do_load(void)
|
||||
{
|
||||
void *initrd;
|
||||
efi_uintn_t initrd_size;
|
||||
u32 crc32;
|
||||
efi_uintn_t ret;
|
||||
|
||||
ret = get_initrd(&initrd, &initrd_size);
|
||||
if (ret != EFI_SUCCESS)
|
||||
return ret;
|
||||
print(L"length: 0x");
|
||||
printx(initrd_size, 1);
|
||||
print(L"\r\n");
|
||||
|
||||
ret = bs->calculate_crc32(initrd, initrd_size, &crc32);
|
||||
if (ret != EFI_SUCCESS) {
|
||||
error(L"Calculating CRC32 failed\r\n");
|
||||
return EFI_LOAD_ERROR;
|
||||
}
|
||||
print(L"crc32: 0x");
|
||||
printx(crc32, 8);
|
||||
print(L"\r\n");
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* do_save() - save initial RAM disk
|
||||
*
|
||||
* @filename: file name
|
||||
* Return: status code
|
||||
*/
|
||||
static efi_status_t do_save(u16 *filename)
|
||||
{
|
||||
struct efi_loaded_image *loaded_image;
|
||||
struct efi_simple_file_system_protocol *file_system;
|
||||
struct efi_file_handle *root, *file;
|
||||
void *initrd;
|
||||
efi_uintn_t initrd_size;
|
||||
efi_uintn_t ret;
|
||||
|
||||
ret = get_initrd(&initrd, &initrd_size);
|
||||
if (ret != EFI_SUCCESS)
|
||||
return ret;
|
||||
|
||||
filename = skip_whitespace(filename);
|
||||
|
||||
ret = bs->open_protocol(handle, &loaded_image_guid,
|
||||
(void **)&loaded_image, NULL, NULL,
|
||||
EFI_OPEN_PROTOCOL_GET_PROTOCOL);
|
||||
if (ret != EFI_SUCCESS) {
|
||||
error(L"Loaded image protocol not found\r\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Open the simple file system protocol */
|
||||
ret = bs->open_protocol(loaded_image->device_handle,
|
||||
&guid_simple_file_system_protocol,
|
||||
(void **)&file_system, NULL, NULL,
|
||||
EFI_OPEN_PROTOCOL_GET_PROTOCOL);
|
||||
if (ret != EFI_SUCCESS) {
|
||||
error(L"Failed to open simple file system protocol\r\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Open volume */
|
||||
ret = file_system->open_volume(file_system, &root);
|
||||
if (ret != EFI_SUCCESS) {
|
||||
error(L"Failed to open volume\r\n");
|
||||
goto out;
|
||||
}
|
||||
/* Check if file already exists */
|
||||
ret = root->open(root, &file, filename, EFI_FILE_MODE_READ, 0);
|
||||
if (ret == EFI_SUCCESS) {
|
||||
file->close(file);
|
||||
print(L"Overwrite existing file (y/n)? ");
|
||||
ret = efi_input_yn();
|
||||
print(L"\r\n");
|
||||
if (ret != EFI_SUCCESS) {
|
||||
root->close(root);
|
||||
error(L"Aborted by user\r\n");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* Create file */
|
||||
ret = root->open(root, &file, filename,
|
||||
EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE |
|
||||
EFI_FILE_MODE_CREATE, EFI_FILE_ARCHIVE);
|
||||
if (ret == EFI_SUCCESS) {
|
||||
/* Write file */
|
||||
ret = file->write(file, &initrd_size, initrd);
|
||||
if (ret != EFI_SUCCESS) {
|
||||
error(L"Failed to write file\r\n");
|
||||
} else {
|
||||
print(filename);
|
||||
print(L" written\r\n");
|
||||
}
|
||||
file->close(file);
|
||||
} else {
|
||||
error(L"Failed to open file\r\n");
|
||||
}
|
||||
root->close(root);
|
||||
|
||||
out:
|
||||
if (initrd)
|
||||
bs->free_pages((uintptr_t)initrd,
|
||||
efi_size_in_pages(initrd_size));
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* efi_main() - entry point of the EFI application.
|
||||
*
|
||||
* @handle: handle of the loaded image
|
||||
* @systab: system table
|
||||
* @return: status code
|
||||
*/
|
||||
efi_status_t EFIAPI efi_main(efi_handle_t image_handle,
|
||||
struct efi_system_table *systab)
|
||||
{
|
||||
handle = image_handle;
|
||||
systable = systab;
|
||||
cerr = systable->std_err;
|
||||
cout = systable->con_out;
|
||||
cin = systable->con_in;
|
||||
bs = systable->boottime;
|
||||
|
||||
cout->set_attribute(cout, EFI_LIGHTBLUE | EFI_BACKGROUND_BLACK);
|
||||
cout->clear_screen(cout);
|
||||
cout->set_attribute(cout, EFI_WHITE | EFI_BACKGROUND_BLACK);
|
||||
print(L"INITRD Dump\r\n========\r\n\r\n");
|
||||
cout->set_attribute(cout, EFI_LIGHTBLUE | EFI_BACKGROUND_BLACK);
|
||||
|
||||
for (;;) {
|
||||
u16 command[BUFFER_SIZE];
|
||||
u16 *pos;
|
||||
efi_uintn_t ret;
|
||||
|
||||
print(L"=> ");
|
||||
ret = efi_input(command, sizeof(command));
|
||||
if (ret == EFI_ABORTED)
|
||||
break;
|
||||
pos = skip_whitespace(command);
|
||||
if (starts_with(pos, L"exit"))
|
||||
break;
|
||||
else if (starts_with(pos, L"load"))
|
||||
do_load();
|
||||
else if (starts_with(pos, L"save "))
|
||||
do_save(pos + 5);
|
||||
else
|
||||
do_help();
|
||||
}
|
||||
|
||||
cout->set_attribute(cout, EFI_LIGHTGRAY | EFI_BACKGROUND_BLACK);
|
||||
cout->clear_screen(cout);
|
||||
return EFI_SUCCESS;
|
||||
}
|
Loading…
Reference in New Issue
Block a user