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_image_path;
|
||||||
static struct efi_device_path *bootefi_device_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
|
* efi_env_set_load_options() - set load options from environment variable
|
||||||
|
@ -135,86 +211,6 @@ done:
|
||||||
return ret;
|
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
|
* get_config_table() - get configuration table
|
||||||
*
|
*
|
||||||
|
@ -398,43 +394,28 @@ static int do_bootefi_image(const char *image_opt)
|
||||||
{
|
{
|
||||||
void *image_buf;
|
void *image_buf;
|
||||||
unsigned long addr, size;
|
unsigned long addr, size;
|
||||||
const char *size_str;
|
|
||||||
efi_status_t ret;
|
efi_status_t ret;
|
||||||
|
|
||||||
#ifdef CONFIG_CMD_BOOTEFI_HELLO
|
#ifdef CONFIG_CMD_BOOTEFI_HELLO
|
||||||
if (!strcmp(image_opt, "hello")) {
|
if (!strcmp(image_opt, "hello")) {
|
||||||
char *saddr;
|
image_buf = __efi_helloworld_begin;
|
||||||
|
|
||||||
saddr = env_get("loadaddr");
|
|
||||||
size = __efi_helloworld_end - __efi_helloworld_begin;
|
size = __efi_helloworld_end - __efi_helloworld_begin;
|
||||||
|
efi_clear_bootdev();
|
||||||
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;
|
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
size_str = env_get("filesize");
|
addr = strtoul(image_opt, NULL, 16);
|
||||||
if (size_str)
|
|
||||||
size = simple_strtoul(size_str, NULL, 16);
|
|
||||||
else
|
|
||||||
size = 0;
|
|
||||||
|
|
||||||
addr = simple_strtoul(image_opt, NULL, 16);
|
|
||||||
/* Check that a numeric value was passed */
|
/* Check that a numeric value was passed */
|
||||||
if (!addr && *image_opt != '0')
|
if (!addr)
|
||||||
return CMD_RET_USAGE;
|
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);
|
ret = efi_run_image(image_buf, size);
|
||||||
|
|
||||||
|
@ -567,11 +548,8 @@ static efi_status_t bootefi_test_prepare
|
||||||
if (ret == EFI_SUCCESS)
|
if (ret == EFI_SUCCESS)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
efi_free_pool(bootefi_image_path);
|
|
||||||
bootefi_image_path = NULL;
|
|
||||||
failure:
|
failure:
|
||||||
efi_free_pool(bootefi_device_path);
|
efi_clear_bootdev();
|
||||||
bootefi_device_path = NULL;
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -691,39 +669,3 @@ U_BOOT_CMD(
|
||||||
"Boots an EFI payload from memory",
|
"Boots an EFI payload from memory",
|
||||||
bootefi_help_text
|
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);
|
printf("%02x ", c);
|
||||||
first = false;
|
first = false;
|
||||||
|
|
||||||
/* 1 ms delay - serves to detect separate keystrokes */
|
/* 10 ms delay - serves to detect separate keystrokes */
|
||||||
udelay(1000);
|
udelay(10000);
|
||||||
if (!tstc()) {
|
if (!tstc()) {
|
||||||
printf("\n");
|
printf("\n");
|
||||||
first = true;
|
first = true;
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include <charset.h>
|
#include <charset.h>
|
||||||
#include <common.h>
|
#include <common.h>
|
||||||
#include <command.h>
|
#include <command.h>
|
||||||
|
#include <efi_dt_fixup.h>
|
||||||
#include <efi_loader.h>
|
#include <efi_loader.h>
|
||||||
#include <efi_rng.h>
|
#include <efi_rng.h>
|
||||||
#include <exports.h>
|
#include <exports.h>
|
||||||
|
@ -495,6 +496,10 @@ static const struct {
|
||||||
"PXE Base Code",
|
"PXE Base Code",
|
||||||
EFI_PXE_BASE_CODE_PROTOCOL_GUID,
|
EFI_PXE_BASE_CODE_PROTOCOL_GUID,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"Device-Tree Fixup",
|
||||||
|
EFI_DT_FIXUP_PROTOCOL_GUID,
|
||||||
|
},
|
||||||
/* Configuration table GUIDs */
|
/* Configuration table GUIDs */
|
||||||
{
|
{
|
||||||
"ACPI table",
|
"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)
|
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 */
|
/* mandatory / node 'description' property */
|
||||||
if (fdt_getprop(fit, 0, FIT_DESC_PROP, NULL) == NULL) {
|
if (fdt_getprop(fit, 0, FIT_DESC_PROP, NULL) == NULL) {
|
||||||
debug("Wrong FIT format: no description\n");
|
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)
|
120832 bytes read in 7 ms (16.5 MiB/s)
|
||||||
=> bootefi ${kernel_addr_r} ${fdt_addr_r}
|
=> bootefi ${kernel_addr_r} ${fdt_addr_r}
|
||||||
|
|
||||||
The bootefi command uses the device, the file name, and the file size
|
When booting from a memory location it is unknown from which file it was loaded.
|
||||||
(environment variable 'filesize') of the most recently loaded file when setting
|
Therefore the bootefi command uses the device path of the block device partition
|
||||||
up the binary for execution. So the UEFI binary should be loaded last.
|
or the network adapter and the file name of the most recently loaded PE-COFF
|
||||||
|
file when setting up the loaded image protocol.
|
||||||
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.
|
|
||||||
|
|
||||||
Launching a UEFI binary from a FIT image
|
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))
|
if (IS_ENABLED(CONFIG_CMD_BOOTEFI))
|
||||||
efi_set_bootdev(argv[1], (argc > 2) ? argv[2] : "",
|
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);
|
printf("%llu bytes read in %lu ms", len_read, time);
|
||||||
if (time > 0) {
|
if (time > 0) {
|
||||||
|
|
|
@ -20,6 +20,11 @@
|
||||||
#include <linux/string.h>
|
#include <linux/string.h>
|
||||||
#include <linux/types.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.
|
* 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
|
EFI_TIMER_RELATIVE = 2
|
||||||
};
|
};
|
||||||
|
|
||||||
#define efi_intn_t ssize_t
|
|
||||||
#define efi_uintn_t size_t
|
|
||||||
typedef void *efi_hii_handle_t;
|
typedef void *efi_hii_handle_t;
|
||||||
typedef u16 *efi_string_t;
|
typedef u16 *efi_string_t;
|
||||||
typedef u16 efi_string_id_t;
|
typedef u16 efi_string_id_t;
|
||||||
|
@ -703,10 +701,10 @@ struct efi_simple_text_output_protocol {
|
||||||
char extended_verification);
|
char extended_verification);
|
||||||
efi_status_t (EFIAPI *output_string)(
|
efi_status_t (EFIAPI *output_string)(
|
||||||
struct efi_simple_text_output_protocol *this,
|
struct efi_simple_text_output_protocol *this,
|
||||||
const efi_string_t str);
|
const u16 *str);
|
||||||
efi_status_t (EFIAPI *test_string)(
|
efi_status_t (EFIAPI *test_string)(
|
||||||
struct efi_simple_text_output_protocol *this,
|
struct efi_simple_text_output_protocol *this,
|
||||||
const efi_string_t str);
|
const u16 *str);
|
||||||
efi_status_t(EFIAPI *query_mode)(
|
efi_status_t(EFIAPI *query_mode)(
|
||||||
struct efi_simple_text_output_protocol *this,
|
struct efi_simple_text_output_protocol *this,
|
||||||
unsigned long mode_number, unsigned long *columns,
|
unsigned long mode_number, unsigned long *columns,
|
||||||
|
@ -1589,35 +1587,35 @@ struct efi_file_io_token {
|
||||||
|
|
||||||
struct efi_file_handle {
|
struct efi_file_handle {
|
||||||
u64 rev;
|
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,
|
struct efi_file_handle **new_handle,
|
||||||
u16 *file_name, u64 open_mode, u64 attributes);
|
u16 *file_name, u64 open_mode, u64 attributes);
|
||||||
efi_status_t (EFIAPI *close)(struct efi_file_handle *file);
|
efi_status_t (EFIAPI *close)(struct efi_file_handle *this);
|
||||||
efi_status_t (EFIAPI *delete)(struct efi_file_handle *file);
|
efi_status_t (EFIAPI *delete)(struct efi_file_handle *this);
|
||||||
efi_status_t (EFIAPI *read)(struct efi_file_handle *file,
|
efi_status_t (EFIAPI *read)(struct efi_file_handle *this,
|
||||||
efi_uintn_t *buffer_size, void *buffer);
|
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_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);
|
u64 *pos);
|
||||||
efi_status_t (EFIAPI *setpos)(struct efi_file_handle *file,
|
efi_status_t (EFIAPI *setpos)(struct efi_file_handle *this,
|
||||||
u64 pos);
|
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,
|
const efi_guid_t *info_type, efi_uintn_t *buffer_size,
|
||||||
void *buffer);
|
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,
|
const efi_guid_t *info_type, efi_uintn_t buffer_size,
|
||||||
void *buffer);
|
void *buffer);
|
||||||
efi_status_t (EFIAPI *flush)(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 *file,
|
efi_status_t (EFIAPI *open_ex)(struct efi_file_handle *this,
|
||||||
struct efi_file_handle **new_handle,
|
struct efi_file_handle **new_handle,
|
||||||
u16 *file_name, u64 open_mode, u64 attributes,
|
u16 *file_name, u64 open_mode, u64 attributes,
|
||||||
struct efi_file_io_token *token);
|
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);
|
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);
|
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);
|
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_convert_pointer() - convert pointer to virtual address */
|
||||||
efi_status_t EFIAPI efi_convert_pointer(efi_uintn_t debug_disposition,
|
efi_status_t EFIAPI efi_convert_pointer(efi_uintn_t debug_disposition,
|
||||||
void **address);
|
void **address);
|
||||||
|
/* Carve out DT reserved memory ranges */
|
||||||
|
void efi_carve_out_dt_rsv(void *fdt);
|
||||||
/* Called by bootefi to make console interface available */
|
/* Called by bootefi to make console interface available */
|
||||||
efi_status_t efi_console_register(void);
|
efi_status_t efi_console_register(void);
|
||||||
/* Called by bootefi to make all disk storage accessible as EFI objects */
|
/* 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 */
|
/* Called from places to check whether a timer expired */
|
||||||
void efi_timer_check(void);
|
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 */
|
/* PE loader implementation */
|
||||||
efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle,
|
efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle,
|
||||||
void *efi, size_t efi_size,
|
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 */
|
/* Call this to relocate the runtime section to an address space */
|
||||||
void efi_runtime_relocate(ulong offset, struct efi_mem_desc *map);
|
void efi_runtime_relocate(ulong offset, struct efi_mem_desc *map);
|
||||||
/* Call this to set the current device name */
|
/* 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. */
|
/* Add a new object to the object list. */
|
||||||
void efi_add_handle(efi_handle_t obj);
|
void efi_add_handle(efi_handle_t obj);
|
||||||
/* Create handle */
|
/* 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 */
|
/* No loader configured, stub out EFI_ENTRY */
|
||||||
static inline void efi_restore_gd(void) { }
|
static inline void efi_restore_gd(void) { }
|
||||||
static inline void efi_set_bootdev(const char *dev, const char *devnr,
|
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_net_set_dhcp_ack(void *pkt, int len) { }
|
||||||
static inline void efi_print_image_infos(void *pc) { }
|
static inline void efi_print_image_infos(void *pc) { }
|
||||||
static inline efi_status_t efi_launch_capsules(void)
|
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-y += efi_device_path.o
|
||||||
obj-$(CONFIG_EFI_DEVICE_PATH_TO_TEXT) += efi_device_path_to_text.o
|
obj-$(CONFIG_EFI_DEVICE_PATH_TO_TEXT) += efi_device_path_to_text.o
|
||||||
obj-y += efi_device_path_utilities.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-y += efi_file.o
|
||||||
obj-$(CONFIG_EFI_LOADER_HII) += efi_hii.o
|
obj-$(CONFIG_EFI_LOADER_HII) += efi_hii.o
|
||||||
obj-y += efi_image_loader.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(
|
static efi_status_t EFIAPI efi_cout_output_string(
|
||||||
struct efi_simple_text_output_protocol *this,
|
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 simple_text_output_mode *con = &efi_con_mode;
|
||||||
struct cout_mode *mode = &efi_cout_modes[con->mode];
|
struct cout_mode *mode = &efi_cout_modes[con->mode];
|
||||||
char *buf, *pos;
|
char *buf, *pos;
|
||||||
u16 *p;
|
const u16 *p;
|
||||||
efi_status_t ret = EFI_SUCCESS;
|
efi_status_t ret = EFI_SUCCESS;
|
||||||
|
|
||||||
EFI_ENTRY("%p, %p", this, string);
|
EFI_ENTRY("%p, %p", this, string);
|
||||||
|
@ -230,7 +230,7 @@ out:
|
||||||
*/
|
*/
|
||||||
static efi_status_t EFIAPI efi_cout_test_string(
|
static efi_status_t EFIAPI efi_cout_test_string(
|
||||||
struct efi_simple_text_output_protocol *this,
|
struct efi_simple_text_output_protocol *this,
|
||||||
const efi_string_t string)
|
const u16 *string)
|
||||||
{
|
{
|
||||||
EFI_ENTRY("%p, %p", this, string);
|
EFI_ENTRY("%p, %p", this, string);
|
||||||
return EFI_EXIT(EFI_SUCCESS);
|
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;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static efi_status_t EFIAPI efi_file_open(struct efi_file_handle *file,
|
static efi_status_t efi_file_open_int(struct efi_file_handle *this,
|
||||||
struct efi_file_handle **new_handle,
|
struct efi_file_handle **new_handle,
|
||||||
u16 *file_name, u64 open_mode, u64 attributes)
|
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_status_t ret;
|
||||||
|
|
||||||
EFI_ENTRY("%p, %p, \"%ls\", %llx, %llu", file, new_handle,
|
|
||||||
file_name, open_mode, attributes);
|
|
||||||
|
|
||||||
/* Check parameters */
|
/* Check parameters */
|
||||||
if (!file || !new_handle || !file_name) {
|
if (!this || !new_handle || !file_name) {
|
||||||
ret = EFI_INVALID_PARAMETER;
|
ret = EFI_INVALID_PARAMETER;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -291,6 +289,75 @@ static efi_status_t EFIAPI efi_file_open(struct efi_file_handle *file,
|
||||||
} else {
|
} else {
|
||||||
ret = EFI_NOT_FOUND;
|
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:
|
out:
|
||||||
return EFI_EXIT(ret);
|
return EFI_EXIT(ret);
|
||||||
}
|
}
|
||||||
|
@ -441,19 +508,15 @@ static efi_status_t dir_read(struct file_handle *fh, u64 *buffer_size,
|
||||||
return EFI_SUCCESS;
|
return EFI_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static efi_status_t EFIAPI efi_file_read(struct efi_file_handle *file,
|
static efi_status_t efi_file_read_int(struct efi_file_handle *this,
|
||||||
efi_uintn_t *buffer_size, void *buffer)
|
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;
|
efi_status_t ret = EFI_SUCCESS;
|
||||||
u64 bs;
|
u64 bs;
|
||||||
|
|
||||||
EFI_ENTRY("%p, %p, %p", file, buffer_size, buffer);
|
if (!this || !buffer_size || !buffer)
|
||||||
|
return EFI_INVALID_PARAMETER;
|
||||||
if (!buffer_size) {
|
|
||||||
ret = EFI_INVALID_PARAMETER;
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
bs = *buffer_size;
|
bs = *buffer_size;
|
||||||
if (fh->isdir)
|
if (fh->isdir)
|
||||||
|
@ -465,34 +528,77 @@ static efi_status_t EFIAPI efi_file_read(struct efi_file_handle *file,
|
||||||
else
|
else
|
||||||
*buffer_size = SIZE_MAX;
|
*buffer_size = SIZE_MAX;
|
||||||
|
|
||||||
error:
|
return ret;
|
||||||
return EFI_EXIT(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
|
* See the Unified Extensible Firmware Interface (UEFI) specification for
|
||||||
* details.
|
* details.
|
||||||
*
|
*
|
||||||
* @file: file handle
|
* @this: file protocol instance
|
||||||
* @buffer_size: number of bytes to write
|
* @buffer_size: number of bytes to read
|
||||||
* @buffer: buffer with the bytes to write
|
* @buffer: read buffer
|
||||||
* Return: status code
|
* Return: status code
|
||||||
*/
|
*/
|
||||||
static efi_status_t EFIAPI efi_file_write(struct efi_file_handle *file,
|
static efi_status_t EFIAPI efi_file_read(struct efi_file_handle *this,
|
||||||
efi_uintn_t *buffer_size,
|
efi_uintn_t *buffer_size, void *buffer)
|
||||||
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;
|
efi_status_t ret = EFI_SUCCESS;
|
||||||
loff_t actwrite;
|
loff_t actwrite;
|
||||||
|
|
||||||
EFI_ENTRY("%p, %p, %p", file, buffer_size, buffer);
|
if (!this || !buffer_size || !buffer) {
|
||||||
|
|
||||||
if (!file || !buffer_size || !buffer) {
|
|
||||||
ret = EFI_INVALID_PARAMETER;
|
ret = EFI_INVALID_PARAMETER;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -520,6 +626,67 @@ static efi_status_t EFIAPI efi_file_write(struct efi_file_handle *file,
|
||||||
*buffer_size = actwrite;
|
*buffer_size = actwrite;
|
||||||
fh->offset += 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:
|
out:
|
||||||
return EFI_EXIT(ret);
|
return EFI_EXIT(ret);
|
||||||
}
|
}
|
||||||
|
@ -761,36 +928,84 @@ out:
|
||||||
return EFI_EXIT(ret);
|
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);
|
struct file_handle *fh = to_fh(this);
|
||||||
return EFI_EXIT(EFI_SUCCESS);
|
|
||||||
|
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,
|
* efi_file_flush() - flush file
|
||||||
u16 *file_name, u64 open_mode, u64 attributes,
|
*
|
||||||
struct efi_file_io_token *token)
|
* 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,
|
EFI_ENTRY("%p, %p", this, token);
|
||||||
struct efi_file_io_token *token)
|
|
||||||
{
|
|
||||||
return EFI_UNSUPPORTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
static efi_status_t EFIAPI efi_file_flush_ex(struct efi_file_handle *file,
|
if (!token) {
|
||||||
struct efi_file_io_token *token)
|
ret = EFI_INVALID_PARAMETER;
|
||||||
{
|
goto out;
|
||||||
return EFI_UNSUPPORTED;
|
}
|
||||||
|
|
||||||
|
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 = {
|
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 */
|
#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
|
* 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;
|
int supported = 0;
|
||||||
efi_status_t ret;
|
efi_status_t ret;
|
||||||
|
|
||||||
/* Sanity check for a file header */
|
ret = efi_check_pe(efi, efi_size, (void **)&nt);
|
||||||
if (efi_size < sizeof(*dos)) {
|
if (ret != EFI_SUCCESS) {
|
||||||
log_err("Truncated DOS Header\n");
|
log_err("Not a PE-COFF file\n");
|
||||||
ret = EFI_LOAD_ERROR;
|
return 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; machines[i]; i++)
|
for (i = 0; machines[i]; i++)
|
||||||
|
@ -746,8 +760,7 @@ efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle,
|
||||||
if (!supported) {
|
if (!supported) {
|
||||||
log_err("Machine type 0x%04x is not supported\n",
|
log_err("Machine type 0x%04x is not supported\n",
|
||||||
nt->FileHeader.Machine);
|
nt->FileHeader.Machine);
|
||||||
ret = EFI_LOAD_ERROR;
|
return EFI_LOAD_ERROR;
|
||||||
goto err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
num_sections = nt->FileHeader.NumberOfSections;
|
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
|
if (efi_size < ((void *)sections + sizeof(sections[0]) * num_sections
|
||||||
- efi)) {
|
- efi)) {
|
||||||
log_err("Invalid number of sections: %d\n", num_sections);
|
log_err("Invalid number of sections: %d\n", num_sections);
|
||||||
ret = EFI_LOAD_ERROR;
|
return EFI_LOAD_ERROR;
|
||||||
goto err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Authenticate an image */
|
/* 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,
|
ret = efi_add_memory_map_pg(memory, pages, EFI_CONVENTIONAL_MEMORY,
|
||||||
false);
|
false);
|
||||||
/* Merging of adjacent free regions is missing */
|
|
||||||
|
|
||||||
if (ret != EFI_SUCCESS)
|
if (ret != EFI_SUCCESS)
|
||||||
return EFI_NOT_FOUND;
|
return EFI_NOT_FOUND;
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
#include <common.h>
|
#include <common.h>
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
|
#include <efi_dt_fixup.h>
|
||||||
#include <efi_loader.h>
|
#include <efi_loader.h>
|
||||||
|
|
||||||
const efi_guid_t efi_u_boot_guid = U_BOOT_GUID;
|
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 */
|
/* Device path utilities protocol */
|
||||||
&efi_guid_device_path_utilities_protocol,
|
&efi_guid_device_path_utilities_protocol,
|
||||||
(void *)&efi_device_path_utilities,
|
(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_PROTOCOL2)
|
||||||
#if CONFIG_IS_ENABLED(EFI_UNICODE_COLLATION_PROTOCOL)
|
#if CONFIG_IS_ENABLED(EFI_UNICODE_COLLATION_PROTOCOL)
|
||||||
/* Deprecated Unicode collation protocol */
|
/* Deprecated Unicode collation protocol */
|
||||||
|
|
|
@ -1,43 +1,41 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0+
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
/*
|
/*
|
||||||
* EFI hello world
|
* Hello world EFI application
|
||||||
*
|
*
|
||||||
* Copyright (c) 2016 Google, Inc
|
* Copyright 2020, Heinrich Schuchardt <xypron.glpk@gmx.de>
|
||||||
* Written by Simon Glass <sjg@chromium.org>
|
|
||||||
*
|
*
|
||||||
* This program demonstrates calling a boottime service.
|
* This test program is used to test the invocation of an EFI application.
|
||||||
* It writes a greeting and the load options to the console.
|
* 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>
|
#include <efi_api.h>
|
||||||
|
|
||||||
static const efi_guid_t loaded_image_guid = EFI_LOADED_IMAGE_PROTOCOL_GUID;
|
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 fdt_guid = EFI_FDT_GUID;
|
||||||
static const efi_guid_t acpi_guid = EFI_ACPI_TABLE_GUID;
|
static const efi_guid_t acpi_guid = EFI_ACPI_TABLE_GUID;
|
||||||
static const efi_guid_t smbios_guid = SMBIOS_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.
|
* print_uefi_revision() - print UEFI revision number
|
||||||
*
|
|
||||||
* @handle: handle of the loaded image
|
|
||||||
* @systable: system table
|
|
||||||
* @return: status code
|
|
||||||
*/
|
*/
|
||||||
efi_status_t EFIAPI efi_main(efi_handle_t handle,
|
static void print_uefi_revision(void)
|
||||||
struct efi_system_table *systable)
|
|
||||||
{
|
{
|
||||||
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";
|
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[0] = (systable->hdr.revision >> 16) + '0';
|
||||||
rev[4] = systable->hdr.revision & 0xffff;
|
rev[4] = systable->hdr.revision & 0xffff;
|
||||||
for (; rev[4] >= 10;) {
|
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, L"Running on UEFI ");
|
||||||
con_out->output_string(con_out, rev);
|
con_out->output_string(con_out, rev);
|
||||||
con_out->output_string(con_out, L"\r\n");
|
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 */
|
/* Find configuration tables */
|
||||||
for (i = 0; i < systable->nr_tables; ++i) {
|
for (i = 0; i < systable->nr_tables; ++i) {
|
||||||
if (!memcmp(&systable->tables[i].guid, &fdt_guid,
|
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->output_string
|
||||||
(con_out, L"Have SMBIOS table\r\n");
|
(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 */
|
/* Output the load options */
|
||||||
con_out->output_string(con_out, L"Load options: ");
|
con_out->output_string(con_out, L"Load options: ");
|
||||||
if (loaded_image->load_options_size && loaded_image->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
|
else
|
||||||
con_out->output_string(con_out, L"<none>");
|
con_out->output_string(con_out, L"<none>");
|
||||||
con_out->output_string(con_out, L"\r\n");
|
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:
|
out:
|
||||||
boottime->exit(handle, ret, 0, NULL);
|
boottime->exit(handle, ret, 0, NULL);
|
||||||
|
|
|
@ -8,10 +8,12 @@
|
||||||
|
|
||||||
#include <common.h>
|
#include <common.h>
|
||||||
#include <efi_api.h>
|
#include <efi_api.h>
|
||||||
|
#include <efi_dt_fixup.h>
|
||||||
|
|
||||||
#define BUFFER_SIZE 64
|
#define BUFFER_SIZE 64
|
||||||
#define ESC 0x17
|
#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 *cerr;
|
||||||
static struct efi_simple_text_output_protocol *cout;
|
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 loaded_image_guid = EFI_LOADED_IMAGE_PROTOCOL_GUID;
|
||||||
static const efi_guid_t guid_simple_file_system_protocol =
|
static const efi_guid_t guid_simple_file_system_protocol =
|
||||||
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID;
|
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
|
* 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 */
|
/* Drain the console input */
|
||||||
ret = cin->reset(cin, true);
|
ret = cin->reset(cin, true);
|
||||||
|
*buffer = 0;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
ret = bs->wait_for_event(1, &cin->wait_for_key, &index);
|
ret = bs->wait_for_event(1, &cin->wait_for_key, &index);
|
||||||
if (ret != EFI_SUCCESS)
|
if (ret != EFI_SUCCESS)
|
||||||
|
@ -62,6 +81,7 @@ static efi_status_t efi_input(u16 *buffer, efi_uintn_t buffer_size)
|
||||||
break;
|
break;
|
||||||
case 0x0a: /* Linefeed */
|
case 0x0a: /* Linefeed */
|
||||||
case 0x0d: /* Carriage return */
|
case 0x0d: /* Carriage return */
|
||||||
|
cout->output_string(cout, L"\n");
|
||||||
return EFI_SUCCESS;
|
return EFI_SUCCESS;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -73,6 +93,7 @@ static efi_status_t efi_input(u16 *buffer, efi_uintn_t buffer_size)
|
||||||
pos < buffer_size - 1) {
|
pos < buffer_size - 1) {
|
||||||
*outbuf = key.unicode_char;
|
*outbuf = key.unicode_char;
|
||||||
buffer[pos++] = key.unicode_char;
|
buffer[pos++] = key.unicode_char;
|
||||||
|
buffer[pos] = 0;
|
||||||
cout->output_string(cout, outbuf);
|
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
|
* @pos: UTF-16 string
|
||||||
* @systable: system table
|
* Return: pointer to first non-whitespace
|
||||||
* @return: status code
|
|
||||||
*/
|
*/
|
||||||
efi_status_t EFIAPI efi_main(efi_handle_t handle,
|
u16 *skip_whitespace(u16 *pos)
|
||||||
struct efi_system_table *systable)
|
|
||||||
{
|
{
|
||||||
efi_uintn_t ret;
|
for (; *pos && *pos <= 0x20; ++pos)
|
||||||
u16 filename[BUFFER_SIZE] = {0};
|
;
|
||||||
efi_uintn_t dtb_size;
|
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_loaded_image *loaded_image;
|
||||||
struct efi_simple_file_system_protocol *file_system;
|
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;
|
struct fdt_header *dtb;
|
||||||
|
efi_uintn_t buffer_size;
|
||||||
|
efi_uintn_t pages;
|
||||||
|
efi_status_t ret, ret2;
|
||||||
|
|
||||||
cerr = systable->std_err;
|
ret = bs->locate_protocol(&efi_dt_fixup_protocol_guid, NULL,
|
||||||
cout = systable->con_out;
|
(void **)&dt_fixup_prot);
|
||||||
cin = systable->con_in;
|
if (ret != EFI_SUCCESS) {
|
||||||
bs = systable->boottime;
|
error(L"Device-tree fix-up protocol not found\n");
|
||||||
|
|
||||||
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)
|
|
||||||
return ret;
|
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,
|
ret = bs->open_protocol(handle, &loaded_image_guid,
|
||||||
(void **)&loaded_image, NULL, NULL,
|
(void **)&loaded_image, NULL, NULL,
|
||||||
EFI_OPEN_PROTOCOL_GET_PROTOCOL);
|
EFI_OPEN_PROTOCOL_GET_PROTOCOL);
|
||||||
if (ret != EFI_SUCCESS) {
|
if (ret != EFI_SUCCESS) {
|
||||||
cerr->output_string(cout,
|
error(L"Loaded image protocol not found\n");
|
||||||
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,15 +369,14 @@ efi_status_t EFIAPI efi_main(efi_handle_t handle,
|
||||||
(void **)&file_system, NULL, NULL,
|
(void **)&file_system, NULL, NULL,
|
||||||
EFI_OPEN_PROTOCOL_GET_PROTOCOL);
|
EFI_OPEN_PROTOCOL_GET_PROTOCOL);
|
||||||
if (ret != EFI_SUCCESS) {
|
if (ret != EFI_SUCCESS) {
|
||||||
cerr->output_string(
|
error(L"Failed to open simple file system protocol\n");
|
||||||
cout, L"Failed to open simple file system protocol\n");
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Open volume */
|
/* Open volume */
|
||||||
ret = file_system->open_volume(file_system, &root);
|
ret = file_system->open_volume(file_system, &root);
|
||||||
if (ret != EFI_SUCCESS) {
|
if (ret != EFI_SUCCESS) {
|
||||||
cerr->output_string(cerr, L"Failed to open volume\n");
|
error(L"Failed to open volume\n");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
/* Create file */
|
/* Create file */
|
||||||
|
@ -199,10 +387,10 @@ efi_status_t EFIAPI efi_main(efi_handle_t handle,
|
||||||
/* Write file */
|
/* Write file */
|
||||||
ret = file->write(file, &dtb_size, dtb);
|
ret = file->write(file, &dtb_size, dtb);
|
||||||
if (ret != EFI_SUCCESS)
|
if (ret != EFI_SUCCESS)
|
||||||
cerr->output_string(cerr, L"Failed to write file\n");
|
error(L"Failed to write file\n");
|
||||||
file->close(file);
|
file->close(file);
|
||||||
} else {
|
} else {
|
||||||
cerr->output_string(cerr, L"Failed to open file\n");
|
error(L"Failed to open file\n");
|
||||||
}
|
}
|
||||||
root->close(root);
|
root->close(root);
|
||||||
|
|
||||||
|
@ -213,3 +401,51 @@ efi_status_t EFIAPI efi_main(efi_handle_t handle,
|
||||||
|
|
||||||
return ret;
|
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");
|
time_start * 1000, "/s");
|
||||||
}
|
}
|
||||||
puts("\ndone\n");
|
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);
|
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);
|
printf("Load address: 0x%lx\n", tftp_load_addr);
|
||||||
puts("Loading: *\b");
|
puts("Loading: *\b");
|
||||||
tftp_state = STATE_SEND_RRQ;
|
tftp_state = STATE_SEND_RRQ;
|
||||||
#ifdef CONFIG_CMD_BOOTEFI
|
|
||||||
efi_set_bootdev("Net", "", tftp_filename);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
time_start = get_timer(0);
|
time_start = get_timer(0);
|
||||||
|
|
|
@ -51,21 +51,21 @@ var_guids = {
|
||||||
}
|
}
|
||||||
|
|
||||||
class EfiStruct:
|
class EfiStruct:
|
||||||
# struct efi_var_file
|
# struct efi_var_file
|
||||||
var_file_fmt = '<QQLL'
|
var_file_fmt = '<QQLL'
|
||||||
var_file_size = struct.calcsize(var_file_fmt)
|
var_file_size = struct.calcsize(var_file_fmt)
|
||||||
# struct efi_var_entry
|
# struct efi_var_entry
|
||||||
var_entry_fmt = '<LLQ16s'
|
var_entry_fmt = '<LLQ16s'
|
||||||
var_entry_size = struct.calcsize(var_entry_fmt)
|
var_entry_size = struct.calcsize(var_entry_fmt)
|
||||||
# struct efi_time
|
# struct efi_time
|
||||||
var_time_fmt = '<H6BLh2B'
|
var_time_fmt = '<H6BLh2B'
|
||||||
var_time_size = struct.calcsize(var_time_fmt)
|
var_time_size = struct.calcsize(var_time_fmt)
|
||||||
# WIN_CERTIFICATE
|
# WIN_CERTIFICATE
|
||||||
var_win_cert_fmt = '<L2H'
|
var_win_cert_fmt = '<L2H'
|
||||||
var_win_cert_size = struct.calcsize(var_win_cert_fmt)
|
var_win_cert_size = struct.calcsize(var_win_cert_fmt)
|
||||||
# WIN_CERTIFICATE_UEFI_GUID
|
# WIN_CERTIFICATE_UEFI_GUID
|
||||||
var_win_cert_uefi_guid_fmt = var_win_cert_fmt+'16s'
|
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)
|
var_win_cert_uefi_guid_size = struct.calcsize(var_win_cert_uefi_guid_fmt)
|
||||||
|
|
||||||
class EfiVariable:
|
class EfiVariable:
|
||||||
def __init__(self, size, attrs, time, guid, name, data):
|
def __init__(self, size, attrs, time, guid, name, data):
|
||||||
|
@ -149,7 +149,7 @@ class EfiVariableStore:
|
||||||
offs = 0
|
offs = 0
|
||||||
while offs < len(self.ents):
|
while offs < len(self.ents):
|
||||||
var, loffs = self._next_var(offs)
|
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:
|
if var.attrs != attrs:
|
||||||
print("err: attributes don't match")
|
print("err: attributes don't match")
|
||||||
exit(1)
|
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"
|
# UEFI 2.8 Errata B "8.2.2 Using the EFI_VARIABLE_AUTHENTICATION_2 descriptor"
|
||||||
def cmd_sign(args):
|
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
|
attrs |= EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
|
||||||
efi = EfiStruct()
|
efi = EfiStruct()
|
||||||
|
|
||||||
|
@ -357,7 +357,10 @@ def main():
|
||||||
signp.set_defaults(func=cmd_sign)
|
signp.set_defaults(func=cmd_sign)
|
||||||
|
|
||||||
args = ap.parse_args()
|
args = ap.parse_args()
|
||||||
args.func(args)
|
if hasattr(args, "func"):
|
||||||
|
args.func(args)
|
||||||
|
else:
|
||||||
|
ap.print_help()
|
||||||
|
|
||||||
def group(a, *ns):
|
def group(a, *ns):
|
||||||
for n in ns:
|
for n in ns:
|
||||||
|
|
Loading…
Reference in New Issue
Block a user