mirror of
https://github.com/brain-hackers/u-boot-brain
synced 2024-06-09 23:36:03 +09:00
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:
commit
35772ff4f6
234
cmd/bootefi.c
234
cmd/bootefi.c
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
|
3
fs/fs.c
3
fs/fs.c
|
@ -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) {
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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
39
include/efi_dt_fixup.h
Normal 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;
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
160
lib/efi_loader/efi_dt_fixup.c
Normal file
160
lib/efi_loader/efi_dt_fixup.c
Normal 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);
|
||||
}
|
|
@ -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 = {
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Reference in New Issue
Block a user