Pull request for UEFI sub-system for efi-2021-04-rc1

In the UEFI sub-system:
 
 * implement non-blocking file services
 * print boot device and file path in helloworld.efi
 * improve detection of boot device
 * correct argument handling in efivar.py
 * implement EFI_DT_FIXUP_PROTOCOL
 
 Bug fixes:
 
 * adjust conitrace command for low baud rates
 * check that FIT images are valid FDTs
 -----BEGIN PGP SIGNATURE-----
 
 iQIyBAABCAAdFiEEbcT5xx8ppvoGt20zxIHbvCwFGsQFAl//PnIACgkQxIHbvCwF
 GsR57w/xARkciVguTEkfydlhS9Cn+e1J/o77S7rAKF3VojV6sePpDpQOnphdyCf2
 e2XfZUzJ1g3M7QHvdT5xc4WtDXgBlttG+97sttlvV9e9bN8YhaKNNdFwpu0aUT+S
 +eYZ21W6NAS6tqv9w6gK6r0R8M2AIszHxZLpNOdjUAgMqDSXlXNL2cuZUMFH8Y/i
 5VBHmSm2kUVvsjZ1wDYonUFukGjRDSI0ZLLXbQBrt2GkYSc0Cm0BpZ6wlP9uFiOK
 oX0HtjvHFyxNEOsQs584is8gW366Q8qYZL6uBJIHU7zGDH/1xPeAiTtPGt5oY5nG
 pyb/UJ11Js3V6SgIq59zoD52KbeC5th0QObGhV0QdmHc1hGGj4wNdL++eVSU69q7
 Zgq+2lHOaqfHtZXFjSw3RZKKcsY31Dk9G3rEkUYetKOX/QNTEulta0+rpDrhkGBJ
 Us2ZlUpg+vR2+V3TYU+2MfdkCH4QK/pYwUjM8qhfET5iRtzVIo7Ekc9iq662jrwP
 Lcqy7SIfkVIS8bwKQ7La2QkmKmFpjefxrqqnYDA1rnnmnqM1H5AXfBNtF25fm9c3
 bY0HJp36J+pbLYdNRGZcEVNlR+V/G3nRpmWGoQZp8C0CqHsXilOmj7lwqj5C26xl
 7322bW5vjCmkRbQzmg3sBBtZ4BzS8jNXgO5Ru+jHe6BUfnxi8g==
 =QOqG
 -----END PGP SIGNATURE-----

Merge tag 'efi-2021-04-rc1' of https://gitlab.denx.de/u-boot/custodians/u-boot-efi

Pull request for UEFI sub-system for efi-2021-04-rc1

In the UEFI sub-system:

* implement non-blocking file services
* print boot device and file path in helloworld.efi
* improve detection of boot device
* correct argument handling in efivar.py
* implement EFI_DT_FIXUP_PROTOCOL

Bug fixes:

* adjust conitrace command for low baud rates
* check that FIT images are valid FDTs
This commit is contained in:
Tom Rini 2021-01-14 08:50:23 -05:00
commit 35772ff4f6
21 changed files with 1106 additions and 364 deletions

View File

@ -29,6 +29,82 @@ DECLARE_GLOBAL_DATA_PTR;
static struct efi_device_path *bootefi_image_path;
static struct efi_device_path *bootefi_device_path;
static void *image_addr;
static size_t image_size;
/**
* efi_clear_bootdev() - clear boot device
*/
static void efi_clear_bootdev(void)
{
efi_free_pool(bootefi_device_path);
efi_free_pool(bootefi_image_path);
bootefi_device_path = NULL;
bootefi_image_path = NULL;
image_addr = NULL;
image_size = 0;
}
/**
* efi_set_bootdev() - set boot device
*
* This function is called when a file is loaded, e.g. via the 'load' command.
* We use the path to this file to inform the UEFI binary about the boot device.
*
* @dev: device, e.g. "MMC"
* @devnr: number of the device, e.g. "1:2"
* @path: path to file loaded
* @buffer: buffer with file loaded
* @buffer_size: size of file loaded
*/
void efi_set_bootdev(const char *dev, const char *devnr, const char *path,
void *buffer, size_t buffer_size)
{
struct efi_device_path *device, *image;
efi_status_t ret;
/* Forget overwritten image */
if (buffer + buffer_size >= image_addr &&
image_addr + image_size >= buffer)
efi_clear_bootdev();
/* Remember only PE-COFF and FIT images */
if (efi_check_pe(buffer, buffer_size, NULL) != EFI_SUCCESS) {
#ifdef CONFIG_FIT
if (!fit_check_format(buffer))
return;
/*
* FIT images of type EFI_OS are started via command bootm.
* We should not use their boot device with the bootefi command.
*/
buffer = 0;
buffer_size = 0;
#else
return;
#endif
}
/* efi_set_bootdev() is typically called repeatedly, recover memory */
efi_clear_bootdev();
image_addr = buffer;
image_size = buffer_size;
ret = efi_dp_from_name(dev, devnr, path, &device, &image);
if (ret == EFI_SUCCESS) {
bootefi_device_path = device;
if (image) {
/* FIXME: image should not contain device */
struct efi_device_path *image_tmp = image;
efi_dp_split_file_path(image, &device, &image);
efi_free_pool(image_tmp);
}
bootefi_image_path = image;
} else {
efi_clear_bootdev();
}
}
/**
* efi_env_set_load_options() - set load options from environment variable
@ -135,86 +211,6 @@ done:
return ret;
}
/**
* efi_reserve_memory() - add reserved memory to memory map
*
* @addr: start address of the reserved memory range
* @size: size of the reserved memory range
* @nomap: indicates that the memory range shall not be accessed by the
* UEFI payload
*/
static void efi_reserve_memory(u64 addr, u64 size, bool nomap)
{
int type;
efi_uintn_t ret;
/* Convert from sandbox address space. */
addr = (uintptr_t)map_sysmem(addr, 0);
if (nomap)
type = EFI_RESERVED_MEMORY_TYPE;
else
type = EFI_BOOT_SERVICES_DATA;
ret = efi_add_memory_map(addr, size, type);
if (ret != EFI_SUCCESS)
log_err("Reserved memory mapping failed addr %llx size %llx\n",
addr, size);
}
/**
* efi_carve_out_dt_rsv() - Carve out DT reserved memory ranges
*
* The mem_rsv entries of the FDT are added to the memory map. Any failures are
* ignored because this is not critical and we would rather continue to try to
* boot.
*
* @fdt: Pointer to device tree
*/
static void efi_carve_out_dt_rsv(void *fdt)
{
int nr_rsv, i;
u64 addr, size;
int nodeoffset, subnode;
nr_rsv = fdt_num_mem_rsv(fdt);
/* Look for an existing entry and add it to the efi mem map. */
for (i = 0; i < nr_rsv; i++) {
if (fdt_get_mem_rsv(fdt, i, &addr, &size) != 0)
continue;
efi_reserve_memory(addr, size, false);
}
/* process reserved-memory */
nodeoffset = fdt_subnode_offset(fdt, 0, "reserved-memory");
if (nodeoffset >= 0) {
subnode = fdt_first_subnode(fdt, nodeoffset);
while (subnode >= 0) {
fdt_addr_t fdt_addr;
fdt_size_t fdt_size;
/* check if this subnode has a reg property */
fdt_addr = fdtdec_get_addr_size_auto_parent(
fdt, nodeoffset, subnode,
"reg", 0, &fdt_size, false);
/*
* The /reserved-memory node may have children with
* a size instead of a reg property.
*/
if (fdt_addr != FDT_ADDR_T_NONE &&
fdtdec_get_is_enabled(fdt, subnode)) {
bool nomap;
nomap = !!fdt_getprop(fdt, subnode, "no-map",
NULL);
efi_reserve_memory(fdt_addr, fdt_size, nomap);
}
subnode = fdt_next_subnode(fdt, subnode);
}
}
}
/**
* get_config_table() - get configuration table
*
@ -398,43 +394,28 @@ static int do_bootefi_image(const char *image_opt)
{
void *image_buf;
unsigned long addr, size;
const char *size_str;
efi_status_t ret;
#ifdef CONFIG_CMD_BOOTEFI_HELLO
if (!strcmp(image_opt, "hello")) {
char *saddr;
saddr = env_get("loadaddr");
image_buf = __efi_helloworld_begin;
size = __efi_helloworld_end - __efi_helloworld_begin;
if (saddr)
addr = simple_strtoul(saddr, NULL, 16);
else
addr = CONFIG_SYS_LOAD_ADDR;
image_buf = map_sysmem(addr, size);
memcpy(image_buf, __efi_helloworld_begin, size);
efi_free_pool(bootefi_device_path);
efi_free_pool(bootefi_image_path);
bootefi_device_path = NULL;
bootefi_image_path = NULL;
efi_clear_bootdev();
} else
#endif
{
size_str = env_get("filesize");
if (size_str)
size = simple_strtoul(size_str, NULL, 16);
else
size = 0;
addr = simple_strtoul(image_opt, NULL, 16);
addr = strtoul(image_opt, NULL, 16);
/* Check that a numeric value was passed */
if (!addr && *image_opt != '0')
if (!addr)
return CMD_RET_USAGE;
image_buf = map_sysmem(addr, size);
image_buf = map_sysmem(addr, 0);
if (image_buf != image_addr) {
log_err("No UEFI binary known at %s\n", image_opt);
return CMD_RET_FAILURE;
}
size = image_size;
}
ret = efi_run_image(image_buf, size);
@ -567,11 +548,8 @@ static efi_status_t bootefi_test_prepare
if (ret == EFI_SUCCESS)
return ret;
efi_free_pool(bootefi_image_path);
bootefi_image_path = NULL;
failure:
efi_free_pool(bootefi_device_path);
bootefi_device_path = NULL;
efi_clear_bootdev();
return ret;
}
@ -691,39 +669,3 @@ U_BOOT_CMD(
"Boots an EFI payload from memory",
bootefi_help_text
);
/**
* efi_set_bootdev() - set boot device
*
* This function is called when a file is loaded, e.g. via the 'load' command.
* We use the path to this file to inform the UEFI binary about the boot device.
*
* @dev: device, e.g. "MMC"
* @devnr: number of the device, e.g. "1:2"
* @path: path to file loaded
*/
void efi_set_bootdev(const char *dev, const char *devnr, const char *path)
{
struct efi_device_path *device, *image;
efi_status_t ret;
/* efi_set_bootdev is typically called repeatedly, recover memory */
efi_free_pool(bootefi_device_path);
efi_free_pool(bootefi_image_path);
ret = efi_dp_from_name(dev, devnr, path, &device, &image);
if (ret == EFI_SUCCESS) {
bootefi_device_path = device;
if (image) {
/* FIXME: image should not contain device */
struct efi_device_path *image_tmp = image;
efi_dp_split_file_path(image, &device, &image);
efi_free_pool(image_tmp);
}
bootefi_image_path = image;
} else {
bootefi_device_path = NULL;
bootefi_image_path = NULL;
}
}

View File

@ -30,8 +30,8 @@ static int do_conitrace(struct cmd_tbl *cmdtp, int flag, int argc,
printf("%02x ", c);
first = false;
/* 1 ms delay - serves to detect separate keystrokes */
udelay(1000);
/* 10 ms delay - serves to detect separate keystrokes */
udelay(10000);
if (!tstc()) {
printf("\n");
first = true;

View File

@ -8,6 +8,7 @@
#include <charset.h>
#include <common.h>
#include <command.h>
#include <efi_dt_fixup.h>
#include <efi_loader.h>
#include <efi_rng.h>
#include <exports.h>
@ -495,6 +496,10 @@ static const struct {
"PXE Base Code",
EFI_PXE_BASE_CODE_PROTOCOL_GUID,
},
{
"Device-Tree Fixup",
EFI_DT_FIXUP_PROTOCOL_GUID,
},
/* Configuration table GUIDs */
{
"ACPI table",

View File

@ -1553,6 +1553,12 @@ int fit_image_check_comp(const void *fit, int noffset, uint8_t comp)
*/
int fit_check_format(const void *fit)
{
/* A FIT image must be a valid FDT */
if (fdt_check_header(fit)) {
debug("Wrong FIT format: not a flattened device tree\n");
return 0;
}
/* mandatory / node 'description' property */
if (fdt_getprop(fit, 0, FIT_DESC_PROP, NULL) == NULL) {
debug("Wrong FIT format: no description\n");

View File

@ -59,13 +59,10 @@ Below you find the output of an example session starting GRUB::
120832 bytes read in 7 ms (16.5 MiB/s)
=> bootefi ${kernel_addr_r} ${fdt_addr_r}
The bootefi command uses the device, the file name, and the file size
(environment variable 'filesize') of the most recently loaded file when setting
up the binary for execution. So the UEFI binary should be loaded last.
The environment variable 'bootargs' is passed as load options in the UEFI system
table. The Linux kernel EFI stub uses the load options as command line
arguments.
When booting from a memory location it is unknown from which file it was loaded.
Therefore the bootefi command uses the device path of the block device partition
or the network adapter and the file name of the most recently loaded PE-COFF
file when setting up the loaded image protocol.
Launching a UEFI binary from a FIT image
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -752,7 +752,8 @@ int do_load(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[],
if (IS_ENABLED(CONFIG_CMD_BOOTEFI))
efi_set_bootdev(argv[1], (argc > 2) ? argv[2] : "",
(argc > 4) ? argv[4] : "");
(argc > 4) ? argv[4] : "", map_sysmem(addr, 0),
len_read);
printf("%llu bytes read in %lu ms", len_read, time);
if (time > 0) {

View File

@ -20,6 +20,11 @@
#include <linux/string.h>
#include <linux/types.h>
/* Type INTN in UEFI specification */
#define efi_intn_t ssize_t
/* Type UINTN in UEFI specification*/
#define efi_uintn_t size_t
/*
* EFI on x86_64 uses the Microsoft ABI which is not the default for GCC.
*

View File

@ -34,8 +34,6 @@ enum efi_timer_delay {
EFI_TIMER_RELATIVE = 2
};
#define efi_intn_t ssize_t
#define efi_uintn_t size_t
typedef void *efi_hii_handle_t;
typedef u16 *efi_string_t;
typedef u16 efi_string_id_t;
@ -703,10 +701,10 @@ struct efi_simple_text_output_protocol {
char extended_verification);
efi_status_t (EFIAPI *output_string)(
struct efi_simple_text_output_protocol *this,
const efi_string_t str);
const u16 *str);
efi_status_t (EFIAPI *test_string)(
struct efi_simple_text_output_protocol *this,
const efi_string_t str);
const u16 *str);
efi_status_t(EFIAPI *query_mode)(
struct efi_simple_text_output_protocol *this,
unsigned long mode_number, unsigned long *columns,
@ -1589,35 +1587,35 @@ struct efi_file_io_token {
struct efi_file_handle {
u64 rev;
efi_status_t (EFIAPI *open)(struct efi_file_handle *file,
efi_status_t (EFIAPI *open)(struct efi_file_handle *this,
struct efi_file_handle **new_handle,
u16 *file_name, u64 open_mode, u64 attributes);
efi_status_t (EFIAPI *close)(struct efi_file_handle *file);
efi_status_t (EFIAPI *delete)(struct efi_file_handle *file);
efi_status_t (EFIAPI *read)(struct efi_file_handle *file,
efi_status_t (EFIAPI *close)(struct efi_file_handle *this);
efi_status_t (EFIAPI *delete)(struct efi_file_handle *this);
efi_status_t (EFIAPI *read)(struct efi_file_handle *this,
efi_uintn_t *buffer_size, void *buffer);
efi_status_t (EFIAPI *write)(struct efi_file_handle *file,
efi_status_t (EFIAPI *write)(struct efi_file_handle *this,
efi_uintn_t *buffer_size, void *buffer);
efi_status_t (EFIAPI *getpos)(struct efi_file_handle *file,
efi_status_t (EFIAPI *getpos)(struct efi_file_handle *this,
u64 *pos);
efi_status_t (EFIAPI *setpos)(struct efi_file_handle *file,
efi_status_t (EFIAPI *setpos)(struct efi_file_handle *this,
u64 pos);
efi_status_t (EFIAPI *getinfo)(struct efi_file_handle *file,
efi_status_t (EFIAPI *getinfo)(struct efi_file_handle *this,
const efi_guid_t *info_type, efi_uintn_t *buffer_size,
void *buffer);
efi_status_t (EFIAPI *setinfo)(struct efi_file_handle *file,
efi_status_t (EFIAPI *setinfo)(struct efi_file_handle *this,
const efi_guid_t *info_type, efi_uintn_t buffer_size,
void *buffer);
efi_status_t (EFIAPI *flush)(struct efi_file_handle *file);
efi_status_t (EFIAPI *open_ex)(struct efi_file_handle *file,
efi_status_t (EFIAPI *flush)(struct efi_file_handle *this);
efi_status_t (EFIAPI *open_ex)(struct efi_file_handle *this,
struct efi_file_handle **new_handle,
u16 *file_name, u64 open_mode, u64 attributes,
struct efi_file_io_token *token);
efi_status_t (EFIAPI *read_ex)(struct efi_file_handle *file,
efi_status_t (EFIAPI *read_ex)(struct efi_file_handle *this,
struct efi_file_io_token *token);
efi_status_t (EFIAPI *write_ex)(struct efi_file_handle *file,
efi_status_t (EFIAPI *write_ex)(struct efi_file_handle *this,
struct efi_file_io_token *token);
efi_status_t (EFIAPI *flush_ex)(struct efi_file_handle *file,
efi_status_t (EFIAPI *flush_ex)(struct efi_file_handle *this,
struct efi_file_io_token *token);
};

39
include/efi_dt_fixup.h Normal file
View File

@ -0,0 +1,39 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* EFI_DT_FIXUP_PROTOCOL
*
* Copyright (c) 2020 Heinrich Schuchardt
*/
#include <efi_api.h>
#define EFI_DT_FIXUP_PROTOCOL_GUID \
EFI_GUID(0xe617d64c, 0xfe08, 0x46da, 0xf4, 0xdc, \
0xbb, 0xd5, 0x87, 0x0c, 0x73, 0x00)
#define EFI_DT_FIXUP_PROTOCOL_REVISION 0x00010000
/* Add nodes and update properties */
#define EFI_DT_APPLY_FIXUPS 0x00000001
/*
* Reserve memory according to the /reserved-memory node
* and the memory reservation block
*/
#define EFI_DT_RESERVE_MEMORY 0x00000002
/* Install the device-tree as configuration table */
#define EFI_DT_INSTALL_TABLE 0x00000004
#define EFI_DT_ALL (EFI_DT_APPLY_FIXUPS | \
EFI_DT_RESERVE_MEMORY | \
EFI_DT_INSTALL_TABLE)
struct efi_dt_fixup_protocol {
u64 revision;
efi_status_t (EFIAPI *fixup) (struct efi_dt_fixup_protocol *this,
void *dtb,
efi_uintn_t *buffer_size,
u32 flags);
};
extern struct efi_dt_fixup_protocol efi_dt_fixup_prot;
extern const efi_guid_t efi_guid_dt_fixup_protocol;

View File

@ -411,6 +411,8 @@ void efi_runtime_detach(void);
/* efi_convert_pointer() - convert pointer to virtual address */
efi_status_t EFIAPI efi_convert_pointer(efi_uintn_t debug_disposition,
void **address);
/* Carve out DT reserved memory ranges */
void efi_carve_out_dt_rsv(void *fdt);
/* Called by bootefi to make console interface available */
efi_status_t efi_console_register(void);
/* Called by bootefi to make all disk storage accessible as EFI objects */
@ -460,6 +462,8 @@ efi_status_t efi_set_watchdog(unsigned long timeout);
/* Called from places to check whether a timer expired */
void efi_timer_check(void);
/* Check if a buffer contains a PE-COFF image */
efi_status_t efi_check_pe(void *buffer, size_t size, void **nt_header);
/* PE loader implementation */
efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle,
void *efi, size_t efi_size,
@ -472,7 +476,8 @@ void efi_restore_gd(void);
/* Call this to relocate the runtime section to an address space */
void efi_runtime_relocate(ulong offset, struct efi_mem_desc *map);
/* Call this to set the current device name */
void efi_set_bootdev(const char *dev, const char *devnr, const char *path);
void efi_set_bootdev(const char *dev, const char *devnr, const char *path,
void *buffer, size_t buffer_size);
/* Add a new object to the object list. */
void efi_add_handle(efi_handle_t obj);
/* Create handle */
@ -871,7 +876,8 @@ static inline efi_status_t efi_add_runtime_mmio(void *mmio_ptr, u64 len)
/* No loader configured, stub out EFI_ENTRY */
static inline void efi_restore_gd(void) { }
static inline void efi_set_bootdev(const char *dev, const char *devnr,
const char *path) { }
const char *path, void *buffer,
size_t buffer_size) { }
static inline void efi_net_set_dhcp_ack(void *pkt, int len) { }
static inline void efi_print_image_infos(void *pc) { }
static inline efi_status_t efi_launch_capsules(void)

View File

@ -29,6 +29,9 @@ 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
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

View File

@ -141,12 +141,12 @@ static int term_read_reply(int *n, int num, char end_char)
*/
static efi_status_t EFIAPI efi_cout_output_string(
struct efi_simple_text_output_protocol *this,
const efi_string_t string)
const u16 *string)
{
struct simple_text_output_mode *con = &efi_con_mode;
struct cout_mode *mode = &efi_cout_modes[con->mode];
char *buf, *pos;
u16 *p;
const u16 *p;
efi_status_t ret = EFI_SUCCESS;
EFI_ENTRY("%p, %p", this, string);
@ -230,7 +230,7 @@ out:
*/
static efi_status_t EFIAPI efi_cout_test_string(
struct efi_simple_text_output_protocol *this,
const efi_string_t string)
const u16 *string)
{
EFI_ENTRY("%p, %p", this, string);
return EFI_EXIT(EFI_SUCCESS);

View File

@ -0,0 +1,160 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* EFI_DT_FIXUP_PROTOCOL
*
* Copyright (c) 2020 Heinrich Schuchardt
*/
#include <common.h>
#include <efi_dt_fixup.h>
#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;
/**
* efi_reserve_memory() - add reserved memory to memory map
*
* @addr: start address of the reserved memory range
* @size: size of the reserved memory range
* @nomap: indicates that the memory range shall not be accessed by the
* UEFI payload
*/
static void efi_reserve_memory(u64 addr, u64 size, bool nomap)
{
int type;
efi_uintn_t ret;
/* Convert from sandbox address space. */
addr = (uintptr_t)map_sysmem(addr, 0);
if (nomap)
type = EFI_RESERVED_MEMORY_TYPE;
else
type = EFI_BOOT_SERVICES_DATA;
ret = efi_add_memory_map(addr, size, type);
if (ret != EFI_SUCCESS)
log_err("Reserved memory mapping failed addr %llx size %llx\n",
addr, size);
}
/**
* efi_carve_out_dt_rsv() - Carve out DT reserved memory ranges
*
* The mem_rsv entries of the FDT are added to the memory map. Any failures are
* ignored because this is not critical and we would rather continue to try to
* boot.
*
* @fdt: Pointer to device tree
*/
void efi_carve_out_dt_rsv(void *fdt)
{
int nr_rsv, i;
u64 addr, size;
int nodeoffset, subnode;
nr_rsv = fdt_num_mem_rsv(fdt);
/* Look for an existing entry and add it to the efi mem map. */
for (i = 0; i < nr_rsv; i++) {
if (fdt_get_mem_rsv(fdt, i, &addr, &size) != 0)
continue;
efi_reserve_memory(addr, size, false);
}
/* process reserved-memory */
nodeoffset = fdt_subnode_offset(fdt, 0, "reserved-memory");
if (nodeoffset >= 0) {
subnode = fdt_first_subnode(fdt, nodeoffset);
while (subnode >= 0) {
fdt_addr_t fdt_addr;
fdt_size_t fdt_size;
/* check if this subnode has a reg property */
fdt_addr = fdtdec_get_addr_size_auto_parent(
fdt, nodeoffset, subnode,
"reg", 0, &fdt_size, false);
/*
* The /reserved-memory node may have children with
* a size instead of a reg property.
*/
if (fdt_addr != FDT_ADDR_T_NONE &&
fdtdec_get_is_enabled(fdt, subnode)) {
bool nomap;
nomap = !!fdt_getprop(fdt, subnode, "no-map",
NULL);
efi_reserve_memory(fdt_addr, fdt_size, nomap);
}
subnode = fdt_next_subnode(fdt, subnode);
}
}
}
static efi_status_t 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;
bootm_headers_t img = { 0 };
EFI_ENTRY("%p, %p, %p, %d", this, dtb, buffer_size, flags);
if (this != &efi_dt_fixup_prot || !dtb || !buffer_size ||
!flags || (flags & ~EFI_DT_ALL)) {
ret = EFI_INVALID_PARAMETER;
goto out;
}
if (fdt_check_header(dtb)) {
ret = EFI_INVALID_PARAMETER;
goto out;
}
if (flags & EFI_DT_APPLY_FIXUPS) {
required_size = fdt_off_dt_strings(dtb) +
fdt_size_dt_strings(dtb) +
0x3000;
} else {
required_size = fdt_totalsize(dtb);
}
if (required_size > *buffer_size) {
*buffer_size = required_size;
ret = EFI_BUFFER_TOO_SMALL;
goto out;
}
fdt_set_totalsize(dtb, *buffer_size);
if (flags & EFI_DT_APPLY_FIXUPS) {
if (image_setup_libfdt(&img, dtb, 0, NULL)) {
log_err("failed to process device tree\n");
ret = EFI_INVALID_PARAMETER;
goto out;
}
}
if (flags & EFI_DT_RESERVE_MEMORY)
efi_carve_out_dt_rsv(dtb);
if (EFI_DT_INSTALL_TABLE) {
ret = efi_install_configuration_table(&efi_guid_fdt, dtb);
if (ret != EFI_SUCCESS) {
log_err("ERROR: failed to install device tree\n");
goto out;
}
}
ret = EFI_SUCCESS;
out:
return EFI_EXIT(ret);
}

View File

@ -246,18 +246,16 @@ error:
return NULL;
}
static efi_status_t EFIAPI efi_file_open(struct efi_file_handle *file,
struct efi_file_handle **new_handle,
u16 *file_name, u64 open_mode, u64 attributes)
static efi_status_t efi_file_open_int(struct efi_file_handle *this,
struct efi_file_handle **new_handle,
u16 *file_name, u64 open_mode,
u64 attributes)
{
struct file_handle *fh = to_fh(file);
struct file_handle *fh = to_fh(this);
efi_status_t ret;
EFI_ENTRY("%p, %p, \"%ls\", %llx, %llu", file, new_handle,
file_name, open_mode, attributes);
/* Check parameters */
if (!file || !new_handle || !file_name) {
if (!this || !new_handle || !file_name) {
ret = EFI_INVALID_PARAMETER;
goto out;
}
@ -291,6 +289,75 @@ static efi_status_t EFIAPI efi_file_open(struct efi_file_handle *file,
} else {
ret = EFI_NOT_FOUND;
}
out:
return ret;
}
/**
* efi_file_open_()
*
* This function implements the Open service of the File Protocol.
* See the UEFI spec for details.
*
* @this: EFI_FILE_PROTOCOL instance
* @new_handle: on return pointer to file handle
* @file_name: file name
* @open_mode: mode to open the file (read, read/write, create/read/write)
* @attributes: attributes for newly created file
*/
static efi_status_t EFIAPI efi_file_open(struct efi_file_handle *this,
struct efi_file_handle **new_handle,
u16 *file_name, u64 open_mode,
u64 attributes)
{
efi_status_t ret;
EFI_ENTRY("%p, %p, \"%ls\", %llx, %llu", this, new_handle,
file_name, open_mode, attributes);
ret = efi_file_open_int(this, new_handle, file_name, open_mode,
attributes);
return EFI_EXIT(ret);
}
/**
* efi_file_open_ex() - open file asynchronously
*
* This function implements the OpenEx service of the File Protocol.
* See the UEFI spec for details.
*
* @this: EFI_FILE_PROTOCOL instance
* @new_handle: on return pointer to file handle
* @file_name: file name
* @open_mode: mode to open the file (read, read/write, create/read/write)
* @attributes: attributes for newly created file
* @token: transaction token
*/
static efi_status_t EFIAPI efi_file_open_ex(struct efi_file_handle *this,
struct efi_file_handle **new_handle,
u16 *file_name, u64 open_mode,
u64 attributes,
struct efi_file_io_token *token)
{
efi_status_t ret;
EFI_ENTRY("%p, %p, \"%ls\", %llx, %llu, %p", this, new_handle,
file_name, open_mode, attributes, token);
if (!token) {
ret = EFI_INVALID_PARAMETER;
goto out;
}
ret = efi_file_open_int(this, new_handle, file_name, open_mode,
attributes);
if (ret == EFI_SUCCESS && token->event) {
token->status = EFI_SUCCESS;
efi_signal_event(token->event);
}
out:
return EFI_EXIT(ret);
}
@ -441,19 +508,15 @@ static efi_status_t dir_read(struct file_handle *fh, u64 *buffer_size,
return EFI_SUCCESS;
}
static efi_status_t EFIAPI efi_file_read(struct efi_file_handle *file,
efi_uintn_t *buffer_size, void *buffer)
static efi_status_t efi_file_read_int(struct efi_file_handle *this,
efi_uintn_t *buffer_size, void *buffer)
{
struct file_handle *fh = to_fh(file);
struct file_handle *fh = to_fh(this);
efi_status_t ret = EFI_SUCCESS;
u64 bs;
EFI_ENTRY("%p, %p, %p", file, buffer_size, buffer);
if (!buffer_size) {
ret = EFI_INVALID_PARAMETER;
goto error;
}
if (!this || !buffer_size || !buffer)
return EFI_INVALID_PARAMETER;
bs = *buffer_size;
if (fh->isdir)
@ -465,34 +528,77 @@ static efi_status_t EFIAPI efi_file_read(struct efi_file_handle *file,
else
*buffer_size = SIZE_MAX;
error:
return EFI_EXIT(ret);
return ret;
}
/**
* efi_file_write() - write to file
* efi_file_read() - read file
*
* This function implements the Write() service of the EFI_FILE_PROTOCOL.
* This function implements the Read() service of the EFI_FILE_PROTOCOL.
*
* See the Unified Extensible Firmware Interface (UEFI) specification for
* details.
*
* @file: file handle
* @buffer_size: number of bytes to write
* @buffer: buffer with the bytes to write
* @this: file protocol instance
* @buffer_size: number of bytes to read
* @buffer: read buffer
* Return: status code
*/
static efi_status_t EFIAPI efi_file_write(struct efi_file_handle *file,
efi_uintn_t *buffer_size,
void *buffer)
static efi_status_t EFIAPI efi_file_read(struct efi_file_handle *this,
efi_uintn_t *buffer_size, void *buffer)
{
struct file_handle *fh = to_fh(file);
efi_status_t ret;
EFI_ENTRY("%p, %p, %p", this, buffer_size, buffer);
ret = efi_file_read_int(this, buffer_size, buffer);
return EFI_EXIT(ret);
}
/**
* efi_file_read_ex() - read file asynchonously
*
* This function implements the ReadEx() service of the EFI_FILE_PROTOCOL.
*
* See the Unified Extensible Firmware Interface (UEFI) specification for
* details.
*
* @this: file protocol instance
* @token: transaction token
* Return: status code
*/
static efi_status_t EFIAPI efi_file_read_ex(struct efi_file_handle *this,
struct efi_file_io_token *token)
{
efi_status_t ret;
EFI_ENTRY("%p, %p", this, token);
if (!token) {
ret = EFI_INVALID_PARAMETER;
goto out;
}
ret = efi_file_read_int(this, &token->buffer_size, token->buffer);
if (ret == EFI_SUCCESS && token->event) {
token->status = EFI_SUCCESS;
efi_signal_event(token->event);
}
out:
return EFI_EXIT(ret);
}
static efi_status_t efi_file_write_int(struct efi_file_handle *this,
efi_uintn_t *buffer_size, void *buffer)
{
struct file_handle *fh = to_fh(this);
efi_status_t ret = EFI_SUCCESS;
loff_t actwrite;
EFI_ENTRY("%p, %p, %p", file, buffer_size, buffer);
if (!file || !buffer_size || !buffer) {
if (!this || !buffer_size || !buffer) {
ret = EFI_INVALID_PARAMETER;
goto out;
}
@ -520,6 +626,67 @@ static efi_status_t EFIAPI efi_file_write(struct efi_file_handle *file,
*buffer_size = actwrite;
fh->offset += actwrite;
out:
return ret;
}
/**
* efi_file_write() - write to file
*
* This function implements the Write() service of the EFI_FILE_PROTOCOL.
*
* See the Unified Extensible Firmware Interface (UEFI) specification for
* details.
*
* @this: file protocol instance
* @buffer_size: number of bytes to write
* @buffer: buffer with the bytes to write
* Return: status code
*/
static efi_status_t EFIAPI efi_file_write(struct efi_file_handle *this,
efi_uintn_t *buffer_size,
void *buffer)
{
efi_status_t ret;
EFI_ENTRY("%p, %p, %p", this, buffer_size, buffer);
ret = efi_file_write_int(this, buffer_size, buffer);
return EFI_EXIT(ret);
}
/**
* efi_file_write_ex() - write to file
*
* This function implements the WriteEx() service of the EFI_FILE_PROTOCOL.
*
* See the Unified Extensible Firmware Interface (UEFI) specification for
* details.
*
* @this: file protocol instance
* @token: transaction token
* Return: status code
*/
static efi_status_t EFIAPI efi_file_write_ex(struct efi_file_handle *this,
struct efi_file_io_token *token)
{
efi_status_t ret;
EFI_ENTRY("%p, %p", this, token);
if (!token) {
ret = EFI_INVALID_PARAMETER;
goto out;
}
ret = efi_file_write_int(this, &token->buffer_size, token->buffer);
if (ret == EFI_SUCCESS && token->event) {
token->status = EFI_SUCCESS;
efi_signal_event(token->event);
}
out:
return EFI_EXIT(ret);
}
@ -761,36 +928,84 @@ out:
return EFI_EXIT(ret);
}
static efi_status_t EFIAPI efi_file_flush(struct efi_file_handle *file)
/**
* efi_file_flush_int() - flush file
*
* This is the internal implementation of the Flush() and FlushEx() services of
* the EFI_FILE_PROTOCOL.
*
* @this: file protocol instance
* Return: status code
*/
static efi_status_t efi_file_flush_int(struct efi_file_handle *this)
{
EFI_ENTRY("%p", file);
return EFI_EXIT(EFI_SUCCESS);
struct file_handle *fh = to_fh(this);
if (!this)
return EFI_INVALID_PARAMETER;
if (!(fh->open_mode & EFI_FILE_MODE_WRITE))
return EFI_ACCESS_DENIED;
/* TODO: flush for file position after end of file */
return EFI_SUCCESS;
}
static efi_status_t EFIAPI efi_file_open_ex(struct efi_file_handle *file,
struct efi_file_handle **new_handle,
u16 *file_name, u64 open_mode, u64 attributes,
struct efi_file_io_token *token)
/**
* efi_file_flush() - flush file
*
* This function implements the Flush() service of the EFI_FILE_PROTOCOL.
*
* See the Unified Extensible Firmware Interface (UEFI) specification for
* details.
*
* @this: file protocol instance
* Return: status code
*/
static efi_status_t EFIAPI efi_file_flush(struct efi_file_handle *this)
{
return EFI_UNSUPPORTED;
efi_status_t ret;
EFI_ENTRY("%p", this);
ret = efi_file_flush_int(this);
return EFI_EXIT(ret);
}
static efi_status_t EFIAPI efi_file_read_ex(struct efi_file_handle *file,
struct efi_file_io_token *token)
/**
* efi_file_flush_ex() - flush file
*
* This function implements the FlushEx() service of the EFI_FILE_PROTOCOL.
*
* See the Unified Extensible Firmware Interface (UEFI) specification for
* details.
*
* @this: file protocol instance
* @token: transaction token
* Return: status code
*/
static efi_status_t EFIAPI efi_file_flush_ex(struct efi_file_handle *this,
struct efi_file_io_token *token)
{
return EFI_UNSUPPORTED;
}
efi_status_t ret;
static efi_status_t EFIAPI efi_file_write_ex(struct efi_file_handle *file,
struct efi_file_io_token *token)
{
return EFI_UNSUPPORTED;
}
EFI_ENTRY("%p, %p", this, token);
static efi_status_t EFIAPI efi_file_flush_ex(struct efi_file_handle *file,
struct efi_file_io_token *token)
{
return EFI_UNSUPPORTED;
if (!token) {
ret = EFI_INVALID_PARAMETER;
goto out;
}
ret = efi_file_flush_int(this);
if (ret == EFI_SUCCESS && token->event) {
token->status = EFI_SUCCESS;
efi_signal_event(token->event);
}
out:
return EFI_EXIT(ret);
}
static const struct efi_file_handle efi_file_handle_protocol = {

View File

@ -675,6 +675,46 @@ static bool efi_image_authenticate(void *efi, size_t efi_size)
}
#endif /* CONFIG_EFI_SECURE_BOOT */
/**
* efi_check_pe() - check if a memory buffer contains a PE-COFF image
*
* @buffer: buffer to check
* @size: size of buffer
* @nt_header: on return pointer to NT header of PE-COFF image
* Return: EFI_SUCCESS if the buffer contains a PE-COFF image
*/
efi_status_t efi_check_pe(void *buffer, size_t size, void **nt_header)
{
IMAGE_DOS_HEADER *dos = buffer;
IMAGE_NT_HEADERS32 *nt;
if (size < sizeof(*dos))
return EFI_INVALID_PARAMETER;
/* Check for DOS magix */
if (dos->e_magic != IMAGE_DOS_SIGNATURE)
return EFI_INVALID_PARAMETER;
/*
* Check if the image section header fits into the file. Knowing that at
* least one section header follows we only need to check for the length
* of the 64bit header which is longer than the 32bit header.
*/
if (size < dos->e_lfanew + sizeof(IMAGE_NT_HEADERS32))
return EFI_INVALID_PARAMETER;
nt = (IMAGE_NT_HEADERS32 *)((u8 *)buffer + dos->e_lfanew);
/* Check for PE-COFF magic */
if (nt->Signature != IMAGE_NT_SIGNATURE)
return EFI_INVALID_PARAMETER;
if (nt_header)
*nt_header = nt;
return EFI_SUCCESS;
}
/**
* efi_load_pe() - relocate EFI binary
*
@ -705,36 +745,10 @@ efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle,
int supported = 0;
efi_status_t ret;
/* Sanity check for a file header */
if (efi_size < sizeof(*dos)) {
log_err("Truncated DOS Header\n");
ret = EFI_LOAD_ERROR;
goto err;
}
dos = efi;
if (dos->e_magic != IMAGE_DOS_SIGNATURE) {
log_err("Invalid DOS Signature\n");
ret = EFI_LOAD_ERROR;
goto err;
}
/*
* Check if the image section header fits into the file. Knowing that at
* least one section header follows we only need to check for the length
* of the 64bit header which is longer than the 32bit header.
*/
if (efi_size < dos->e_lfanew + sizeof(IMAGE_NT_HEADERS64)) {
log_err("Invalid offset for Extended Header\n");
ret = EFI_LOAD_ERROR;
goto err;
}
nt = (void *) ((char *)efi + dos->e_lfanew);
if (nt->Signature != IMAGE_NT_SIGNATURE) {
log_err("Invalid NT Signature\n");
ret = EFI_LOAD_ERROR;
goto err;
ret = efi_check_pe(efi, efi_size, (void **)&nt);
if (ret != EFI_SUCCESS) {
log_err("Not a PE-COFF file\n");
return EFI_LOAD_ERROR;
}
for (i = 0; machines[i]; i++)
@ -746,8 +760,7 @@ efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle,
if (!supported) {
log_err("Machine type 0x%04x is not supported\n",
nt->FileHeader.Machine);
ret = EFI_LOAD_ERROR;
goto err;
return EFI_LOAD_ERROR;
}
num_sections = nt->FileHeader.NumberOfSections;
@ -757,8 +770,7 @@ efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle,
if (efi_size < ((void *)sections + sizeof(sections[0]) * num_sections
- efi)) {
log_err("Invalid number of sections: %d\n", num_sections);
ret = EFI_LOAD_ERROR;
goto err;
return EFI_LOAD_ERROR;
}
/* Authenticate an image */

View File

@ -541,8 +541,6 @@ efi_status_t efi_free_pages(uint64_t memory, efi_uintn_t pages)
ret = efi_add_memory_map_pg(memory, pages, EFI_CONVENTIONAL_MEMORY,
false);
/* Merging of adjacent free regions is missing */
if (ret != EFI_SUCCESS)
return EFI_NOT_FOUND;

View File

@ -7,6 +7,7 @@
#include <common.h>
#include <malloc.h>
#include <efi_dt_fixup.h>
#include <efi_loader.h>
const efi_guid_t efi_u_boot_guid = U_BOOT_GUID;
@ -60,6 +61,11 @@ efi_status_t efi_root_node_register(void)
/* Device path utilities protocol */
&efi_guid_device_path_utilities_protocol,
(void *)&efi_device_path_utilities,
#if !CONFIG_IS_ENABLED(GENERATE_ACPI_TABLE)
/* 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 */

View File

@ -1,43 +1,41 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* EFI hello world
* Hello world EFI application
*
* Copyright (c) 2016 Google, Inc
* Written by Simon Glass <sjg@chromium.org>
* Copyright 2020, Heinrich Schuchardt <xypron.glpk@gmx.de>
*
* This program demonstrates calling a boottime service.
* It writes a greeting and the load options to the console.
* This test program is used to test the invocation of an EFI application.
* It writes
*
* * a greeting
* * the firmware's UEFI version
* * the installed configuration tables
* * the boot device's device path and the file path
*
* to the console.
*/
#include <common.h>
#include <efi_api.h>
static const efi_guid_t loaded_image_guid = EFI_LOADED_IMAGE_PROTOCOL_GUID;
static const efi_guid_t device_path_to_text_protocol_guid =
EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID;
static const efi_guid_t device_path_guid = EFI_DEVICE_PATH_PROTOCOL_GUID;
static const efi_guid_t fdt_guid = EFI_FDT_GUID;
static const efi_guid_t acpi_guid = EFI_ACPI_TABLE_GUID;
static const efi_guid_t smbios_guid = SMBIOS_TABLE_GUID;
static struct efi_system_table *systable;
static struct efi_boot_services *boottime;
static struct efi_simple_text_output_protocol *con_out;
/**
* efi_main() - entry point of the EFI application.
*
* @handle: handle of the loaded image
* @systable: system table
* @return: status code
* print_uefi_revision() - print UEFI revision number
*/
efi_status_t EFIAPI efi_main(efi_handle_t handle,
struct efi_system_table *systable)
static void print_uefi_revision(void)
{
struct efi_simple_text_output_protocol *con_out = systable->con_out;
struct efi_boot_services *boottime = systable->boottime;
struct efi_loaded_image *loaded_image;
efi_status_t ret;
efi_uintn_t i;
u16 rev[] = L"0.0.0";
/* UEFI requires CR LF */
con_out->output_string(con_out, L"Hello, world!\r\n");
/* Print the revision number */
rev[0] = (systable->hdr.revision >> 16) + '0';
rev[4] = systable->hdr.revision & 0xffff;
for (; rev[4] >= 10;) {
@ -53,15 +51,15 @@ efi_status_t EFIAPI efi_main(efi_handle_t handle,
con_out->output_string(con_out, L"Running on UEFI ");
con_out->output_string(con_out, rev);
con_out->output_string(con_out, L"\r\n");
}
/**
* print_config_tables() - print configuration tables
*/
static void print_config_tables(void)
{
efi_uintn_t i;
/* Get the loaded image protocol */
ret = boottime->handle_protocol(handle, &loaded_image_guid,
(void **)&loaded_image);
if (ret != EFI_SUCCESS) {
con_out->output_string
(con_out, L"Cannot open loaded image protocol\r\n");
goto out;
}
/* Find configuration tables */
for (i = 0; i < systable->nr_tables; ++i) {
if (!memcmp(&systable->tables[i].guid, &fdt_guid,
@ -77,6 +75,16 @@ efi_status_t EFIAPI efi_main(efi_handle_t handle,
con_out->output_string
(con_out, L"Have SMBIOS table\r\n");
}
}
/**
* print_load_options() - print load options
*
* @systable: system table
* @con_out: simple text output protocol
*/
void print_load_options(struct efi_loaded_image *loaded_image)
{
/* Output the load options */
con_out->output_string(con_out, L"Load options: ");
if (loaded_image->load_options_size && loaded_image->load_options)
@ -85,6 +93,105 @@ efi_status_t EFIAPI efi_main(efi_handle_t handle,
else
con_out->output_string(con_out, L"<none>");
con_out->output_string(con_out, L"\r\n");
}
/**
* print_device_path() - print device path
*
* @device_path: device path to print
* @dp2txt: device path to text protocol
*/
efi_status_t print_device_path(struct efi_device_path *device_path,
struct efi_device_path_to_text_protocol *dp2txt)
{
u16 *string;
efi_status_t ret;
if (!device_path) {
con_out->output_string(con_out, L"<none>\r\n");
return EFI_SUCCESS;
}
string = dp2txt->convert_device_path_to_text(device_path, true, false);
if (!string) {
con_out->output_string
(con_out, L"Cannot convert device path to text\r\n");
return EFI_OUT_OF_RESOURCES;
}
con_out->output_string(con_out, string);
con_out->output_string(con_out, L"\r\n");
ret = boottime->free_pool(string);
if (ret != EFI_SUCCESS) {
con_out->output_string(con_out, L"Cannot free pool memory\r\n");
return ret;
}
return EFI_SUCCESS;
}
/**
* 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 handle,
struct efi_system_table *systab)
{
struct efi_loaded_image *loaded_image;
struct efi_device_path_to_text_protocol *device_path_to_text;
struct efi_device_path *device_path;
efi_status_t ret;
systable = systab;
boottime = systable->boottime;
con_out = systable->con_out;
/* UEFI requires CR LF */
con_out->output_string(con_out, L"Hello, world!\r\n");
print_uefi_revision();
print_config_tables();
/* Get the loaded image protocol */
ret = boottime->handle_protocol(handle, &loaded_image_guid,
(void **)&loaded_image);
if (ret != EFI_SUCCESS) {
con_out->output_string
(con_out, L"Cannot open loaded image protocol\r\n");
goto out;
}
print_load_options(loaded_image);
/* Get the device path to text protocol */
ret = boottime->locate_protocol(&device_path_to_text_protocol_guid,
NULL, (void **)&device_path_to_text);
if (ret != EFI_SUCCESS) {
con_out->output_string
(con_out, L"Cannot open device path to text protocol\r\n");
goto out;
}
if (!loaded_image->device_handle) {
con_out->output_string
(con_out, L"Missing device handle\r\n");
goto out;
}
ret = boottime->handle_protocol(loaded_image->device_handle,
&device_path_guid,
(void **)&device_path);
if (ret != EFI_SUCCESS) {
con_out->output_string
(con_out, L"Missing devide path for device handle\r\n");
goto out;
}
con_out->output_string(con_out, L"Boot device: ");
ret = print_device_path(device_path, device_path_to_text);
if (ret != EFI_SUCCESS)
goto out;
con_out->output_string(con_out, L"File path: ");
ret = print_device_path(loaded_image->file_path, device_path_to_text);
if (ret != EFI_SUCCESS)
goto out;
out:
boottime->exit(handle, ret, 0, NULL);

View File

@ -8,10 +8,12 @@
#include <common.h>
#include <efi_api.h>
#include <efi_dt_fixup.h>
#define BUFFER_SIZE 64
#define ESC 0x17
#define DEFAULT_FILENAME L"dtb.dtb"
#define efi_size_in_pages(size) ((size + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT)
static struct efi_simple_text_output_protocol *cerr;
static struct efi_simple_text_output_protocol *cout;
@ -21,6 +23,22 @@ static const efi_guid_t fdt_guid = EFI_FDT_GUID;
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 efi_handle_t handle;
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;
/**
* error() - print error string
*
* @string: error text
*/
static void error(u16 *string)
{
cout->set_attribute(cout, EFI_LIGHTRED | EFI_BACKGROUND_BLACK);
cout->output_string(cout, string);
cout->set_attribute(cout, EFI_LIGHTBLUE | EFI_BACKGROUND_BLACK);
}
/**
* input() - read string from console
@ -39,6 +57,7 @@ static efi_status_t efi_input(u16 *buffer, efi_uintn_t buffer_size)
/* 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)
@ -62,6 +81,7 @@ static efi_status_t efi_input(u16 *buffer, efi_uintn_t buffer_size)
break;
case 0x0a: /* Linefeed */
case 0x0d: /* Carriage return */
cout->output_string(cout, L"\n");
return EFI_SUCCESS;
default:
break;
@ -73,6 +93,7 @@ static efi_status_t efi_input(u16 *buffer, efi_uintn_t buffer_size)
pos < buffer_size - 1) {
*outbuf = key.unicode_char;
buffer[pos++] = key.unicode_char;
buffer[pos] = 0;
cout->output_string(cout, outbuf);
}
}
@ -117,60 +138,228 @@ void *get_dtb(struct efi_system_table *systable)
}
/**
* efi_main() - entry point of the EFI application.
* skip_whitespace() - skip over leading whitespace
*
* @handle: handle of the loaded image
* @systable: system table
* @return: status code
* @pos: UTF-16 string
* Return: pointer to first non-whitespace
*/
efi_status_t EFIAPI efi_main(efi_handle_t handle,
struct efi_system_table *systable)
u16 *skip_whitespace(u16 *pos)
{
efi_uintn_t ret;
u16 filename[BUFFER_SIZE] = {0};
efi_uintn_t dtb_size;
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
*/
bool starts_with(u16 *string, u16 *keyword)
{
for (; *keyword; ++string, ++keyword) {
if (*string != *keyword)
return false;
}
return true;
}
/**
* do_help() - print help
*/
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");
}
/**
* do_load() - load and install device-tree
*
* @filename: file name
* Return: status code
*/
efi_status_t do_load(u16 *filename)
{
struct efi_dt_fixup_protocol *dt_fixup_prot;
struct efi_loaded_image *loaded_image;
struct efi_simple_file_system_protocol *file_system;
struct efi_file_handle *root, *file;
struct efi_file_handle *root = NULL, *file = NULL;
u64 addr = 0;
struct efi_file_info *info;
struct fdt_header *dtb;
efi_uintn_t buffer_size;
efi_uintn_t pages;
efi_status_t ret, ret2;
cerr = systable->std_err;
cout = systable->con_out;
cin = systable->con_in;
bs = systable->boottime;
cout->set_attribute(cout, EFI_LIGHTGRAY | EFI_BACKGROUND_BLACK);
cout->clear_screen(cout);
cout->set_attribute(cout, EFI_YELLOW | EFI_BACKGROUND_BLACK);
cout->output_string(cout, L"DTB Dump\n\n");
cout->set_attribute(cout, EFI_LIGHTGRAY | EFI_BACKGROUND_BLACK);
dtb = get_dtb(systable);
if (!dtb) {
cerr->output_string(cout, L"DTB not found\n");
return EFI_NOT_FOUND;
}
if (f2h(dtb->magic) != FDT_MAGIC) {
cerr->output_string(cout, L"Wrong device tree magic\n");
return EFI_NOT_FOUND;
}
dtb_size = f2h(dtb->totalsize);
cout->output_string(cout, L"Filename (" DEFAULT_FILENAME ")?\n");
ret = efi_input(filename, sizeof(filename));
if (ret != EFI_SUCCESS)
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");
return ret;
if (!*filename)
memcpy(filename, DEFAULT_FILENAME, sizeof(DEFAULT_FILENAME));
}
cout->output_string(cout, L"\n");
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) {
cerr->output_string(cout,
L"Loaded image protocol not found\n");
error(L"Loaded image protocol not found\n");
return ret;
}
/* 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\n");
goto out;
}
/* Open volume */
ret = file_system->open_volume(file_system, &root);
if (ret != EFI_SUCCESS) {
error(L"Failed to open volume\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");
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");
goto out;
}
ret = bs->allocate_pool(EFI_LOADER_DATA, buffer_size, (void **)&info);
if (ret != EFI_SUCCESS) {
error(L"Out of memory\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");
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");
/* 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");
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");
goto out;
}
/* Fixup file, expecting EFI_BUFFER_TOO_SMALL */
ret = dt_fixup_prot->fixup(dt_fixup_prot, dtb, &buffer_size,
EFI_DT_APPLY_FIXUPS | EFI_DT_RESERVE_MEMORY |
EFI_DT_INSTALL_TABLE);
if (ret == EFI_BUFFER_TOO_SMALL) {
/* Read file into larger buffer */
ret = bs->free_pages(addr, pages);
if (ret != EFI_SUCCESS)
error(L"Can't free memory pages\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");
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");
goto out;
}
ret = file->read(file, &buffer_size, dtb);
if (ret != EFI_SUCCESS) {
error(L"Can't read file\n");
goto out;
}
buffer_size = pages << EFI_PAGE_SHIFT;
ret = dt_fixup_prot->fixup(
dt_fixup_prot, dtb, &buffer_size,
EFI_DT_APPLY_FIXUPS | EFI_DT_RESERVE_MEMORY |
EFI_DT_INSTALL_TABLE);
}
if (ret == EFI_SUCCESS)
cout->output_string(cout, L"device-tree installed\n");
else
error(L"Device-tree fix-up failed\n");
out:
if (addr) {
ret2 = bs->free_pages(addr, pages);
if (ret2 != EFI_SUCCESS)
error(L"Can't free memory pages\n");
}
if (file) {
ret2 = file->close(file);
if (ret2 != EFI_SUCCESS)
error(L"Can't close file\n");
}
if (root) {
ret2 = root->close(root);
if (ret2 != EFI_SUCCESS)
error(L"Can't close volume\n");
}
return ret;
}
/**
* do_save() - save current device-tree
*
* @filename: file name
* Return: status code
*/
efi_status_t do_save(u16 *filename)
{
struct efi_loaded_image *loaded_image;
struct efi_simple_file_system_protocol *file_system;
efi_uintn_t dtb_size;
struct efi_file_handle *root, *file;
struct fdt_header *dtb;
efi_uintn_t ret;
dtb = get_dtb(systable);
if (!dtb) {
error(L"DTB not found\n");
return EFI_NOT_FOUND;
}
if (f2h(dtb->magic) != FDT_MAGIC) {
error(L"Wrong device tree magic\n");
return EFI_NOT_FOUND;
}
dtb_size = f2h(dtb->totalsize);
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\n");
return ret;
}
@ -180,15 +369,14 @@ efi_status_t EFIAPI efi_main(efi_handle_t handle,
(void **)&file_system, NULL, NULL,
EFI_OPEN_PROTOCOL_GET_PROTOCOL);
if (ret != EFI_SUCCESS) {
cerr->output_string(
cout, L"Failed to open simple file system protocol\n");
error(L"Failed to open simple file system protocol\n");
return ret;
}
/* Open volume */
ret = file_system->open_volume(file_system, &root);
if (ret != EFI_SUCCESS) {
cerr->output_string(cerr, L"Failed to open volume\n");
error(L"Failed to open volume\n");
return ret;
}
/* Create file */
@ -199,10 +387,10 @@ efi_status_t EFIAPI efi_main(efi_handle_t handle,
/* Write file */
ret = file->write(file, &dtb_size, dtb);
if (ret != EFI_SUCCESS)
cerr->output_string(cerr, L"Failed to write file\n");
error(L"Failed to write file\n");
file->close(file);
} else {
cerr->output_string(cerr, L"Failed to open file\n");
error(L"Failed to open file\n");
}
root->close(root);
@ -213,3 +401,51 @@ efi_status_t EFIAPI efi_main(efi_handle_t handle,
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);
cout->output_string(cout, L"DTB Dump\n========\n\n");
cout->set_attribute(cout, EFI_LIGHTBLUE | EFI_BACKGROUND_BLACK);
for (;;) {
u16 command[BUFFER_SIZE];
u16 *pos;
efi_uintn_t ret;
cout->output_string(cout, 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(pos + 5);
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;
}

View File

@ -329,6 +329,12 @@ static void tftp_complete(void)
time_start * 1000, "/s");
}
puts("\ndone\n");
if (IS_ENABLED(CONFIG_CMD_BOOTEFI)) {
if (!tftp_put_active)
efi_set_bootdev("Net", "", tftp_filename,
map_sysmem(tftp_load_addr, 0),
net_boot_file_size);
}
net_set_state(NETLOOP_SUCCESS);
}
@ -841,9 +847,6 @@ void tftp_start(enum proto_t protocol)
printf("Load address: 0x%lx\n", tftp_load_addr);
puts("Loading: *\b");
tftp_state = STATE_SEND_RRQ;
#ifdef CONFIG_CMD_BOOTEFI
efi_set_bootdev("Net", "", tftp_filename);
#endif
}
time_start = get_timer(0);

View File

@ -51,21 +51,21 @@ var_guids = {
}
class EfiStruct:
# struct efi_var_file
var_file_fmt = '<QQLL'
var_file_size = struct.calcsize(var_file_fmt)
# struct efi_var_entry
var_entry_fmt = '<LLQ16s'
var_entry_size = struct.calcsize(var_entry_fmt)
# struct efi_time
var_time_fmt = '<H6BLh2B'
var_time_size = struct.calcsize(var_time_fmt)
# WIN_CERTIFICATE
var_win_cert_fmt = '<L2H'
var_win_cert_size = struct.calcsize(var_win_cert_fmt)
# WIN_CERTIFICATE_UEFI_GUID
var_win_cert_uefi_guid_fmt = var_win_cert_fmt+'16s'
var_win_cert_uefi_guid_size = struct.calcsize(var_win_cert_uefi_guid_fmt)
# struct efi_var_file
var_file_fmt = '<QQLL'
var_file_size = struct.calcsize(var_file_fmt)
# struct efi_var_entry
var_entry_fmt = '<LLQ16s'
var_entry_size = struct.calcsize(var_entry_fmt)
# struct efi_time
var_time_fmt = '<H6BLh2B'
var_time_size = struct.calcsize(var_time_fmt)
# WIN_CERTIFICATE
var_win_cert_fmt = '<L2H'
var_win_cert_size = struct.calcsize(var_win_cert_fmt)
# WIN_CERTIFICATE_UEFI_GUID
var_win_cert_uefi_guid_fmt = var_win_cert_fmt+'16s'
var_win_cert_uefi_guid_size = struct.calcsize(var_win_cert_uefi_guid_fmt)
class EfiVariable:
def __init__(self, size, attrs, time, guid, name, data):
@ -149,7 +149,7 @@ class EfiVariableStore:
offs = 0
while offs < len(self.ents):
var, loffs = self._next_var(offs)
if var.name == name and str(var.guid):
if var.name == name and str(var.guid) == guid:
if var.attrs != attrs:
print("err: attributes don't match")
exit(1)
@ -292,7 +292,7 @@ def pkcs7_sign(cert, key, buf):
# UEFI 2.8 Errata B "8.2.2 Using the EFI_VARIABLE_AUTHENTICATION_2 descriptor"
def cmd_sign(args):
guid, name, attrs, data, size = parse_args(args)
guid, name, attrs, data, _ = parse_args(args)
attrs |= EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
efi = EfiStruct()
@ -357,7 +357,10 @@ def main():
signp.set_defaults(func=cmd_sign)
args = ap.parse_args()
args.func(args)
if hasattr(args, "func"):
args.func(args)
else:
ap.print_help()
def group(a, *ns):
for n in ns: