diff options
author | Tom Rini | 2018-07-30 16:02:29 -0400 |
---|---|---|
committer | Tom Rini | 2018-07-30 16:02:29 -0400 |
commit | 406fd7e207d3593f150079514a371dccdc651ce7 (patch) | |
tree | 005f94b428abc454efd05f56364ee052cb16ac39 /lib | |
parent | 3a8c8bffd767abb350010f3892c0029c54cef725 (diff) | |
parent | 0b8a88ab6aa24de0ef2bf1e8109409f71e770a8e (diff) |
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.c | 2 | ||||
-rw-r--r-- | lib/efi_loader/Kconfig | 2 | ||||
-rw-r--r-- | lib/efi_loader/Makefile | 3 | ||||
-rw-r--r-- | lib/efi_loader/efi_boottime.c | 169 | ||||
-rw-r--r-- | lib/efi_loader/efi_console.c | 9 | ||||
-rw-r--r-- | lib/efi_loader/efi_image_loader.c | 12 | ||||
-rw-r--r-- | lib/efi_loader/efi_memory.c | 65 | ||||
-rw-r--r-- | lib/efi_loader/efi_runtime.c | 83 | ||||
-rw-r--r-- | lib/efi_loader/efi_smbios.c | 11 | ||||
-rw-r--r-- | lib/efi_selftest/.gitignore | 4 | ||||
-rw-r--r-- | lib/efi_selftest/Makefile | 5 | ||||
-rw-r--r-- | lib/efi_selftest/efi_selftest.c | 14 | ||||
-rw-r--r-- | lib/efi_selftest/efi_selftest_block_device.c | 70 | ||||
-rw-r--r-- | lib/efi_selftest/efi_selftest_config_table.c | 266 | ||||
-rw-r--r-- | lib/efi_selftest/efi_selftest_console.c | 33 | ||||
-rw-r--r-- | lib/efi_selftest/efi_selftest_crc32.c | 141 | ||||
-rw-r--r-- | lib/efi_selftest/efi_selftest_rtc.c | 67 | ||||
-rw-r--r-- | lib/vsprintf.c | 5 |
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 9c807ff71df..5b9c139f389 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 df58e633d1c..ce6a09f0b43 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 d6402c4615f..1ffbf52a898 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 eeefe0bdfe3..b9e54f551a4 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 ce66c935ecb..3fd0d2fd516 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 ecdb77e5b6b..fdf40a62c8e 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 ec66af98ea8..967c3f733e4 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 4874eb602f7..06958f23fa1 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 7c3fc8af0b2..932f7582ec6 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 c527e464e53..293a17b818c 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 4fe404d88d8..590f90b16d3 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 13eb2cd6048..dd338db687e 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 4af8bd8cb28..b82e4050302 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 00000000000..2aa3fc72847 --- /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 c3655a1fcc0..eb139c127cb 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 00000000000..8555b8f1140 --- /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 00000000000..8d440dc0b3c --- /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 8b1b29fb5aa..914fbd30cbc 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); } |