diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/efi_loader/efi_bootmgr.c | 6 | ||||
-rw-r--r-- | lib/efi_loader/efi_device_path.c | 33 | ||||
-rw-r--r-- | lib/efi_loader/efi_runtime.c | 7 | ||||
-rw-r--r-- | lib/efi_selftest/Makefile | 1 | ||||
-rw-r--r-- | lib/efi_selftest/efi_selftest.c | 10 | ||||
-rw-r--r-- | lib/efi_selftest/efi_selftest_reset.c | 58 | ||||
-rw-r--r-- | lib/fdtdec.c | 106 | ||||
-rw-r--r-- | lib/sscanf.c | 3 |
8 files changed, 193 insertions, 31 deletions
diff --git a/lib/efi_loader/efi_bootmgr.c b/lib/efi_loader/efi_bootmgr.c index 1e06e609639..61dc72a23da 100644 --- a/lib/efi_loader/efi_bootmgr.c +++ b/lib/efi_loader/efi_bootmgr.c @@ -105,10 +105,8 @@ efi_status_t efi_deserialize_load_option(struct efi_load_option *lo, u8 *data, if (*size < len) return EFI_INVALID_PARAMETER; lo->file_path = (struct efi_device_path *)data; - /* - * TODO: validate device path. There should be an end node within - * the indicated file_path_length. - */ + if (efi_dp_check_length(lo->file_path, len) < 0) + return EFI_INVALID_PARAMETER; data += len; *size -= len; diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c index 7ae14f34239..8a5c13c4241 100644 --- a/lib/efi_loader/efi_device_path.c +++ b/lib/efi_loader/efi_device_path.c @@ -1127,3 +1127,36 @@ efi_status_t efi_dp_from_name(const char *dev, const char *devnr, return EFI_SUCCESS; } + +/** + * efi_dp_check_length() - check length of a device path + * + * @dp: pointer to device path + * @maxlen: maximum length of the device path + * Return: + * * length of the device path if it is less or equal @maxlen + * * -1 if the device path is longer then @maxlen + * * -1 if a device path node has a length of less than 4 + * * -EINVAL if maxlen exceeds SSIZE_MAX + */ +ssize_t efi_dp_check_length(const struct efi_device_path *dp, + const size_t maxlen) +{ + ssize_t ret = 0; + u16 len; + + if (maxlen > SSIZE_MAX) + return -EINVAL; + for (;;) { + len = dp->length; + if (len < 4) + return -1; + ret += len; + if (ret > maxlen) + return -1; + if (dp->type == DEVICE_PATH_TYPE_END && + dp->sub_type == DEVICE_PATH_SUB_TYPE_END) + return ret; + dp = (const struct efi_device_path *)((const u8 *)dp + len); + } +} diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c index 78fd8014d90..dea2b4e5eea 100644 --- a/lib/efi_loader/efi_runtime.c +++ b/lib/efi_loader/efi_runtime.c @@ -365,7 +365,9 @@ out: * efi_reset_system() - reset system * * This function implements the ResetSystem() runtime service after - * SetVirtualAddressMap() is called. It only executes an endless loop. + * SetVirtualAddressMap() is called. As this placeholder cannot reset the + * system it simply return to the caller. + * * Boards may override the helpers below to implement reset functionality. * * See the Unified Extensible Firmware Interface (UEFI) specification for @@ -381,8 +383,7 @@ void __weak __efi_runtime EFIAPI efi_reset_system( efi_status_t reset_status, unsigned long data_size, void *reset_data) { - /* Nothing we can do */ - while (1) { } + return; } /** diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile index 45ce6859b86..85fe8e1216a 100644 --- a/lib/efi_selftest/Makefile +++ b/lib/efi_selftest/Makefile @@ -31,6 +31,7 @@ efi_selftest_mem.o \ efi_selftest_memory.o \ efi_selftest_open_protocol.o \ efi_selftest_register_notify.o \ +efi_selftest_reset.o \ efi_selftest_set_virtual_address_map.o \ efi_selftest_textinput.o \ efi_selftest_textinputex.o \ diff --git a/lib/efi_selftest/efi_selftest.c b/lib/efi_selftest/efi_selftest.c index 5b01610eca1..6eec8ae2a7c 100644 --- a/lib/efi_selftest/efi_selftest.c +++ b/lib/efi_selftest/efi_selftest.c @@ -5,6 +5,7 @@ * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de> */ +#include <command.h> #include <efi_selftest.h> #include <vsprintf.h> @@ -309,8 +310,13 @@ efi_status_t EFIAPI efi_selftest(efi_handle_t image_handle, /* Reset system */ 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); + + if (IS_ENABLED(CONFIG_EFI_HAVE_RUNTIME_RESET)) + runtime->reset_system(EFI_RESET_WARM, EFI_NOT_READY, + sizeof(reset_message), reset_message); + else + do_reset(NULL, 0, 0, NULL); + efi_st_printf("\n"); efi_st_error("Reset failed\n"); diff --git a/lib/efi_selftest/efi_selftest_reset.c b/lib/efi_selftest/efi_selftest_reset.c new file mode 100644 index 00000000000..8b6ac24cb15 --- /dev/null +++ b/lib/efi_selftest/efi_selftest_reset.c @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_reset + * + * Copyright (c) 2020 Heinrich Schuchardt <xypron.glpk@gmx.de> + * + * This test checks the following service at boot time or runtime: + * ResetSystem() + */ + +#include <efi_selftest.h> + +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. + * + * @return: EFI_ST_SUCCESS for success + */ +static int execute(void) +{ + u16 reset_data[] = L"Reset by selftest"; + + runtime->reset_system(EFI_RESET_COLD, EFI_SUCCESS, + sizeof(reset_data), reset_data); + efi_st_error("Reset failed.\n"); + return EFI_ST_FAILURE; +} + +EFI_UNIT_TEST(reset) = { + .name = "reset system", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, + .on_request = true, +}; + +EFI_UNIT_TEST(resetrt) = { + .name = "reset system runtime", + .phase = EFI_SETUP_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, + .on_request = true, +}; diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 78576b530fd..d3b22ec3238 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -24,6 +24,7 @@ #include <asm/sections.h> #include <linux/ctype.h> #include <linux/lzo.h> +#include <linux/ioport.h> DECLARE_GLOBAL_DATA_PTR; @@ -242,6 +243,22 @@ int fdtdec_get_pci_bar32(const struct udevice *dev, struct fdt_pci_addr *addr, return 0; } + +int fdtdec_get_pci_bus_range(const void *blob, int node, + struct fdt_resource *res) +{ + const u32 *values; + int len; + + values = fdt_getprop(blob, node, "bus-range", &len); + if (!values || len < sizeof(*values) * 2) + return -EINVAL; + + res->start = fdt32_to_cpu(*values++); + res->end = fdt32_to_cpu(*values); + + return 0; +} #endif uint64_t fdtdec_get_uint64(const void *blob, int node, const char *prop_name, @@ -1032,16 +1049,17 @@ int fdtdec_decode_display_timing(const void *blob, int parent, int index, int fdtdec_setup_mem_size_base(void) { - int ret, mem; - struct fdt_resource res; + int ret; + ofnode mem; + struct resource res; - mem = fdt_path_offset(gd->fdt_blob, "/memory"); - if (mem < 0) { + mem = ofnode_path("/memory"); + if (!ofnode_valid(mem)) { debug("%s: Missing /memory node\n", __func__); return -EINVAL; } - ret = fdt_get_resource(gd->fdt_blob, mem, "reg", 0, &res); + ret = ofnode_read_resource(mem, 0, &res); if (ret != 0) { debug("%s: Unable to decode first memory bank\n", __func__); return -EINVAL; @@ -1057,42 +1075,42 @@ int fdtdec_setup_mem_size_base(void) #if defined(CONFIG_NR_DRAM_BANKS) -static int get_next_memory_node(const void *blob, int mem) +ofnode get_next_memory_node(ofnode mem) { do { - mem = fdt_node_offset_by_prop_value(gd->fdt_blob, mem, - "device_type", "memory", 7); - } while (!fdtdec_get_is_enabled(blob, mem)); + mem = ofnode_by_prop_value(mem, "device_type", "memory", 7); + } while (!ofnode_is_available(mem)); return mem; } int fdtdec_setup_memory_banksize(void) { - int bank, ret, mem, reg = 0; - struct fdt_resource res; + int bank, ret, reg = 0; + struct resource res; + ofnode mem = ofnode_null(); - mem = get_next_memory_node(gd->fdt_blob, -1); - if (mem < 0) { + mem = get_next_memory_node(mem); + if (!ofnode_valid(mem)) { debug("%s: Missing /memory node\n", __func__); return -EINVAL; } for (bank = 0; bank < CONFIG_NR_DRAM_BANKS; bank++) { - ret = fdt_get_resource(gd->fdt_blob, mem, "reg", reg++, &res); - if (ret == -FDT_ERR_NOTFOUND) { + ret = ofnode_read_resource(mem, reg++, &res); + if (ret < 0) { reg = 0; - mem = get_next_memory_node(gd->fdt_blob, mem); - if (mem == -FDT_ERR_NOTFOUND) + mem = get_next_memory_node(mem); + if (ofnode_valid(mem)) break; - ret = fdt_get_resource(gd->fdt_blob, mem, "reg", reg++, &res); - if (ret == -FDT_ERR_NOTFOUND) + ret = ofnode_read_resource(mem, reg++, &res); + if (ret < 0) break; } - if (ret != 0) { + + if (ret != 0) return -EINVAL; - } gd->bd->bi_dram[bank].start = (phys_addr_t)res.start; gd->bd->bi_dram[bank].size = @@ -1106,6 +1124,52 @@ int fdtdec_setup_memory_banksize(void) return 0; } + +int fdtdec_setup_mem_size_base_lowest(void) +{ + int bank, ret, reg = 0; + struct resource res; + unsigned long base; + phys_size_t size; + ofnode mem = ofnode_null(); + + gd->ram_base = (unsigned long)~0; + + mem = get_next_memory_node(mem); + if (!ofnode_valid(mem)) { + debug("%s: Missing /memory node\n", __func__); + return -EINVAL; + } + + for (bank = 0; bank < CONFIG_NR_DRAM_BANKS; bank++) { + ret = ofnode_read_resource(mem, reg++, &res); + if (ret < 0) { + reg = 0; + mem = get_next_memory_node(mem); + if (ofnode_valid(mem)) + break; + + ret = ofnode_read_resource(mem, reg++, &res); + if (ret < 0) + break; + } + + if (ret != 0) + return -EINVAL; + + base = (unsigned long)res.start; + size = (phys_size_t)(res.end - res.start + 1); + + if (gd->ram_base > base && size) { + gd->ram_base = base; + gd->ram_size = size; + debug("%s: Initial DRAM base %lx size %lx\n", + __func__, base, (unsigned long)size); + } + } + + return 0; +} #endif #if CONFIG_IS_ENABLED(MULTI_DTB_FIT) diff --git a/lib/sscanf.c b/lib/sscanf.c index d1e2dc272cc..4c35c035fe1 100644 --- a/lib/sscanf.c +++ b/lib/sscanf.c @@ -555,7 +555,8 @@ literal: if (flags & SUPPRESS) { size_t sum = 0; - if ((n = inr) < width) { + n = inr; + if (n < width) { sum += n; width -= n; inp += n; |