aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2018-07-30 16:02:29 -0400
committerTom Rini <trini@konsulko.com>2018-07-30 16:02:29 -0400
commit406fd7e207d3593f150079514a371dccdc651ce7 (patch)
tree005f94b428abc454efd05f56364ee052cb16ac39 /lib
parent3a8c8bffd767abb350010f3892c0029c54cef725 (diff)
parent0b8a88ab6aa24de0ef2bf1e8109409f71e770a8e (diff)
downloadu-boot-406fd7e207d3593f150079514a371dccdc651ce7.zip
u-boot-406fd7e207d3593f150079514a371dccdc651ce7.tar.gz
u-boot-406fd7e207d3593f150079514a371dccdc651ce7.tar.bz2
Merge tag 'signed-efi-next' of git://github.com/agraf/u-boot
Patch queue for efi - 2018-07-25 Highlights this time: - Many small fixes to improve spec compatibility (found by SCT) - Almost enough to run with sandbox target - GetTime() improvements - Enable EFI_LOADER and HYP entry on ARMv7 with NONSEC=y
Diffstat (limited to 'lib')
-rw-r--r--lib/efi_driver/efi_block_device.c2
-rw-r--r--lib/efi_loader/Kconfig2
-rw-r--r--lib/efi_loader/Makefile3
-rw-r--r--lib/efi_loader/efi_boottime.c169
-rw-r--r--lib/efi_loader/efi_console.c9
-rw-r--r--lib/efi_loader/efi_image_loader.c12
-rw-r--r--lib/efi_loader/efi_memory.c65
-rw-r--r--lib/efi_loader/efi_runtime.c83
-rw-r--r--lib/efi_loader/efi_smbios.c11
-rw-r--r--lib/efi_selftest/.gitignore4
-rw-r--r--lib/efi_selftest/Makefile5
-rw-r--r--lib/efi_selftest/efi_selftest.c14
-rw-r--r--lib/efi_selftest/efi_selftest_block_device.c70
-rw-r--r--lib/efi_selftest/efi_selftest_config_table.c266
-rw-r--r--lib/efi_selftest/efi_selftest_console.c33
-rw-r--r--lib/efi_selftest/efi_selftest_crc32.c141
-rw-r--r--lib/efi_selftest/efi_selftest_rtc.c67
-rw-r--r--lib/vsprintf.c5
18 files changed, 826 insertions, 135 deletions
diff --git a/lib/efi_driver/efi_block_device.c b/lib/efi_driver/efi_block_device.c
index 9c807ff..5b9c139 100644
--- a/lib/efi_driver/efi_block_device.c
+++ b/lib/efi_driver/efi_block_device.c
@@ -161,6 +161,8 @@ static int efi_bl_bind(efi_handle_t handle, void *interface)
return ret;
if (!bdev)
return -ENOENT;
+ /* Set the DM_FLAG_NAME_ALLOCED flag to avoid a memory leak */
+ device_set_name_alloced(bdev);
/* Allocate priv */
ret = device_probe(bdev);
if (ret)
diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig
index df58e63..ce6a09f 100644
--- a/lib/efi_loader/Kconfig
+++ b/lib/efi_loader/Kconfig
@@ -1,8 +1,6 @@
config EFI_LOADER
bool "Support running EFI Applications in U-Boot"
depends on (ARM || X86 || RISCV) && OF_LIBFDT
- # We do not support bootefi booting ARMv7 in non-secure mode
- depends on !ARMV7_NONSEC
# We need EFI_STUB_64BIT to be set on x86_64 with EFI_STUB
depends on !EFI_STUB || !X86_64 || EFI_STUB_64BIT
# We need EFI_STUB_32BIT to be set on x86_32 with EFI_STUB
diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile
index d6402c4..1ffbf52 100644
--- a/lib/efi_loader/Makefile
+++ b/lib/efi_loader/Makefile
@@ -6,6 +6,9 @@
# This file only gets included with CONFIG_EFI_LOADER set, so all
# object inclusion implicitly depends on it
+CFLAGS_efi_boottime.o += \
+ -DFW_VERSION="0x$(VERSION)" \
+ -DFW_PATCHLEVEL="0x$(PATCHLEVEL)"
CFLAGS_helloworld.o := $(CFLAGS_EFI) -Os -ffreestanding
CFLAGS_REMOVE_helloworld.o := $(CFLAGS_NON_EFI) -Os
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
index eeefe0b..b9e54f5 100644
--- a/lib/efi_loader/efi_boottime.c
+++ b/lib/efi_loader/efi_boottime.c
@@ -35,16 +35,6 @@ LIST_HEAD(efi_events);
*/
static bool efi_is_direct_boot = true;
-/*
- * EFI can pass arbitrary additional "tables" containing vendor specific
- * information to the payload. One such table is the FDT table which contains
- * a pointer to a flattened device tree blob.
- *
- * In most cases we want to pass an FDT to the payload, so reserve one slot of
- * config table space for it. The pointer gets populated by do_bootefi_exec().
- */
-static struct efi_configuration_table __efi_runtime_data efi_conf_table[16];
-
#ifdef CONFIG_ARM
/*
* The "gd" pointer lives in a register on ARM and AArch64 that we declare
@@ -164,6 +154,18 @@ const char *__efi_nesting_dec(void)
}
/**
+ * efi_update_table_header_crc32() - Update CRC32 in table header
+ *
+ * @table: EFI table
+ */
+static void efi_update_table_header_crc32(struct efi_table_hdr *table)
+{
+ table->crc32 = 0;
+ table->crc32 = crc32(0, (const unsigned char *)table,
+ table->headersize);
+}
+
+/**
* efi_queue_event() - queue an EFI event
* @event: event to signal
* @check_tpl: check the TPL level
@@ -191,6 +193,25 @@ static void efi_queue_event(struct efi_event *event, bool check_tpl)
}
/**
+ * is_valid_tpl() - check if the task priority level is valid
+ *
+ * @tpl: TPL level to check
+ * ReturnValue: status code
+ */
+efi_status_t is_valid_tpl(efi_uintn_t tpl)
+{
+ switch (tpl) {
+ case TPL_APPLICATION:
+ case TPL_CALLBACK:
+ case TPL_NOTIFY:
+ case TPL_HIGH_LEVEL:
+ return EFI_SUCCESS;
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+}
+
+/**
* efi_signal_event() - signal an EFI event
* @event: event to signal
* @check_tpl: check the TPL level
@@ -592,11 +613,21 @@ efi_status_t efi_create_event(uint32_t type, efi_uintn_t notify_tpl,
if (event == NULL)
return EFI_INVALID_PARAMETER;
- if ((type & EVT_NOTIFY_SIGNAL) && (type & EVT_NOTIFY_WAIT))
+ switch (type) {
+ case 0:
+ case EVT_TIMER:
+ case EVT_NOTIFY_SIGNAL:
+ case EVT_TIMER | EVT_NOTIFY_SIGNAL:
+ case EVT_NOTIFY_WAIT:
+ case EVT_TIMER | EVT_NOTIFY_WAIT:
+ case EVT_SIGNAL_EXIT_BOOT_SERVICES:
+ case EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE:
+ break;
+ default:
return EFI_INVALID_PARAMETER;
+ }
- if ((type & (EVT_NOTIFY_SIGNAL | EVT_NOTIFY_WAIT)) &&
- notify_function == NULL)
+ if (is_valid_tpl(notify_tpl) != EFI_SUCCESS)
return EFI_INVALID_PARAMETER;
evt = calloc(1, sizeof(struct efi_event));
@@ -1361,9 +1392,9 @@ static efi_status_t EFIAPI efi_locate_handle_ext(
*/
static void efi_remove_configuration_table(int i)
{
- struct efi_configuration_table *this = &efi_conf_table[i];
- struct efi_configuration_table *next = &efi_conf_table[i + 1];
- struct efi_configuration_table *end = &efi_conf_table[systab.nr_tables];
+ struct efi_configuration_table *this = &systab.tables[i];
+ struct efi_configuration_table *next = &systab.tables[i + 1];
+ struct efi_configuration_table *end = &systab.tables[systab.nr_tables];
memmove(this, next, (ulong)end - (ulong)next);
systab.nr_tables--;
@@ -1391,9 +1422,9 @@ efi_status_t efi_install_configuration_table(const efi_guid_t *guid,
/* Check for guid override */
for (i = 0; i < systab.nr_tables; i++) {
- if (!guidcmp(guid, &efi_conf_table[i].guid)) {
+ if (!guidcmp(guid, &systab.tables[i].guid)) {
if (table)
- efi_conf_table[i].table = table;
+ systab.tables[i].table = table;
else
efi_remove_configuration_table(i);
goto out;
@@ -1404,15 +1435,18 @@ efi_status_t efi_install_configuration_table(const efi_guid_t *guid,
return EFI_NOT_FOUND;
/* No override, check for overflow */
- if (i >= ARRAY_SIZE(efi_conf_table))
+ if (i >= EFI_MAX_CONFIGURATION_TABLES)
return EFI_OUT_OF_RESOURCES;
/* Add a new entry */
- memcpy(&efi_conf_table[i].guid, guid, sizeof(*guid));
- efi_conf_table[i].table = table;
+ memcpy(&systab.tables[i].guid, guid, sizeof(*guid));
+ systab.tables[i].table = table;
systab.nr_tables = i + 1;
out:
+ /* systab.nr_tables may have changed. So we need to update the crc32 */
+ efi_update_table_header_crc32(&systab.hdr);
+
/* Notify that the configuration table was changed */
list_for_each_entry(evt, &efi_events, link) {
if (evt->group && !guidcmp(evt->group, guid)) {
@@ -1468,6 +1502,7 @@ efi_status_t efi_setup_loaded_image(
/* efi_exit() assumes that the handle points to the info */
obj->handle = info;
+ info->revision = EFI_LOADED_IMAGE_PROTOCOL_REVISION;
info->file_path = file_path;
if (device_path) {
@@ -1825,6 +1860,10 @@ static efi_status_t EFIAPI efi_exit_boot_services(efi_handle_t image_handle,
EFI_ENTRY("%p, %ld", image_handle, map_key);
+ /* Check that the caller has read the current memory map */
+ if (map_key != efi_memory_map_key)
+ return EFI_INVALID_PARAMETER;
+
/* Make sure that notification functions are not called anymore */
efi_tpl = TPL_HIGH_LEVEL;
@@ -1867,9 +1906,7 @@ static efi_status_t EFIAPI efi_exit_boot_services(efi_handle_t image_handle,
systab.boottime = NULL;
/* Recalculate CRC32 */
- systab.hdr.crc32 = 0;
- systab.hdr.crc32 = crc32(0, (const unsigned char *)&systab,
- sizeof(struct efi_system_table));
+ efi_update_table_header_crc32(&systab.hdr);
/* Give the payload some time to boot */
efi_set_watchdog(0);
@@ -2302,7 +2339,7 @@ static efi_status_t EFIAPI efi_install_multiple_protocol_interfaces(
{
EFI_ENTRY("%p", handle);
- va_list argptr;
+ efi_va_list argptr;
const efi_guid_t *protocol;
void *protocol_interface;
efi_status_t r = EFI_SUCCESS;
@@ -2311,12 +2348,12 @@ static efi_status_t EFIAPI efi_install_multiple_protocol_interfaces(
if (!handle)
return EFI_EXIT(EFI_INVALID_PARAMETER);
- va_start(argptr, handle);
+ efi_va_start(argptr, handle);
for (;;) {
- protocol = va_arg(argptr, efi_guid_t*);
+ protocol = efi_va_arg(argptr, efi_guid_t*);
if (!protocol)
break;
- protocol_interface = va_arg(argptr, void*);
+ protocol_interface = efi_va_arg(argptr, void*);
r = EFI_CALL(efi_install_protocol_interface(
handle, protocol,
EFI_NATIVE_INTERFACE,
@@ -2325,19 +2362,19 @@ static efi_status_t EFIAPI efi_install_multiple_protocol_interfaces(
break;
i++;
}
- va_end(argptr);
+ efi_va_end(argptr);
if (r == EFI_SUCCESS)
return EFI_EXIT(r);
/* If an error occurred undo all changes. */
- va_start(argptr, handle);
+ efi_va_start(argptr, handle);
for (; i; --i) {
- protocol = va_arg(argptr, efi_guid_t*);
- protocol_interface = va_arg(argptr, void*);
+ protocol = efi_va_arg(argptr, efi_guid_t*);
+ protocol_interface = efi_va_arg(argptr, void*);
EFI_CALL(efi_uninstall_protocol_interface(handle, protocol,
protocol_interface));
}
- va_end(argptr);
+ efi_va_end(argptr);
return EFI_EXIT(r);
}
@@ -2361,7 +2398,7 @@ static efi_status_t EFIAPI efi_uninstall_multiple_protocol_interfaces(
{
EFI_ENTRY("%p", handle);
- va_list argptr;
+ efi_va_list argptr;
const efi_guid_t *protocol;
void *protocol_interface;
efi_status_t r = EFI_SUCCESS;
@@ -2370,12 +2407,12 @@ static efi_status_t EFIAPI efi_uninstall_multiple_protocol_interfaces(
if (!handle)
return EFI_EXIT(EFI_INVALID_PARAMETER);
- va_start(argptr, handle);
+ efi_va_start(argptr, handle);
for (;;) {
- protocol = va_arg(argptr, efi_guid_t*);
+ protocol = efi_va_arg(argptr, efi_guid_t*);
if (!protocol)
break;
- protocol_interface = va_arg(argptr, void*);
+ protocol_interface = efi_va_arg(argptr, void*);
r = EFI_CALL(efi_uninstall_protocol_interface(
handle, protocol,
protocol_interface));
@@ -2383,20 +2420,20 @@ static efi_status_t EFIAPI efi_uninstall_multiple_protocol_interfaces(
break;
i++;
}
- va_end(argptr);
+ efi_va_end(argptr);
if (r == EFI_SUCCESS)
return EFI_EXIT(r);
/* If an error occurred undo all changes. */
- va_start(argptr, handle);
+ efi_va_start(argptr, handle);
for (; i; --i) {
- protocol = va_arg(argptr, efi_guid_t*);
- protocol_interface = va_arg(argptr, void*);
+ protocol = efi_va_arg(argptr, efi_guid_t*);
+ protocol_interface = efi_va_arg(argptr, void*);
EFI_CALL(efi_install_protocol_interface(&handle, protocol,
EFI_NATIVE_INTERFACE,
protocol_interface));
}
- va_end(argptr);
+ efi_va_end(argptr);
return EFI_EXIT(r);
}
@@ -2414,11 +2451,11 @@ static efi_status_t EFIAPI efi_uninstall_multiple_protocol_interfaces(
*
* Return: status code
*/
-static efi_status_t EFIAPI efi_calculate_crc32(void *data,
- unsigned long data_size,
- uint32_t *crc32_p)
+static efi_status_t EFIAPI efi_calculate_crc32(const void *data,
+ efi_uintn_t data_size,
+ u32 *crc32_p)
{
- EFI_ENTRY("%p, %ld", data, data_size);
+ EFI_ENTRY("%p, %zu", data, data_size);
*crc32_p = crc32(0, data, data_size);
return EFI_EXIT(EFI_SUCCESS);
}
@@ -3022,9 +3059,11 @@ out:
return EFI_EXIT(r);
}
-static const struct efi_boot_services efi_boot_services = {
+static struct efi_boot_services efi_boot_services = {
.hdr = {
- .headersize = sizeof(struct efi_table_hdr),
+ .signature = EFI_BOOT_SERVICES_SIGNATURE,
+ .revision = EFI_SPECIFICATION_VERSION,
+ .headersize = sizeof(struct efi_boot_services),
},
.raise_tpl = efi_raise_tpl,
.restore_tpl = efi_restore_tpl,
@@ -3074,20 +3113,44 @@ static const struct efi_boot_services efi_boot_services = {
.create_event_ex = efi_create_event_ex,
};
-static uint16_t __efi_runtime_data firmware_vendor[] = L"Das U-Boot";
+static u16 __efi_runtime_data firmware_vendor[] = L"Das U-Boot";
struct efi_system_table __efi_runtime_data systab = {
.hdr = {
.signature = EFI_SYSTEM_TABLE_SIGNATURE,
- .revision = 2 << 16 | 70, /* 2.7 */
- .headersize = sizeof(struct efi_table_hdr),
+ .revision = EFI_SPECIFICATION_VERSION,
+ .headersize = sizeof(struct efi_system_table),
},
- .fw_vendor = (long)firmware_vendor,
+ .fw_vendor = firmware_vendor,
+ .fw_revision = FW_VERSION << 16 | FW_PATCHLEVEL << 8,
.con_in = (void *)&efi_con_in,
.con_out = (void *)&efi_con_out,
.std_err = (void *)&efi_con_out,
.runtime = (void *)&efi_runtime_services,
.boottime = (void *)&efi_boot_services,
.nr_tables = 0,
- .tables = (void *)efi_conf_table,
+ .tables = NULL,
};
+
+/**
+ * efi_initialize_system_table() - Initialize system table
+ *
+ * Return Value: status code
+ */
+efi_status_t efi_initialize_system_table(void)
+{
+ efi_status_t ret;
+
+ /* Allocate configuration table array */
+ ret = efi_allocate_pool(EFI_RUNTIME_SERVICES_DATA,
+ EFI_MAX_CONFIGURATION_TABLES *
+ sizeof(struct efi_configuration_table),
+ (void **)&systab.tables);
+
+ /* Set crc32 field in table headers */
+ efi_update_table_header_crc32(&systab.hdr);
+ efi_update_table_header_crc32(&efi_runtime_services.hdr);
+ efi_update_table_header_crc32(&efi_boot_services.hdr);
+
+ return ret;
+}
diff --git a/lib/efi_loader/efi_console.c b/lib/efi_loader/efi_console.c
index ce66c93..3fd0d2f 100644
--- a/lib/efi_loader/efi_console.c
+++ b/lib/efi_loader/efi_console.c
@@ -335,6 +335,8 @@ static efi_status_t EFIAPI efi_cout_clear_screen(
EFI_ENTRY("%p", this);
printf(ESC"[2J");
+ efi_con_mode.cursor_column = 0;
+ efi_con_mode.cursor_row = 0;
return EFI_EXIT(EFI_SUCCESS);
}
@@ -381,7 +383,12 @@ static efi_status_t EFIAPI efi_cin_reset(
bool extended_verification)
{
EFI_ENTRY("%p, %d", this, extended_verification);
- return EFI_EXIT(EFI_UNSUPPORTED);
+
+ /* Empty input buffer */
+ while (tstc())
+ getc();
+
+ return EFI_EXIT(EFI_SUCCESS);
}
/*
diff --git a/lib/efi_loader/efi_image_loader.c b/lib/efi_loader/efi_image_loader.c
index ecdb77e..fdf40a6 100644
--- a/lib/efi_loader/efi_image_loader.c
+++ b/lib/efi_loader/efi_image_loader.c
@@ -19,25 +19,25 @@ const efi_guid_t efi_simple_file_system_protocol_guid =
const efi_guid_t efi_file_info_guid = EFI_FILE_INFO_GUID;
static int machines[] = {
-#if defined(CONFIG_ARM64)
+#if defined(__aarch64__)
IMAGE_FILE_MACHINE_ARM64,
-#elif defined(CONFIG_ARM)
+#elif defined(__arm__)
IMAGE_FILE_MACHINE_ARM,
IMAGE_FILE_MACHINE_THUMB,
IMAGE_FILE_MACHINE_ARMNT,
#endif
-#if defined(CONFIG_X86_64)
+#if defined(__x86_64__)
IMAGE_FILE_MACHINE_AMD64,
-#elif defined(CONFIG_X86)
+#elif defined(__i386__)
IMAGE_FILE_MACHINE_I386,
#endif
-#if defined(CONFIG_CPU_RISCV_32)
+#if defined(__riscv) && (__riscv_xlen == 32)
IMAGE_FILE_MACHINE_RISCV32,
#endif
-#if defined(CONFIG_CPU_RISCV_64)
+#if defined(__riscv) && (__riscv_xlen == 64)
IMAGE_FILE_MACHINE_RISCV64,
#endif
0 };
diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c
index ec66af9..967c3f7 100644
--- a/lib/efi_loader/efi_memory.c
+++ b/lib/efi_loader/efi_memory.c
@@ -9,11 +9,14 @@
#include <efi_loader.h>
#include <inttypes.h>
#include <malloc.h>
+#include <mapmem.h>
#include <watchdog.h>
#include <linux/list_sort.h>
DECLARE_GLOBAL_DATA_PTR;
+efi_uintn_t efi_memory_map_key;
+
struct efi_mem_list {
struct list_head link;
struct efi_mem_desc desc;
@@ -159,9 +162,13 @@ uint64_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type,
debug("%s: 0x%" PRIx64 " 0x%" PRIx64 " %d %s\n", __func__,
start, pages, memory_type, overlap_only_ram ? "yes" : "no");
+ if (memory_type >= EFI_MAX_MEMORY_TYPE)
+ return EFI_INVALID_PARAMETER;
+
if (!pages)
return start;
+ ++efi_memory_map_key;
newlist = calloc(1, sizeof(*newlist));
newlist->desc.type = memory_type;
newlist->desc.physical_start = start;
@@ -292,10 +299,13 @@ efi_status_t efi_allocate_pages(int type, int memory_type,
efi_status_t r = EFI_SUCCESS;
uint64_t addr;
+ if (!memory)
+ return EFI_INVALID_PARAMETER;
+
switch (type) {
case EFI_ALLOCATE_ANY_PAGES:
/* Any page */
- addr = efi_find_free_memory(len, gd->start_addr_sp);
+ addr = efi_find_free_memory(len, -1ULL);
if (!addr) {
r = EFI_NOT_FOUND;
break;
@@ -325,7 +335,7 @@ efi_status_t efi_allocate_pages(int type, int memory_type,
/* Reserve that map in our memory maps */
ret = efi_add_memory_map(addr, pages, memory_type, true);
if (ret == addr) {
- *memory = addr;
+ *memory = (uintptr_t)map_sysmem(addr, len);
} else {
/* Map would overlap, bail out */
r = EFI_OUT_OF_RESOURCES;
@@ -359,11 +369,12 @@ void *efi_alloc(uint64_t len, int memory_type)
efi_status_t efi_free_pages(uint64_t memory, efi_uintn_t pages)
{
uint64_t r = 0;
+ uint64_t addr = map_to_sysmem((void *)(uintptr_t)memory);
- r = efi_add_memory_map(memory, pages, EFI_CONVENTIONAL_MEMORY, false);
+ r = efi_add_memory_map(addr, pages, EFI_CONVENTIONAL_MEMORY, false);
/* Merging of adjacent free regions is missing */
- if (r == memory)
+ if (r == addr)
return EFI_SUCCESS;
return EFI_NOT_FOUND;
@@ -380,20 +391,22 @@ efi_status_t efi_free_pages(uint64_t memory, efi_uintn_t pages)
efi_status_t efi_allocate_pool(int pool_type, efi_uintn_t size, void **buffer)
{
efi_status_t r;
- efi_physical_addr_t t;
+ struct efi_pool_allocation *alloc;
u64 num_pages = (size + sizeof(struct efi_pool_allocation) +
EFI_PAGE_MASK) >> EFI_PAGE_SHIFT;
+ if (!buffer)
+ return EFI_INVALID_PARAMETER;
+
if (size == 0) {
*buffer = NULL;
return EFI_SUCCESS;
}
r = efi_allocate_pages(EFI_ALLOCATE_ANY_PAGES, pool_type, num_pages,
- &t);
+ (uint64_t *)&alloc);
if (r == EFI_SUCCESS) {
- struct efi_pool_allocation *alloc = (void *)(uintptr_t)t;
alloc->num_pages = num_pages;
*buffer = alloc->data;
}
@@ -446,6 +459,9 @@ efi_status_t efi_get_memory_map(efi_uintn_t *memory_map_size,
struct list_head *lhandle;
efi_uintn_t provided_map_size = *memory_map_size;
+ if (!memory_map_size)
+ return EFI_INVALID_PARAMETER;
+
list_for_each(lhandle, &efi_mem)
map_entries++;
@@ -456,6 +472,9 @@ efi_status_t efi_get_memory_map(efi_uintn_t *memory_map_size,
if (provided_map_size < map_size)
return EFI_BUFFER_TOO_SMALL;
+ if (!memory_map)
+ return EFI_INVALID_PARAMETER;
+
if (descriptor_size)
*descriptor_size = sizeof(struct efi_mem_desc);
@@ -463,19 +482,18 @@ efi_status_t efi_get_memory_map(efi_uintn_t *memory_map_size,
*descriptor_version = EFI_MEMORY_DESCRIPTOR_VERSION;
/* Copy list into array */
- if (memory_map) {
- /* Return the list in ascending order */
- memory_map = &memory_map[map_entries - 1];
- list_for_each(lhandle, &efi_mem) {
- struct efi_mem_list *lmem;
+ /* Return the list in ascending order */
+ memory_map = &memory_map[map_entries - 1];
+ list_for_each(lhandle, &efi_mem) {
+ struct efi_mem_list *lmem;
- lmem = list_entry(lhandle, struct efi_mem_list, link);
- *memory_map = lmem->desc;
- memory_map--;
- }
+ lmem = list_entry(lhandle, struct efi_mem_list, link);
+ *memory_map = lmem->desc;
+ memory_map--;
}
- *map_key = 0;
+ if (map_key)
+ *map_key = efi_memory_map_key;
return EFI_SUCCESS;
}
@@ -496,14 +514,13 @@ __weak void efi_add_known_memory(void)
}
}
-int efi_memory_init(void)
+/* Add memory regions for U-Boot's memory and for the runtime services code */
+static void add_u_boot_and_runtime(void)
{
unsigned long runtime_start, runtime_end, runtime_pages;
unsigned long uboot_start, uboot_pages;
unsigned long uboot_stack_size = 16 * 1024 * 1024;
- efi_add_known_memory();
-
/* Add U-Boot */
uboot_start = (gd->start_addr_sp - uboot_stack_size) & ~EFI_PAGE_MASK;
uboot_pages = (gd->ram_top - uboot_start) >> EFI_PAGE_SHIFT;
@@ -516,6 +533,14 @@ int efi_memory_init(void)
runtime_pages = (runtime_end - runtime_start) >> EFI_PAGE_SHIFT;
efi_add_memory_map(runtime_start, runtime_pages,
EFI_RUNTIME_SERVICES_CODE, false);
+}
+
+int efi_memory_init(void)
+{
+ efi_add_known_memory();
+
+ if (!IS_ENABLED(CONFIG_SANDBOX))
+ add_u_boot_and_runtime();
#ifdef CONFIG_EFI_LOADER_BOUNCE_BUFFER
/* Request a 32bit 64MB bounce buffer region */
diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c
index 4874eb6..06958f2 100644
--- a/lib/efi_loader/efi_runtime.c
+++ b/lib/efi_loader/efi_runtime.c
@@ -8,6 +8,7 @@
#include <common.h>
#include <command.h>
#include <dm.h>
+#include <elf.h>
#include <efi_loader.h>
#include <rtc.h>
@@ -32,19 +33,17 @@ static efi_status_t __efi_runtime EFIAPI efi_invalid_parameter(void);
* TODO(sjg@chromium.org): These defines and structs should come from the elf
* header for each arch (or a generic header) rather than being repeated here.
*/
-#if defined(CONFIG_ARM64)
-#define R_RELATIVE 1027
+#if defined(__aarch64__)
+#define R_RELATIVE R_AARCH64_RELATIVE
#define R_MASK 0xffffffffULL
#define IS_RELA 1
-#elif defined(CONFIG_ARM)
-#define R_RELATIVE 23
+#elif defined(__arm__)
+#define R_RELATIVE R_ARM_RELATIVE
#define R_MASK 0xffULL
-#elif defined(CONFIG_X86)
-#include <asm/elf.h>
+#elif defined(__x86_64__) || defined(__i386__)
#define R_RELATIVE R_386_RELATIVE
#define R_MASK 0xffULL
-#elif defined(CONFIG_RISCV)
-#include <elf.h>
+#elif defined(__riscv)
#define R_RELATIVE R_RISCV_RELATIVE
#define R_MASK 0xffULL
#define IS_RELA 1
@@ -55,12 +54,14 @@ struct dyn_sym {
u32 foo2;
u32 foo3;
};
-#ifdef CONFIG_CPU_RISCV_32
+#if (__riscv_xlen == 32)
#define R_ABSOLUTE R_RISCV_32
#define SYM_INDEX 8
-#else
+#elif (__riscv_xlen == 64)
#define R_ABSOLUTE R_RISCV_64
#define SYM_INDEX 32
+#else
+#error unknown riscv target
#endif
#else
#error Need to add relocation awareness
@@ -116,24 +117,41 @@ static void EFIAPI efi_reset_system_boottime(
while (1) { }
}
+/**
+ * efi_get_time_boottime - get current time
+ *
+ * This function implements the GetTime runtime service.
+ * See the Unified Extensible Firmware Interface (UEFI) specification
+ * for details.
+ *
+ * @time: pointer to structure to receive current time
+ * @capabilities: pointer to structure to receive RTC properties
+ * Return Value: status code
+ */
static efi_status_t EFIAPI efi_get_time_boottime(
struct efi_time *time,
struct efi_time_cap *capabilities)
{
-#if defined(CONFIG_CMD_DATE) && defined(CONFIG_DM_RTC)
- struct rtc_time tm;
+#ifdef CONFIG_DM_RTC
+ efi_status_t ret = EFI_SUCCESS;
int r;
+ struct rtc_time tm;
struct udevice *dev;
EFI_ENTRY("%p %p", time, capabilities);
- r = uclass_get_device(UCLASS_RTC, 0, &dev);
- if (r)
- return EFI_EXIT(EFI_DEVICE_ERROR);
+ if (!time) {
+ ret = EFI_INVALID_PARAMETER;
+ goto out;
+ }
- r = dm_rtc_get(dev, &tm);
- if (r)
- return EFI_EXIT(EFI_DEVICE_ERROR);
+ r = uclass_get_device(UCLASS_RTC, 0, &dev);
+ if (!r)
+ r = dm_rtc_get(dev, &tm);
+ if (r) {
+ ret = EFI_DEVICE_ERROR;
+ goto out;
+ }
memset(time, 0, sizeof(*time));
time->year = tm.tm_year;
@@ -141,11 +159,23 @@ static efi_status_t EFIAPI efi_get_time_boottime(
time->day = tm.tm_mday;
time->hour = tm.tm_hour;
time->minute = tm.tm_min;
- time->daylight = tm.tm_isdst;
-
- return EFI_EXIT(EFI_SUCCESS);
+ time->second = tm.tm_sec;
+ time->daylight = EFI_TIME_ADJUST_DAYLIGHT;
+ if (tm.tm_isdst > 0)
+ time->daylight |= EFI_TIME_IN_DAYLIGHT;
+ time->timezone = EFI_UNSPECIFIED_TIMEZONE;
+
+ if (capabilities) {
+ /* Set reasonable dummy values */
+ capabilities->resolution = 1; /* 1 Hz */
+ capabilities->accuracy = 100000000; /* 100 ppm */
+ capabilities->sets_to_zero = false;
+ }
+out:
+ return EFI_EXIT(ret);
#else
- return EFI_DEVICE_ERROR;
+ EFI_ENTRY("%p %p", time, capabilities);
+ return EFI_EXIT(EFI_DEVICE_ERROR);
#endif
}
@@ -173,11 +203,6 @@ efi_status_t __weak __efi_runtime EFIAPI efi_get_time(
return EFI_DEVICE_ERROR;
}
-efi_status_t __weak efi_get_time_init(void)
-{
- return EFI_SUCCESS;
-}
-
struct efi_runtime_detach_list_struct {
void *ptr;
void *patchto;
@@ -458,8 +483,8 @@ efi_status_t __efi_runtime EFIAPI efi_query_variable_info(
struct efi_runtime_services __efi_runtime_data efi_runtime_services = {
.hdr = {
.signature = EFI_RUNTIME_SERVICES_SIGNATURE,
- .revision = EFI_RUNTIME_SERVICES_REVISION,
- .headersize = sizeof(struct efi_table_hdr),
+ .revision = EFI_SPECIFICATION_VERSION,
+ .headersize = sizeof(struct efi_runtime_services),
},
.get_time = &efi_get_time_boottime,
.set_time = (void *)&efi_device_error,
diff --git a/lib/efi_loader/efi_smbios.c b/lib/efi_loader/efi_smbios.c
index 7c3fc8a..932f758 100644
--- a/lib/efi_loader/efi_smbios.c
+++ b/lib/efi_loader/efi_smbios.c
@@ -26,8 +26,15 @@ efi_status_t efi_smbios_register(void)
/* Reserve 4kiB page for SMBIOS */
ret = efi_allocate_pages(EFI_ALLOCATE_MAX_ADDRESS,
EFI_RUNTIME_SERVICES_DATA, 1, &dmi);
- if (ret != EFI_SUCCESS)
- return ret;
+
+ if (ret != EFI_SUCCESS) {
+ /* Could not find space in lowmem, use highmem instead */
+ ret = efi_allocate_pages(EFI_ALLOCATE_ANY_PAGES,
+ EFI_RUNTIME_SERVICES_DATA, 1, &dmi);
+
+ if (ret != EFI_SUCCESS)
+ return ret;
+ }
/*
* Generate SMBIOS tables - we know that efi_allocate_pages() returns
diff --git a/lib/efi_selftest/.gitignore b/lib/efi_selftest/.gitignore
index c527e46..293a17b 100644
--- a/lib/efi_selftest/.gitignore
+++ b/lib/efi_selftest/.gitignore
@@ -1,2 +1,4 @@
-efi_miniapp_file_image.h
+efi_miniapp_file_image_exit.h
+efi_miniapp_file_image_return.h
*.efi
+*.so
diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile
index 4fe404d..590f90b 100644
--- a/lib/efi_selftest/Makefile
+++ b/lib/efi_selftest/Makefile
@@ -13,8 +13,10 @@ CFLAGS_REMOVE_efi_selftest_miniapp_return.o := $(CFLAGS_NON_EFI) -Os
obj-$(CONFIG_CMD_BOOTEFI_SELFTEST) += \
efi_selftest.o \
efi_selftest_bitblt.o \
+efi_selftest_config_table.o \
efi_selftest_controllers.o \
efi_selftest_console.o \
+efi_selftest_crc32.o \
efi_selftest_devicepath.o \
efi_selftest_devicepath_util.o \
efi_selftest_events.o \
@@ -23,6 +25,7 @@ efi_selftest_exitbootservices.o \
efi_selftest_fdt.o \
efi_selftest_gop.o \
efi_selftest_manageprotocols.o \
+efi_selftest_rtc.o \
efi_selftest_snp.o \
efi_selftest_textinput.o \
efi_selftest_textoutput.o \
@@ -41,7 +44,7 @@ endif
# TODO: As of v2018.01 the relocation code for the EFI application cannot
# be built on x86_64.
-ifeq ($(CONFIG_X86_64),)
+ifeq ($(CONFIG_X86_64)$(CONFIG_SANDBOX),)
ifneq ($(CONFIG_CMD_BOOTEFI_SELFTEST),)
diff --git a/lib/efi_selftest/efi_selftest.c b/lib/efi_selftest/efi_selftest.c
index 13eb2cd..dd338db 100644
--- a/lib/efi_selftest/efi_selftest.c
+++ b/lib/efi_selftest/efi_selftest.c
@@ -8,9 +8,7 @@
#include <efi_selftest.h>
#include <vsprintf.h>
-/*
- * Constants for test step bitmap
- */
+/* Constants for test step bitmap */
#define EFI_ST_SETUP 1
#define EFI_ST_EXECUTE 2
#define EFI_ST_TEARDOWN 4
@@ -26,7 +24,7 @@ static u16 reset_message[] = L"Selftest completed";
*
* The size of the memory map is determined.
* Pool memory is allocated to copy the memory map.
- * The memory amp is copied and the map key is obtained.
+ * The memory map is copied and the map key is obtained.
* The map key is used to exit the boot services.
*/
void efi_st_exit_boot_services(void)
@@ -146,7 +144,7 @@ static int teardown(struct efi_unit_test *test, unsigned int *failures)
* Check that a test exists.
*
* @testname: name of the test
- * @return: test
+ * @return: test, or NULL if not found
*/
static struct efi_unit_test *find_test(const u16 *testname)
{
@@ -182,7 +180,7 @@ static void list_all_tests(void)
*
* @testname name of a single selected test or NULL
* @phase test phase
- * @steps steps to execute
+ * @steps steps to execute (mask with bits from EFI_ST_...)
* failures returns EFI_ST_SUCCESS if all test steps succeeded
*/
void efi_st_do_tests(const u16 *testname, unsigned int phase,
@@ -296,12 +294,12 @@ efi_status_t EFIAPI efi_selftest(efi_handle_t image_handle,
efi_st_printc(EFI_WHITE, "\nSummary: %u failures\n\n", failures);
/* Reset system */
- efi_st_printf("Preparing for reset. Press any key.\n");
+ efi_st_printf("Preparing for reset. Press any key...\n");
efi_st_get_key();
runtime->reset_system(EFI_RESET_WARM, EFI_NOT_READY,
sizeof(reset_message), reset_message);
efi_st_printf("\n");
- efi_st_error("Reset failed.\n");
+ efi_st_error("Reset failed\n");
return EFI_UNSUPPORTED;
}
diff --git a/lib/efi_selftest/efi_selftest_block_device.c b/lib/efi_selftest/efi_selftest_block_device.c
index 4af8bd8..b82e405 100644
--- a/lib/efi_selftest/efi_selftest_block_device.c
+++ b/lib/efi_selftest/efi_selftest_block_device.c
@@ -309,11 +309,14 @@ static int execute(void)
efi_uintn_t buf_size;
char buf[16] __aligned(ARCH_DMA_MINALIGN);
+ /* Connect controller to virtual disk */
ret = boottime->connect_controller(disk_handle, NULL, NULL, 1);
if (ret != EFI_SUCCESS) {
efi_st_error("Failed to connect controller\n");
return EFI_ST_FAILURE;
}
+
+ /* Get the handle for the partition */
ret = boottime->locate_handle_buffer(
BY_PROTOCOL, &guid_device_path, NULL,
&no_handles, &handles);
@@ -347,6 +350,8 @@ static int execute(void)
efi_st_error("Partition handle not found\n");
return EFI_ST_FAILURE;
}
+
+ /* Open the simple file system protocol */
ret = boottime->open_protocol(handle_partition,
&guid_simple_file_system_protocol,
(void **)&file_system, NULL, NULL,
@@ -355,6 +360,8 @@ static int execute(void)
efi_st_error("Failed to open simple file system protocol\n");
return EFI_ST_FAILURE;
}
+
+ /* Open volume */
ret = file_system->open_volume(file_system, &root);
if (ret != EFI_SUCCESS) {
efi_st_error("Failed to open volume\n");
@@ -377,6 +384,8 @@ static int execute(void)
"Wrong volume label '%ps', expected 'U-BOOT TEST'\n",
system_info.info.volume_label);
}
+
+ /* Read file */
ret = root->open(root, &file, (s16 *)L"hello.txt", EFI_FILE_MODE_READ,
0);
if (ret != EFI_SUCCESS) {
@@ -389,6 +398,11 @@ static int execute(void)
efi_st_error("Failed to read file\n");
return EFI_ST_FAILURE;
}
+ if (buf_size != 13) {
+ efi_st_error("Wrong number of bytes read: %u\n",
+ (unsigned int)buf_size);
+ return EFI_ST_FAILURE;
+ }
if (efi_st_memcmp(buf, "Hello world!", 12)) {
efi_st_error("Unexpected file content\n");
return EFI_ST_FAILURE;
@@ -398,6 +412,62 @@ static int execute(void)
efi_st_error("Failed to close file\n");
return EFI_ST_FAILURE;
}
+
+#ifdef CONFIG_FAT_WRITE
+ /* Write file */
+ ret = root->open(root, &file, (s16 *)L"u-boot.txt",
+ EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE, 0);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("Failed to open file\n");
+ return EFI_ST_FAILURE;
+ }
+ buf_size = 7;
+ boottime->set_mem(buf, sizeof(buf), 0);
+ boottime->copy_mem(buf, "U-Boot", buf_size);
+ ret = file->write(file, &buf_size, buf);
+ if (ret != EFI_SUCCESS || buf_size != 7) {
+ efi_st_error("Failed to write file\n");
+ return EFI_ST_FAILURE;
+ }
+ ret = file->close(file);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("Failed to close file\n");
+ return EFI_ST_FAILURE;
+ }
+
+ /* Verify file */
+ boottime->set_mem(buf, sizeof(buf), 0);
+ ret = root->open(root, &file, (s16 *)L"u-boot.txt", EFI_FILE_MODE_READ,
+ 0);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("Failed to open file\n");
+ return EFI_ST_FAILURE;
+ }
+ buf_size = sizeof(buf) - 1;
+ ret = file->read(file, &buf_size, buf);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("Failed to read file\n");
+ return EFI_ST_FAILURE;
+ }
+ if (buf_size != 7) {
+ efi_st_error("Wrong number of bytes read: %u\n",
+ (unsigned int)buf_size);
+ return EFI_ST_FAILURE;
+ }
+ if (efi_st_memcmp(buf, "U-Boot", 7)) {
+ efi_st_error("Unexpected file content %s\n", buf);
+ return EFI_ST_FAILURE;
+ }
+ ret = file->close(file);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("Failed to close file\n");
+ return EFI_ST_FAILURE;
+ }
+#else
+ efi_st_todo("CONFIG_FAT_WRITE is not set\n");
+#endif /* CONFIG_FAT_WRITE */
+
+ /* Close volume */
ret = root->close(root);
if (ret != EFI_SUCCESS) {
efi_st_error("Failed to close volume\n");
diff --git a/lib/efi_selftest/efi_selftest_config_table.c b/lib/efi_selftest/efi_selftest_config_table.c
new file mode 100644
index 0000000..2aa3fc7
--- /dev/null
+++ b/lib/efi_selftest/efi_selftest_config_table.c
@@ -0,0 +1,266 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * efi_selftest_config_tables
+ *
+ * Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de>
+ *
+ * This test checks the following service:
+ * InstallConfigurationTable.
+ */
+
+#include <efi_selftest.h>
+
+static const struct efi_system_table *sys_table;
+static struct efi_boot_services *boottime;
+
+static efi_guid_t table_guid =
+ EFI_GUID(0xff1c3f9e, 0x795b, 0x1529, 0xf1, 0x55,
+ 0x17, 0x2e, 0x51, 0x6b, 0x49, 0x75);
+
+/*
+ * Notification function, increments the notfication count if parameter
+ * context is provided.
+ *
+ * @event notified event
+ * @context pointer to the notification count
+ */
+static void EFIAPI notify(struct efi_event *event, void *context)
+{
+ unsigned int *count = context;
+
+ if (count)
+ ++*count;
+}
+
+/*
+ * Check crc32 of a table.
+ */
+static int check_table(const void *table)
+{
+ efi_status_t ret;
+ u32 crc32, res;
+ /* Casting from const to not const */
+ struct efi_table_hdr *hdr = (struct efi_table_hdr *)table;
+
+ crc32 = hdr->crc32;
+ /*
+ * Setting the crc32 of the 'const' table to zero is easier than
+ * copying
+ */
+ hdr->crc32 = 0;
+ ret = boottime->calculate_crc32(table, hdr->headersize, &res);
+ /* Reset table crc32 so it stays constant */
+ hdr->crc32 = crc32;
+ if (ret != EFI_ST_SUCCESS) {
+ efi_st_error("CalculateCrc32 failed\n");
+ return EFI_ST_FAILURE;
+ }
+ if (res != crc32) {
+ efi_st_error("Incorrect CRC32\n");
+ return EFI_ST_FAILURE;
+ }
+ return EFI_ST_SUCCESS;
+}
+
+/*
+ * Setup unit test.
+ *
+ * @handle: handle of the loaded image
+ * @systable: system table
+ * @return: EFI_ST_SUCCESS for success
+ */
+static int setup(const efi_handle_t handle,
+ const struct efi_system_table *systable)
+{
+ sys_table = systable;
+ boottime = systable->boottime;
+
+ return EFI_ST_SUCCESS;
+}
+
+/*
+ * Execute unit test.
+ *
+ * A table is installed, updated, removed. The table entry and the
+ * triggering of events is checked.
+ *
+ * @return: EFI_ST_SUCCESS for success
+ */
+static int execute(void)
+{
+ efi_status_t ret;
+ unsigned int counter = 0;
+ struct efi_event *event;
+ void *table;
+ const unsigned int tables[2];
+ efi_uintn_t i;
+ efi_uintn_t tabcnt;
+ efi_uintn_t table_count = sys_table->nr_tables;
+
+ ret = boottime->create_event_ex(0, TPL_NOTIFY,
+ notify, (void *)&counter,
+ &table_guid, &event);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("Failed to create event\n");
+ return EFI_ST_FAILURE;
+ }
+
+ /* Try to delete non-existent table */
+ ret = boottime->install_configuration_table(&table_guid, NULL);
+ if (ret != EFI_NOT_FOUND) {
+ efi_st_error("Failed to detect missing table\n");
+ return EFI_ST_FAILURE;
+ }
+ if (counter) {
+ efi_st_error("Notification function was called.\n");
+ return EFI_ST_FAILURE;
+ }
+ /* Check if the event was signaled */
+ ret = boottime->check_event(event);
+ if (ret == EFI_SUCCESS) {
+ efi_st_error("Event was signaled on EFI_NOT_FOUND\n");
+ return EFI_ST_FAILURE;
+ }
+ if (counter != 1) {
+ efi_st_error("Notification function was not called.\n");
+ return EFI_ST_FAILURE;
+ }
+ if (table_count != sys_table->nr_tables) {
+ efi_st_error("Incorrect table count %u, expected %u\n",
+ (unsigned int)sys_table->nr_tables,
+ (unsigned int)table_count);
+ return EFI_ST_FAILURE;
+ }
+
+ /* Install table */
+ ret = boottime->install_configuration_table(&table_guid,
+ (void *)&tables[0]);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("Failed to install table\n");
+ return EFI_ST_FAILURE;
+ }
+ /* Check signaled state */
+ ret = boottime->check_event(event);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("Event was not signaled on insert\n");
+ return EFI_ST_FAILURE;
+ }
+ if (++table_count != sys_table->nr_tables) {
+ efi_st_error("Incorrect table count %u, expected %u\n",
+ (unsigned int)sys_table->nr_tables,
+ (unsigned int)table_count);
+ return EFI_ST_FAILURE;
+ }
+ table = NULL;
+ for (i = 0; i < sys_table->nr_tables; ++i) {
+ if (!efi_st_memcmp(&sys_table->tables[i].guid, &table_guid,
+ sizeof(efi_guid_t)))
+ table = sys_table->tables[i].table;
+ }
+ if (!table) {
+ efi_st_error("Installed table not found\n");
+ return EFI_ST_FAILURE;
+ }
+ if (table != &tables[0]) {
+ efi_st_error("Incorrect table address\n");
+ return EFI_ST_FAILURE;
+ }
+ if (check_table(sys_table) != EFI_ST_SUCCESS) {
+ efi_st_error("Checking system table\n");
+ return EFI_ST_FAILURE;
+ }
+
+ /* Update table */
+ ret = boottime->install_configuration_table(&table_guid,
+ (void *)&tables[1]);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("Failed to update table\n");
+ return EFI_ST_FAILURE;
+ }
+ /* Check signaled state */
+ ret = boottime->check_event(event);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("Event was not signaled on update\n");
+ return EFI_ST_FAILURE;
+ }
+ if (table_count != sys_table->nr_tables) {
+ efi_st_error("Incorrect table count %u, expected %u\n",
+ (unsigned int)sys_table->nr_tables,
+ (unsigned int)table_count);
+ return EFI_ST_FAILURE;
+ }
+ table = NULL;
+ tabcnt = 0;
+ for (i = 0; i < sys_table->nr_tables; ++i) {
+ if (!efi_st_memcmp(&sys_table->tables[i].guid, &table_guid,
+ sizeof(efi_guid_t))) {
+ table = sys_table->tables[i].table;
+ ++tabcnt;
+ }
+ }
+ if (!table) {
+ efi_st_error("Installed table not found\n");
+ return EFI_ST_FAILURE;
+ }
+ if (tabcnt > 1) {
+ efi_st_error("Duplicate table guid\n");
+ return EFI_ST_FAILURE;
+ }
+ if (table != &tables[1]) {
+ efi_st_error("Incorrect table address\n");
+ return EFI_ST_FAILURE;
+ }
+ if (check_table(sys_table) != EFI_ST_SUCCESS) {
+ efi_st_error("Checking system table\n");
+ return EFI_ST_FAILURE;
+ }
+
+ /* Delete table */
+ ret = boottime->install_configuration_table(&table_guid, NULL);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("Failed to delete table\n");
+ return EFI_ST_FAILURE;
+ }
+ /* Check signaled state */
+ ret = boottime->check_event(event);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("Event was not signaled on delete\n");
+ return EFI_ST_FAILURE;
+ }
+ if (--table_count != sys_table->nr_tables) {
+ efi_st_error("Incorrect table count %u, expected %u\n",
+ (unsigned int)sys_table->nr_tables,
+ (unsigned int)table_count);
+ return EFI_ST_FAILURE;
+ }
+ table = NULL;
+ for (i = 0; i < sys_table->nr_tables; ++i) {
+ if (!efi_st_memcmp(&sys_table->tables[i].guid, &table_guid,
+ sizeof(efi_guid_t))) {
+ table = sys_table->tables[i].table;
+ }
+ }
+ if (table) {
+ efi_st_error("Wrong table deleted\n");
+ return EFI_ST_FAILURE;
+ }
+
+ ret = boottime->close_event(event);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("Failed to close event\n");
+ return EFI_ST_FAILURE;
+ }
+ if (check_table(sys_table) != EFI_ST_SUCCESS) {
+ efi_st_error("Checking system table\n");
+ return EFI_ST_FAILURE;
+ }
+
+ return EFI_ST_SUCCESS;
+}
+
+EFI_UNIT_TEST(configtables) = {
+ .name = "configuration tables",
+ .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
+ .setup = setup,
+ .execute = execute,
+};
diff --git a/lib/efi_selftest/efi_selftest_console.c b/lib/efi_selftest/efi_selftest_console.c
index c3655a1..eb139c1 100644
--- a/lib/efi_selftest/efi_selftest_console.c
+++ b/lib/efi_selftest/efi_selftest_console.c
@@ -70,11 +70,12 @@ static void pointer(void *pointer, u16 **buf)
/*
* Print an unsigned 32bit value as decimal number to an u16 string
*
- * @value: value to be printed
- * @buf: pointer to buffer address
- * on return position of terminating zero word
+ * @value: value to be printed
+ * @prec: minimum number of digits to display
+ * @buf: pointer to buffer address
+ * on return position of terminating zero word
*/
-static void uint2dec(u32 value, u16 **buf)
+static void uint2dec(u32 value, int prec, u16 **buf)
{
u16 *pos = *buf;
int i;
@@ -93,7 +94,7 @@ static void uint2dec(u32 value, u16 **buf)
for (i = 0; i < 10; ++i) {
/* Write current digit */
c = f >> 60;
- if (c || pos != *buf)
+ if (c || pos != *buf || 10 - i <= prec)
*pos++ = c + '0';
/* Eliminate current digit */
f &= 0xfffffffffffffff;
@@ -109,11 +110,12 @@ static void uint2dec(u32 value, u16 **buf)
/*
* Print a signed 32bit value as decimal number to an u16 string
*
- * @value: value to be printed
- * @buf: pointer to buffer address
+ * @value: value to be printed
+ * @prec: minimum number of digits to display
+ * @buf: pointer to buffer address
* on return position of terminating zero word
*/
-static void int2dec(s32 value, u16 **buf)
+static void int2dec(s32 value, int prec, u16 **buf)
{
u32 u;
u16 *pos = *buf;
@@ -124,7 +126,7 @@ static void int2dec(s32 value, u16 **buf)
} else {
u = value;
}
- uint2dec(u, &pos);
+ uint2dec(u, prec, &pos);
*buf = pos;
}
@@ -143,6 +145,7 @@ void efi_st_printc(int color, const char *fmt, ...)
u16 *pos = buf;
const char *s;
u16 *u;
+ int prec;
va_start(args, fmt);
@@ -172,12 +175,20 @@ void efi_st_printc(int color, const char *fmt, ...)
break;
case '%':
++c;
+ /* Parse precision */
+ if (*c == '.') {
+ ++c;
+ prec = *c - '0';
+ ++c;
+ } else {
+ prec = 0;
+ }
switch (*c) {
case '\0':
--c;
break;
case 'd':
- int2dec(va_arg(args, s32), &pos);
+ int2dec(va_arg(args, s32), prec, &pos);
break;
case 'p':
++c;
@@ -209,7 +220,7 @@ void efi_st_printc(int color, const char *fmt, ...)
*pos++ = *s;
break;
case 'u':
- uint2dec(va_arg(args, u32), &pos);
+ uint2dec(va_arg(args, u32), prec, &pos);
break;
default:
break;
diff --git a/lib/efi_selftest/efi_selftest_crc32.c b/lib/efi_selftest/efi_selftest_crc32.c
new file mode 100644
index 0000000..8555b8f
--- /dev/null
+++ b/lib/efi_selftest/efi_selftest_crc32.c
@@ -0,0 +1,141 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * efi_selftest_crc32
+ *
+ * Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de>
+ *
+ * This unit test checks the CalculateCrc32 bootservice and checks the
+ * headers of the system table, the boot services tablle, and the runtime
+ * services table before and after ExitBootServices().
+ */
+
+#include <efi_selftest.h>
+
+const struct efi_system_table *st;
+efi_status_t (EFIAPI *bs_crc32)(const void *data, efi_uintn_t data_size,
+ u32 *crc32);
+
+static int check_table(const void *table)
+{
+ efi_status_t ret;
+ u32 crc32, res;
+ /* Casting from const to not const */
+ struct efi_table_hdr *hdr = (struct efi_table_hdr *)table;
+
+ if (!hdr->signature) {
+ efi_st_error("Missing header signature\n");
+ return EFI_ST_FAILURE;
+ }
+ if (!hdr->revision) {
+ efi_st_error("Missing header revision\n");
+ return EFI_ST_FAILURE;
+ }
+ if (hdr->headersize <= sizeof(struct efi_table_hdr)) {
+ efi_st_error("Incorrect headersize value\n");
+ return EFI_ST_FAILURE;
+ }
+ if (hdr->reserved) {
+ efi_st_error("Reserved header field is not zero\n");
+ return EFI_ST_FAILURE;
+ }
+
+ crc32 = hdr->crc32;
+ /*
+ * Setting the crc32 of the 'const' table to zero is easier than
+ * copying
+ */
+ hdr->crc32 = 0;
+ ret = bs_crc32(table, hdr->headersize, &res);
+ /* Reset table crc32 so it stays constant */
+ hdr->crc32 = crc32;
+ if (ret != EFI_ST_SUCCESS) {
+ efi_st_error("CalculateCrc32 failed\n");
+ return EFI_ST_FAILURE;
+ }
+ if (res != crc32) {
+ efi_st_error("Incorrect CRC32\n");
+ // return EFI_ST_FAILURE;
+ }
+ return EFI_ST_SUCCESS;
+}
+
+/*
+ * Setup unit test.
+ *
+ * Check that CalculateCrc32 is working correctly.
+ * Check tables before ExitBootServices().
+ *
+ * @handle: handle of the loaded image
+ * @systable: system table
+ * @return: EFI_ST_SUCCESS for success
+ */
+static int setup(const efi_handle_t handle,
+ const struct efi_system_table *systable)
+{
+ efi_status_t ret;
+ u32 res;
+
+ st = systable;
+ bs_crc32 = systable->boottime->calculate_crc32;
+
+ /* Check that CalculateCrc32 is working */
+ ret = bs_crc32("U-Boot", 6, &res);
+ if (ret != EFI_ST_SUCCESS) {
+ efi_st_error("CalculateCrc32 failed\n");
+ return EFI_ST_FAILURE;
+ }
+ if (res != 0x134b0db4) {
+ efi_st_error("Incorrect CRC32\n");
+ return EFI_ST_FAILURE;
+ }
+
+ /* Check tables before ExitBootServices() */
+ if (check_table(st) != EFI_ST_SUCCESS) {
+ efi_st_error("Checking system table\n");
+ return EFI_ST_FAILURE;
+ }
+ if (check_table(st->boottime) != EFI_ST_SUCCESS) {
+ efi_st_error("Checking boottime table\n");
+ return EFI_ST_FAILURE;
+ }
+ if (check_table(st->runtime) != EFI_ST_SUCCESS) {
+ efi_st_error("Checking runtime table\n");
+ return EFI_ST_FAILURE;
+ }
+
+ return EFI_ST_SUCCESS;
+}
+
+/*
+ * Execute unit test
+ *
+ * Check tables after ExitBootServices()
+ *
+ * @return: EFI_ST_SUCCESS for success
+ */
+static int execute(void)
+{
+ if (check_table(st) != EFI_ST_SUCCESS) {
+ efi_st_error("Checking system table\n");
+ return EFI_ST_FAILURE;
+ }
+ if (check_table(st->runtime) != EFI_ST_SUCCESS) {
+ efi_st_error("Checking runtime table\n");
+ return EFI_ST_FAILURE;
+ }
+
+ /*
+ * We cannot call SetVirtualAddressMap() and recheck the runtime
+ * table afterwards because this would invalidate the addresses of the
+ * unit tests.
+ */
+
+ return EFI_ST_SUCCESS;
+}
+
+EFI_UNIT_TEST(crc32) = {
+ .name = "crc32",
+ .phase = EFI_SETUP_BEFORE_BOOTTIME_EXIT,
+ .setup = setup,
+ .execute = execute,
+};
diff --git a/lib/efi_selftest/efi_selftest_rtc.c b/lib/efi_selftest/efi_selftest_rtc.c
new file mode 100644
index 0000000..8d440dc
--- /dev/null
+++ b/lib/efi_selftest/efi_selftest_rtc.c
@@ -0,0 +1,67 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * efi_selftest_rtc
+ *
+ * Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de>
+ *
+ * Test the real time clock runtime services.
+ */
+
+#include <efi_selftest.h>
+
+#define EFI_ST_NO_RTC "Could not read real time clock\n"
+
+static struct efi_runtime_services *runtime;
+
+/*
+ * Setup unit test.
+ *
+ * @handle: handle of the loaded image
+ * @systable: system table
+ * @return: EFI_ST_SUCCESS for success
+ */
+static int setup(const efi_handle_t handle,
+ const struct efi_system_table *systable)
+{
+ runtime = systable->runtime;
+ return EFI_ST_SUCCESS;
+}
+
+/*
+ * Execute unit test.
+ *
+ * Display current time.
+ *
+ * @return: EFI_ST_SUCCESS for success
+ */
+static int execute(void)
+{
+ efi_status_t ret;
+ struct efi_time tm;
+
+ /* Display current time */
+ ret = runtime->get_time(&tm, NULL);
+ if (ret != EFI_SUCCESS) {
+#ifdef CONFIG_CMD_DATE
+ efi_st_error(EFI_ST_NO_RTC);
+ return EFI_ST_FAILURE;
+#else
+ efi_st_todo(EFI_ST_NO_RTC);
+ return EFI_ST_SUCCESS;
+#endif
+ } else {
+ efi_st_printf("Time according to real time clock: "
+ "%.4u-%.2u-%.2u %.2u:%.2u:%.2u\n",
+ tm.year, tm.month, tm.day,
+ tm.hour, tm.minute, tm.second);
+ }
+
+ return EFI_ST_SUCCESS;
+}
+
+EFI_UNIT_TEST(rtc) = {
+ .name = "real time clock",
+ .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
+ .setup = setup,
+ .execute = execute,
+};
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index 8b1b29f..914fbd3 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -407,7 +407,10 @@ static char *uuid_string(char *buf, char *end, u8 *addr, int field_width,
break;
}
- uuid_bin_to_str(addr, uuid, str_format);
+ if (addr)
+ uuid_bin_to_str(addr, uuid, str_format);
+ else
+ strcpy(uuid, "<NULL>");
return string(buf, end, uuid, field_width, precision, flags);
}