diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/Kconfig | 13 | ||||
| -rw-r--r-- | lib/acpi/base.c | 4 | ||||
| -rw-r--r-- | lib/efi_loader/Kconfig | 8 | ||||
| -rw-r--r-- | lib/efi_loader/efi_bootbin.c | 7 | ||||
| -rw-r--r-- | lib/efi_loader/efi_bootmgr.c | 7 | ||||
| -rw-r--r-- | lib/efi_loader/efi_console.c | 7 | ||||
| -rw-r--r-- | lib/efi_loader/efi_device_path.c | 4 | ||||
| -rw-r--r-- | lib/efi_loader/efi_dt_fixup.c | 3 | ||||
| -rw-r--r-- | lib/efi_loader/efi_hii.c | 3 | ||||
| -rw-r--r-- | lib/efi_loader/efi_image_loader.c | 86 | ||||
| -rw-r--r-- | lib/efi_loader/efi_memory.c | 51 | ||||
| -rw-r--r-- | lib/efi_loader/efi_setup.c | 2 | ||||
| -rw-r--r-- | lib/efi_selftest/efi_selftest_hii.c | 67 | ||||
| -rw-r--r-- | lib/efi_selftest/efi_selftest_hii_data.c | 12 | ||||
| -rw-r--r-- | lib/efi_selftest/efi_selftest_memory.c | 21 | ||||
| -rw-r--r-- | lib/fdtdec.c | 129 | ||||
| -rw-r--r-- | lib/fwu_updates/fwu.c | 33 | ||||
| -rw-r--r-- | lib/gunzip.c | 76 | ||||
| -rw-r--r-- | lib/lmb.c | 20 | ||||
| -rw-r--r-- | lib/smbios.c | 4 | ||||
| -rw-r--r-- | lib/string.c | 31 | ||||
| -rw-r--r-- | lib/uuid.c | 1 | ||||
| -rw-r--r-- | lib/vsprintf.c | 37 |
23 files changed, 489 insertions, 137 deletions
diff --git a/lib/Kconfig b/lib/Kconfig index 4e6a0c6a1b6..cf13ac1bdad 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -72,7 +72,7 @@ config DYNAMIC_CRC_TABLE This can be helpful when reducing the size of the build image config SUPPORTS_FW_LOADER - bool + def_bool y depends on CMDLINE depends on ENV_SUPPORT @@ -285,7 +285,7 @@ config PANIC_HANG config REGEX bool "Enable regular expression support" - default y if NET + default y if NET_LEGACY help If this variable is defined, U-Boot is linked against the SLRE (Super Light Regular Expression) library, which adds @@ -1295,6 +1295,15 @@ config SPL_LMB_ARCH_MEM_MAP memory map. Enable this config in such scenarios which allow architectures and boards to define their own memory map. +config LMB_LIMIT_DMA_BELOW_RAM_TOP + bool + depends on LMB + default y if ARCH_BCM283X + help + Some architectures can not DMA above ram_top boundary, + which is after 4 GiB or 32-bit boundary too. Limit the + available memory to memory below ram_top boundary. + config PHANDLE_CHECK_SEQ bool "Enable phandle check while getting sequence number" help diff --git a/lib/acpi/base.c b/lib/acpi/base.c index 5c755b14c16..01ebad8994a 100644 --- a/lib/acpi/base.c +++ b/lib/acpi/base.c @@ -44,7 +44,7 @@ static void acpi_write_rsdt(struct acpi_rsdt *rsdt) /* Fill out header fields */ acpi_fill_header(header, "RSDT"); - header->length = sizeof(struct acpi_rsdt); + header->length = sizeof(struct acpi_table_header); header->revision = 1; /* Entries are filled in later, we come with an empty set */ @@ -59,7 +59,7 @@ static void acpi_write_xsdt(struct acpi_xsdt *xsdt) /* Fill out header fields */ acpi_fill_header(header, "XSDT"); - header->length = sizeof(struct acpi_xsdt); + header->length = sizeof(struct acpi_table_header); header->revision = 1; /* Entries are filled in later, we come with an empty set */ diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index bae98e07d23..4cb13ae7c8a 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -102,8 +102,7 @@ config EFI_SET_TIME can be used by an EFI application to adjust the real time clock. config EFI_HAVE_RUNTIME_RESET - # bool "Reset runtime service is available" - bool + bool "Reset runtime service" default y depends on ARCH_BCM283X || FSL_LAYERSCAPE || PSCI_RESET || \ SANDBOX || SYSRESET_SBI || SYSRESET_X86 @@ -517,7 +516,7 @@ config EFI_RISCV_BOOT_PROTOCOL config EFI_IP4_CONFIG2_PROTOCOL bool "EFI_IP4_CONFIG2_PROTOCOL support" default y if ARCH_QEMU || SANDBOX - depends on NET || NET_LWIP + depends on NET help Provides an implementation of the EFI_IP4_CONFIG2_PROTOCOL, this protocol can be used to set and get the current ip address and @@ -610,7 +609,8 @@ config EFI_BOOTMGR config EFI_HTTP_BOOT bool "EFI HTTP Boot support" - depends on NET || NET_LWIP + depends on NET + depends on CMDLINE select CMD_NET select CMD_DHCP select CMD_DNS diff --git a/lib/efi_loader/efi_bootbin.c b/lib/efi_loader/efi_bootbin.c index b394f0d60ce..12db8f517c7 100644 --- a/lib/efi_loader/efi_bootbin.c +++ b/lib/efi_loader/efi_bootbin.c @@ -224,11 +224,8 @@ static efi_status_t efi_binary_run_dp(void *image, size_t size, void *fdt, /* Initialize EFI drivers */ ret = efi_init_obj_list(); - if (ret != EFI_SUCCESS) { - log_err("Error: Cannot initialize UEFI sub-system, r = %lu\n", - ret & ~EFI_ERROR_MASK); - return -1; - } + if (ret != EFI_SUCCESS) + return ret; ret = efi_install_fdt(fdt); if (ret != EFI_SUCCESS) diff --git a/lib/efi_loader/efi_bootmgr.c b/lib/efi_loader/efi_bootmgr.c index a687f4d8e85..8c9a9b5eb56 100644 --- a/lib/efi_loader/efi_bootmgr.c +++ b/lib/efi_loader/efi_bootmgr.c @@ -1310,11 +1310,8 @@ efi_status_t efi_bootmgr_run(void *fdt) /* Initialize EFI drivers */ ret = efi_init_obj_list(); - if (ret != EFI_SUCCESS) { - log_err("Error: Cannot initialize UEFI sub-system, r = %lu\n", - ret & ~EFI_ERROR_MASK); - return CMD_RET_FAILURE; - } + if (ret != EFI_SUCCESS) + return ret; ret = efi_bootmgr_load(&handle, &load_options); if (ret != EFI_SUCCESS) { diff --git a/lib/efi_loader/efi_console.c b/lib/efi_loader/efi_console.c index a798d5604a3..8d076058280 100644 --- a/lib/efi_loader/efi_console.c +++ b/lib/efi_loader/efi_console.c @@ -9,6 +9,7 @@ #include <ansi.h> #include <charset.h> +#include <console.h> #include <efi_device_path.h> #include <malloc.h> #include <time.h> @@ -299,8 +300,7 @@ static int query_console_serial(int *rows, int *cols) int n[2]; /* Empty input buffer */ - while (tstc()) - getchar(); + console_flush_stdin(); /* * Not all terminals understand CSI [18t for querying the console size. @@ -960,8 +960,7 @@ static void efi_cin_check(void) */ static void efi_cin_empty_buffer(void) { - while (tstc()) - getchar(); + console_flush_stdin(); key_available = false; } diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c index b3fb20b2501..9efb158f5dd 100644 --- a/lib/efi_loader/efi_device_path.c +++ b/lib/efi_loader/efi_device_path.c @@ -955,8 +955,8 @@ struct efi_device_path *efi_dp_from_http(const char *server, struct udevice *dev efi_uintn_t uridp_len; char *pos; char tmp[128]; - struct efi_ipv4_address ip; - struct efi_ipv4_address mask; + struct efi_ipv4_address ip = { .ip_addr = { 0, 0, 0, 0 } }; + struct efi_ipv4_address mask = { .ip_addr = { 0, 0, 0, 0 } }; if ((server && strlen("http://") + strlen(server) + 1 > sizeof(tmp)) || (!server && IS_ENABLED(CONFIG_NET_LWIP))) diff --git a/lib/efi_loader/efi_dt_fixup.c b/lib/efi_loader/efi_dt_fixup.c index 544e1aa9808..333711b9957 100644 --- a/lib/efi_loader/efi_dt_fixup.c +++ b/lib/efi_loader/efi_dt_fixup.c @@ -123,8 +123,7 @@ void efi_carve_out_dt_rsv(void *fdt) fdtdec_get_is_enabled(fdt, subnode)) { bool nomap; - nomap = !!fdt_getprop(fdt, subnode, "no-map", - NULL); + nomap = fdtdec_get_bool(fdt, subnode, "no-map"); efi_reserve_memory(fdt_addr, fdt_size, nomap); } subnode = fdt_next_subnode(fdt, subnode); diff --git a/lib/efi_loader/efi_hii.c b/lib/efi_loader/efi_hii.c index 330d7c5830b..7bf51ad43d1 100644 --- a/lib/efi_loader/efi_hii.c +++ b/lib/efi_loader/efi_hii.c @@ -324,7 +324,8 @@ add_keyboard_package(struct efi_hii_packagelist *hii, list_add_tail(&layout_data->link_sys, &efi_keyboard_layout_list); - layout += layout_length; + layout = (struct efi_hii_keyboard_layout *) + ((uintptr_t)layout + layout_length); } list_add_tail(&package_data->link, &hii->keyboard_packages); diff --git a/lib/efi_loader/efi_image_loader.c b/lib/efi_loader/efi_image_loader.c index d002eb0c744..f9a2d2df405 100644 --- a/lib/efi_loader/efi_image_loader.c +++ b/lib/efi_loader/efi_image_loader.c @@ -108,11 +108,13 @@ void efi_print_image_infos(void *pc) * @rel_size: size of the relocation table in bytes * @efi_reloc: actual load address of the image * @pref_address: preferred load address of the image + * @virt_size: virtual image size as provided in the PE-COFF header * Return: status code */ static efi_status_t efi_loader_relocate(const IMAGE_BASE_RELOCATION *rel, - unsigned long rel_size, void *efi_reloc, - unsigned long pref_address) + unsigned long rel_size, void *efi_reloc, + unsigned long pref_address, + unsigned long virt_size) { unsigned long delta = (unsigned long)efi_reloc - pref_address; const IMAGE_BASE_RELOCATION *end; @@ -122,34 +124,95 @@ static efi_status_t efi_loader_relocate(const IMAGE_BASE_RELOCATION *rel, return EFI_SUCCESS; end = (const IMAGE_BASE_RELOCATION *)((const char *)rel + rel_size); - while (rel + 1 < end && rel->SizeOfBlock) { + while (rel + 1 < end) { const uint16_t *relocs = (const uint16_t *)(rel + 1); + + /* Each block must start on a 32-bit boundary */ + if (!IS_ALIGNED((uintptr_t)rel, sizeof(uint32_t))) { + log_debug("Relocation block not 32-bit aligned\n"); + return EFI_LOAD_ERROR; + } + /* Relocation block cannot be shorter than its header */ + if (rel->SizeOfBlock < sizeof(*rel)) { + log_debug("Relocation block too small: %u\n", + rel->SizeOfBlock); + return EFI_LOAD_ERROR; + } + /* All relocation entries must be inside the .reloc section */ + if ((const char *)rel + rel->SizeOfBlock > (const char *)end) { + log_debug("Relocation block exceeds relocation data\n"); + return EFI_LOAD_ERROR; + } + /* + * Relocations must be within the virtual address range. + * This also ensures that there is no overflow in the + * entry_offset check below. + */ + if (rel->VirtualAddress > virt_size) { + log_debug("relocation address out of bounds\n"); + return EFI_LOAD_ERROR; + } + i = (rel->SizeOfBlock - sizeof(*rel)) / sizeof(uint16_t); while (i--) { - uint32_t offset = (uint32_t)(*relocs & 0xfff) + - rel->VirtualAddress; + uint32_t entry_offset = *relocs & 0xfff; + unsigned long offset; int type = *relocs >> EFI_PAGE_SHIFT; - uint64_t *x64 = efi_reloc + offset; - uint32_t *x32 = efi_reloc + offset; - uint16_t *x16 = efi_reloc + offset; + uint64_t *x64; + uint32_t *x32; + uint16_t *x16; + + /* + * Relocation address must be within virtual address + * range. + */ + if (entry_offset > virt_size - rel->VirtualAddress) { + log_debug("relocation address out of bounds\n"); + return EFI_LOAD_ERROR; + } + + offset = rel->VirtualAddress + entry_offset; + x64 = efi_reloc + offset; + x32 = efi_reloc + offset; + x16 = efi_reloc + offset; switch (type) { case IMAGE_REL_BASED_ABSOLUTE: break; case IMAGE_REL_BASED_HIGH: + if (sizeof(uint16_t) > virt_size - offset) { + log_debug("relocation address out of bounds\n"); + return EFI_LOAD_ERROR; + } *x16 += ((uint32_t)delta) >> 16; break; case IMAGE_REL_BASED_LOW: + if (sizeof(uint16_t) > virt_size - offset) { + log_debug("relocation address out of bounds\n"); + return EFI_LOAD_ERROR; + } *x16 += (uint16_t)delta; break; case IMAGE_REL_BASED_HIGHLOW: + if (sizeof(uint32_t) > virt_size - offset) { + log_debug("relocation address out of bounds\n"); + return EFI_LOAD_ERROR; + } *x32 += (uint32_t)delta; break; case IMAGE_REL_BASED_DIR64: + if (sizeof(uint64_t) > virt_size - offset) { + log_debug("relocation address out of bounds\n"); + return EFI_LOAD_ERROR; + } *x64 += (uint64_t)delta; break; #ifdef __riscv case IMAGE_REL_BASED_RISCV_HI20: + if (sizeof(uint32_t) > virt_size - offset) { + log_debug("relocation address out of bounds\n"); + return EFI_LOAD_ERROR; + } *x32 = ((*x32 & 0xfffff000) + (uint32_t)delta) | (*x32 & 0x00000fff); break; @@ -163,7 +226,7 @@ static efi_status_t efi_loader_relocate(const IMAGE_BASE_RELOCATION *rel, break; #endif default: - log_err("Unknown Relocation off %x type %x\n", + log_err("Unknown Relocation off %lx type %x\n", offset, type); return EFI_LOAD_ERROR; } @@ -970,8 +1033,9 @@ efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle, /* Run through relocations */ if (efi_loader_relocate(rel, rel_size, efi_reloc, - (unsigned long)image_base) != EFI_SUCCESS) { - efi_free_pages((uintptr_t) efi_reloc, + (unsigned long)image_base, + virt_size) != EFI_SUCCESS) { + efi_free_pages((uintptr_t)efi_reloc, (virt_size + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT); ret = EFI_LOAD_ERROR; goto err; diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index b77c2f980cc..2feb29f0a2c 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -128,44 +128,29 @@ static uint64_t desc_get_end(struct efi_mem_desc *desc) */ static void efi_mem_sort(void) { - struct efi_mem_list *lmem; - struct efi_mem_list *prevmem = NULL; - bool merge_again = true; + struct efi_mem_list *curmem, *nextmem = NULL; list_sort(NULL, &efi_mem, efi_mem_cmp); /* Now merge entries that can be merged */ - while (merge_again) { - merge_again = false; - list_for_each_entry(lmem, &efi_mem, link) { - struct efi_mem_desc *prev; - struct efi_mem_desc *cur; - uint64_t pages; - - if (!prevmem) { - prevmem = lmem; - continue; - } - - cur = &lmem->desc; - prev = &prevmem->desc; + list_for_each_entry_safe(curmem, nextmem, &efi_mem, link) { + struct efi_mem_desc *cur; + struct efi_mem_desc *next; - if ((desc_get_end(cur) == prev->physical_start) && - (prev->type == cur->type) && - (prev->attribute == cur->attribute)) { - /* There is an existing map before, reuse it */ - pages = cur->num_pages; - prev->num_pages += pages; - prev->physical_start -= pages << EFI_PAGE_SHIFT; - prev->virtual_start -= pages << EFI_PAGE_SHIFT; - list_del(&lmem->link); - free(lmem); + /* Exit when we've got nothing to compare with */ + if (&nextmem->link == &efi_mem) + break; - merge_again = true; - break; - } + cur = &curmem->desc; + next = &nextmem->desc; - prevmem = lmem; + if ((cur->physical_start == desc_get_end(next)) && + (cur->type == next->type) && + (cur->attribute == next->attribute)) { + /* There is another similar map coming up, reuse it */ + next->num_pages += cur->num_pages; + list_del(&curmem->link); + free(curmem); } } } @@ -510,7 +495,9 @@ efi_status_t efi_allocate_pages(enum efi_allocate_type type, /* Map would overlap, bail out */ lmb_free(addr, (u64)pages << EFI_PAGE_SHIFT, flags); unmap_sysmem((void *)(uintptr_t)efi_addr); - return EFI_OUT_OF_RESOURCES; + if (type == EFI_ALLOCATE_ADDRESS) + return EFI_NOT_FOUND; + return EFI_OUT_OF_RESOURCES; } *memory = efi_addr; diff --git a/lib/efi_loader/efi_setup.c b/lib/efi_loader/efi_setup.c index f06cf49e443..f302bb62ab9 100644 --- a/lib/efi_loader/efi_setup.c +++ b/lib/efi_loader/efi_setup.c @@ -392,5 +392,7 @@ efi_status_t efi_init_obj_list(void) ret = efi_start_obj_list(); out: efi_obj_list_initialized = ret; + if (ret != EFI_SUCCESS) + log_err("Cannot initialize UEFI sub-system\n"); return ret; } diff --git a/lib/efi_selftest/efi_selftest_hii.c b/lib/efi_selftest/efi_selftest_hii.c index 228dc296950..fdbb08fb417 100644 --- a/lib/efi_selftest/efi_selftest_hii.c +++ b/lib/efi_selftest/efi_selftest_hii.c @@ -452,8 +452,7 @@ out: * test_hii_database_get_keyboard_layout() - test retrieval of keyboard layout * * This test adds two package lists, each of which has two keyboard layouts - * and then tries to get a handle to keyboard layout with a specific guid - * and the current one. + * and then tries to get a handle to every keyboard layout and the current one. * * @Return: status code */ @@ -463,7 +462,11 @@ static int test_hii_database_get_keyboard_layout(void) struct efi_hii_keyboard_layout *kb_layout; u16 kb_layout_size; efi_status_t ret; - int result = EFI_ST_FAILURE; + int result = EFI_ST_FAILURE, i; + static efi_guid_t *const kb_layout_guids[] = { + &kb_layout_guid11, &kb_layout_guid12, + &kb_layout_guid21, &kb_layout_guid22 + }; PRINT_TESTNAME; ret = hii_database_protocol->new_package_list(hii_database_protocol, @@ -484,33 +487,37 @@ static int test_hii_database_get_keyboard_layout(void) goto out; } - /* specific keyboard_layout(guid11) */ - kb_layout = NULL; - kb_layout_size = 0; - ret = hii_database_protocol->get_keyboard_layout(hii_database_protocol, - &kb_layout_guid11, &kb_layout_size, kb_layout); - if (ret != EFI_BUFFER_TOO_SMALL) { - efi_st_error("get_keyboard_layout returned %u\n", - (unsigned int)ret); - goto out; - } - ret = boottime->allocate_pool(EFI_LOADER_DATA, kb_layout_size, - (void **)&kb_layout); - if (ret != EFI_SUCCESS) { - efi_st_error("AllocatePool failed\n"); - goto out; - } - ret = hii_database_protocol->get_keyboard_layout(hii_database_protocol, - &kb_layout_guid11, &kb_layout_size, kb_layout); - if (ret != EFI_SUCCESS) { - efi_st_error("get_keyboard_layout returned %u\n", - (unsigned int)ret); - goto out; - } - ret = boottime->free_pool(kb_layout); - if (ret != EFI_SUCCESS) { - efi_st_error("FreePool failed\n"); - goto out; + /* Verify all keyboard layouts */ + for (i = 0; i < ARRAY_SIZE(kb_layout_guids); i++) { + efi_guid_t *kb_layout_guid = kb_layout_guids[i]; + + kb_layout = NULL; + kb_layout_size = 0; + ret = hii_database_protocol->get_keyboard_layout(hii_database_protocol, + kb_layout_guid, &kb_layout_size, kb_layout); + if (ret != EFI_BUFFER_TOO_SMALL) { + efi_st_error("get_keyboard_layout returned %u\n", + (unsigned int)ret); + goto out; + } + ret = boottime->allocate_pool(EFI_LOADER_DATA, kb_layout_size, + (void **)&kb_layout); + if (ret != EFI_SUCCESS) { + efi_st_error("AllocatePool failed\n"); + goto out; + } + ret = hii_database_protocol->get_keyboard_layout(hii_database_protocol, + kb_layout_guid, &kb_layout_size, kb_layout); + if (ret != EFI_SUCCESS) { + efi_st_error("get_keyboard_layout returned %u\n", + (unsigned int)ret); + goto out; + } + ret = boottime->free_pool(kb_layout); + if (ret != EFI_SUCCESS) { + efi_st_error("FreePool failed\n"); + goto out; + } } /* current */ diff --git a/lib/efi_selftest/efi_selftest_hii_data.c b/lib/efi_selftest/efi_selftest_hii_data.c index 5fc890112b4..2d29bb045d3 100644 --- a/lib/efi_selftest/efi_selftest_hii_data.c +++ b/lib/efi_selftest/efi_selftest_hii_data.c @@ -428,6 +428,18 @@ static efi_guid_t kb_layout_guid11 = EFI_GUID(0x8d40e495, 0xe2aa, 0x4c6f, 0x89, 0x70, 0x68, 0x85, 0x09, 0xee, 0xc7, 0xd2); +static efi_guid_t kb_layout_guid12 = + EFI_GUID(0x2ae60b3e, 0xb9d6, 0x49d8, + 0x9a, 0x16, 0xc2, 0x48, 0xf1, 0xeb, 0xa8, 0xdb); + +static efi_guid_t kb_layout_guid21 = + EFI_GUID(0xe0f56a1f, 0xdf6b, 0x4a7e, + 0xa3, 0x9a, 0xe7, 0xa5, 0x19, 0x15, 0x45, 0xd6); + +static efi_guid_t kb_layout_guid22 = + EFI_GUID(0x47be6ac9, 0x54cc, 0x46f9, + 0xa2, 0x62, 0xd5, 0x3b, 0x25, 0x6a, 0x0c, 0x34); + static efi_guid_t package_guid = EFI_GUID(0x0387c95a, 0xd703, 0x2346, 0xb2, 0xab, 0xd0, 0xc7, 0xdd, 0x90, 0x44, 0xf8); diff --git a/lib/efi_selftest/efi_selftest_memory.c b/lib/efi_selftest/efi_selftest_memory.c index 4d32a280061..7320964c129 100644 --- a/lib/efi_selftest/efi_selftest_memory.c +++ b/lib/efi_selftest/efi_selftest_memory.c @@ -60,7 +60,7 @@ static int find_in_memory_map(efi_uintn_t map_size, u64 addr, int memory_type) { efi_uintn_t i; - bool found = false; + struct efi_mem_desc *match = NULL; for (i = 0; map_size; ++i, map_size -= desc_size) { struct efi_mem_desc *entry = &memory_map[i]; @@ -72,24 +72,23 @@ static int find_in_memory_map(efi_uintn_t map_size, if (addr >= entry->physical_start && addr < entry->physical_start + - (entry->num_pages << EFI_PAGE_SHIFT)) { - if (found) { + (entry->num_pages << EFI_PAGE_SHIFT)) { + if (match) { efi_st_error("Duplicate memory map entry\n"); return EFI_ST_FAILURE; } - found = true; - if (memory_type != entry->type) { - efi_st_error - ("Wrong memory type %d, expected %d\n", - entry->type, memory_type); - return EFI_ST_FAILURE; - } + match = entry; } } - if (!found) { + if (!match) { efi_st_error("Missing memory map entry\n"); return EFI_ST_FAILURE; } + if (memory_type != match->type) { + efi_st_error("Wrong memory type %d, expected %d\n", match->type, + memory_type); + return EFI_ST_FAILURE; + } return EFI_ST_SUCCESS; } diff --git a/lib/fdtdec.c b/lib/fdtdec.c index fb3375ea157..c67b6e8c133 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -714,6 +714,24 @@ int fdtdec_get_int_array(const void *blob, int node, const char *prop_name, return err; } +int fdtdec_get_long_array(const void *blob, int node, const char *prop_name, + u64 *array, int count) +{ + const u64 *cell; + int err = 0; + + debug("%s: %s\n", __func__, prop_name); + cell = get_prop_check_min_len(blob, node, prop_name, + sizeof(u64) * count, &err); + if (!err) { + int i; + + for (i = 0; i < count; i++) + array[i] = fdt64_to_cpu(cell[i]); + } + return err; +} + int fdtdec_get_int_array_count(const void *blob, int node, const char *prop_name, u32 *array, int count) { @@ -1691,6 +1709,114 @@ void fdtdec_setup_embed(void) gd->fdt_src = FDTSRC_EMBED; } +static int fdtdec_match_dto_compatible(const void *base, const void *dto) +{ + const char *compat_base; + const char *compat_dto; + int len; + + compat_base = (const char *)fdt_getprop(base, 0, "compatible", &len); + if (!compat_base || len <= 0) + return -ENOENT; + + compat_dto = (const char *)fdt_getprop(dto, 0, "compatible", &len); + if (!compat_dto || len <= 0) + return -ENOENT; + + if (strcmp(compat_base, compat_dto)) + return -EPERM; + + return 0; +} + +static inline int fdtdec_ret_to_errno(int ret) +{ + switch (ret) { + case -FDT_ERR_NOTFOUND: + return -ENOENT; + case -FDT_ERR_EXISTS: + return -EEXIST; + case -FDT_ERR_NOSPACE: + case -FDT_ERR_NOPHANDLES: + return -ENOSPC; + default: + return -EINVAL; + } +} + +static int fdtdec_apply_dto_blob(void **blob, __maybe_unused int size) +{ + int ret; + + ret = fdt_check_header(*blob); + if (ret) + return fdtdec_ret_to_errno(ret); + + ret = fdtdec_match_dto_compatible(gd->fdt_blob, *blob); + if (ret) + return ret; + + ret = fdt_overlay_apply_verbose((void *)gd->fdt_blob, *blob); + if (ret) + return fdtdec_ret_to_errno(ret); + + return 0; +} + +static int fdtdec_apply_bloblist_dtos(void) +{ + int ret; + struct fdt_header *live_fdt; + int blob_size; + size_t padded_size, max_size; + + if (!CONFIG_IS_ENABLED(OF_LIBFDT_OVERLAY) || + !CONFIG_IS_ENABLED(BLOBLIST)) + return 0; + + /* Get the total space reserved for FDT in blob */ + live_fdt = bloblist_get_blob(BLOBLISTT_CONTROL_FDT, &blob_size); + if (live_fdt != gd->fdt_blob) + return -ENOENT; + + ret = fdt_check_full(live_fdt, blob_size); + if (ret) + return fdtdec_ret_to_errno(ret); + + /* Calculate the allowed padded size */ + padded_size = fdt_totalsize(live_fdt) + CONFIG_SYS_FDT_PAD; + max_size = bloblist_get_total_size() - bloblist_get_size() + blob_size; + if (padded_size > max_size) + padded_size = max_size; + + /* Resize if the current space is not sufficient */ + if (blob_size < padded_size) { + ret = bloblist_resize(BLOBLISTT_CONTROL_FDT, padded_size); + if (ret) + return ret; + + blob_size = padded_size; + ret = fdt_open_into(live_fdt, live_fdt, padded_size); + if (ret) + return fdtdec_ret_to_errno(ret); + } + + ret = bloblist_apply_blobs(BLOBLISTT_FDT_OVERLAY, fdtdec_apply_dto_blob); + if (ret) + return ret; + + ret = fdt_check_full(live_fdt, blob_size); + if (ret) + return fdtdec_ret_to_errno(ret); + + ret = fdt_pack(live_fdt); + if (ret) + return fdtdec_ret_to_errno(ret); + + /* Shrink the blob to the actual FDT size */ + return bloblist_resize(BLOBLISTT_CONTROL_FDT, fdt_totalsize(live_fdt)); +} + int fdtdec_setup(void) { int ret = -ENOENT; @@ -1712,6 +1838,9 @@ int fdtdec_setup(void) gd->fdt_src = FDTSRC_BLOBLIST; log_debug("Devicetree is in bloblist at %p\n", gd->fdt_blob); + ret = fdtdec_apply_bloblist_dtos(); + if (ret) + return ret; goto setup_fdt; } else { log_debug("No FDT found in bloblist\n"); diff --git a/lib/fwu_updates/fwu.c b/lib/fwu_updates/fwu.c index e82600a29a4..2b11e5da061 100644 --- a/lib/fwu_updates/fwu.c +++ b/lib/fwu_updates/fwu.c @@ -244,6 +244,39 @@ int fwu_sync_mdata(struct fwu_mdata *mdata, int part) } /** + * fwu_mdata_get_image_guid() - Get image GUID for a type and bank + * @image_guid: Pointer to be filled with the found image GUID + * @image_type_guid: Pointer to the image type GUID to search for + * @bank_index: Index of the bank + * + * Return: 0 if OK, -ve on error + */ +int fwu_mdata_get_image_guid(efi_guid_t *image_guid, + const efi_guid_t *image_type_guid, u32 bank_index) +{ + struct fwu_data *data = &g_fwu_data; + struct fwu_image_entry *image; + int i; + + if (bank_index >= data->num_banks) + return -EINVAL; + + for (i = 0; i < data->num_images; i++) { + image = &data->fwu_images[i]; + + if (!guidcmp(image_type_guid, &image->image_type_guid)) { + struct fwu_image_bank_info *bank; + + bank = &image->img_bank_info[bank_index]; + guidcpy(image_guid, &bank->image_guid); + return 0; + } + } + + return -ENOENT; +} + +/** * fwu_mdata_copies_allocate() - Allocate memory for metadata * @mdata_size: Size of the metadata structure * diff --git a/lib/gunzip.c b/lib/gunzip.c index 76f3397fced..20cc14f9688 100644 --- a/lib/gunzip.c +++ b/lib/gunzip.c @@ -8,8 +8,10 @@ #include <command.h> #include <console.h> #include <div64.h> +#include <env.h> #include <gzip.h> #include <image.h> +#include <linux/sizes.h> #include <malloc.h> #include <memalign.h> #include <u-boot/crc.h> @@ -119,7 +121,7 @@ void gzwrite_progress_finish(int returnval, int gzwrite(unsigned char *src, size_t len, struct blk_desc *dev, size_t szwritebuf, off_t startoffs, size_t szexpected) { - int i, flags; + int flags; z_stream s; int r = 0; unsigned char *writebuf; @@ -127,13 +129,23 @@ int gzwrite(unsigned char *src, size_t len, struct blk_desc *dev, ulong totalfilled = 0; lbaint_t blksperbuf, outblock; u32 expected_crc; - size_t payload_size; + size_t i, payload_size; + unsigned long blocks_written; + lbaint_t writeblocks; + int numfilled = 0; int iteration = 0; - - if (len > 0xffffffff) { - log_err("Input size over 4 GiB in size not supported\n"); - return -1; - } + /* + * Allow runtime configuration of decompression chunk on + * sandbox to better cover the chunked decompression + * functionality without having to use > 4 GiB files. + */ + const ulong minchunk = 0x400; + const ulong maxchunk = SZ_4G - minchunk; + const ulong chunk = + CONFIG_IS_ENABLED(SANDBOX, + (clamp(env_get_ulong("gzwrite_chunk", 10, maxchunk), + minchunk, maxchunk)), + (maxchunk)); if (!szwritebuf || (szwritebuf % dev->blksz) || @@ -175,7 +187,7 @@ int gzwrite(unsigned char *src, size_t len, struct blk_desc *dev, return -1; } - payload_size = len - i - 8; + payload_size = len - i; memcpy(&expected_crc, src + len - 8, sizeof(expected_crc)); expected_crc = le32_to_cpu(expected_crc); @@ -205,35 +217,44 @@ int gzwrite(unsigned char *src, size_t len, struct blk_desc *dev, return -1; } - s.next_in = src + i; - s.avail_in = payload_size+8; + src += i; + s.avail_in = 0; writebuf = (unsigned char *)malloc_cache_aligned(szwritebuf); /* decompress until deflate stream ends or end of file */ do { if (s.avail_in == 0) { - printf("%s: weird termination with result %d\n", - __func__, r); - break; + if (payload_size == 0) { + printf("%s: weird termination with result %d\n", + __func__, r); + break; + } + + s.next_in = src; + s.avail_in = (payload_size > chunk) ? chunk : payload_size; + src += s.avail_in; + payload_size -= s.avail_in; } /* run inflate() on input until output buffer not full */ do { - unsigned long blocks_written; - int numfilled; - lbaint_t writeblocks; - - s.avail_out = szwritebuf; - s.next_out = writebuf; + if (numfilled) { + s.avail_out = szwritebuf - numfilled; + s.next_out = writebuf + numfilled; + } else { + s.avail_out = szwritebuf; + s.next_out = writebuf; + } r = inflate(&s, Z_SYNC_FLUSH); if ((r != Z_OK) && (r != Z_STREAM_END)) { printf("Error: inflate() returned %d\n", r); goto out; } + crc = crc32(crc, writebuf + numfilled, + szwritebuf - s.avail_out - numfilled); + totalfilled += szwritebuf - s.avail_out - numfilled; numfilled = szwritebuf - s.avail_out; - crc = crc32(crc, writebuf, numfilled); - totalfilled += numfilled; if (numfilled < szwritebuf) { writeblocks = (numfilled+dev->blksz-1) / dev->blksz; @@ -241,14 +262,17 @@ int gzwrite(unsigned char *src, size_t len, struct blk_desc *dev, dev->blksz-(numfilled%dev->blksz)); } else { writeblocks = blksperbuf; + numfilled = 0; } gzwrite_progress(iteration++, totalfilled, szexpected); - blocks_written = blk_dwrite(dev, outblock, + if (!numfilled) { + blocks_written = blk_dwrite(dev, outblock, writeblocks, writebuf); - outblock += blocks_written; + outblock += blocks_written; + } if (ctrlc()) { puts("abort\n"); goto out; @@ -258,6 +282,12 @@ int gzwrite(unsigned char *src, size_t len, struct blk_desc *dev, /* done when inflate() says it's done */ } while (r != Z_STREAM_END); + if (numfilled) { + blocks_written = blk_dwrite(dev, outblock, + writeblocks, writebuf); + outblock += blocks_written; + } + if ((szexpected != totalfilled) || (crc != expected_crc)) r = -1; diff --git a/lib/lmb.c b/lib/lmb.c index 8f12c6ad8e5..275d105c5aa 100644 --- a/lib/lmb.c +++ b/lib/lmb.c @@ -611,6 +611,7 @@ static __maybe_unused void lmb_reserve_common_spl(void) static void lmb_add_memory(void) { int i; + phys_addr_t bank_end; phys_size_t size; u64 ram_top = gd->ram_top; struct bd_info *bd = gd->bd; @@ -625,8 +626,25 @@ static void lmb_add_memory(void) for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { size = bd->bi_dram[i].size; - if (size) + if (size) { lmb_add(bd->bi_dram[i].start, size); + if (!IS_ENABLED(CONFIG_LMB_LIMIT_DMA_BELOW_RAM_TOP)) + continue; + + bank_end = bd->bi_dram[i].start + size; + + /* + * Reserve memory above ram_top as + * no-overwrite so that it cannot be + * allocated + */ + if (bd->bi_dram[i].start >= ram_top) + lmb_reserve(bd->bi_dram[i].start, size, + LMB_NOOVERWRITE); + else if (bank_end > ram_top) + lmb_reserve(ram_top, bank_end - ram_top, + LMB_NOOVERWRITE); + } } } diff --git a/lib/smbios.c b/lib/smbios.c index d5f18c8bd69..afde6401ae5 100644 --- a/lib/smbios.c +++ b/lib/smbios.c @@ -292,7 +292,7 @@ static int smbios_get_val_si(struct smbios_ctx * __maybe_unused ctx, /* If the node is still missing, try with the mapping values */ nprop = convert_sysinfo_to_dt(ctx->subnode_name, prop); - if (!ofnode_read_u32(ofnode_root(), nprop->dt_str, &val)) + if (nprop && !ofnode_read_u32(ofnode_root(), nprop->dt_str, &val)) return val; #endif return val_def; @@ -679,7 +679,7 @@ static int smbios_write_type3(ulong *current, int *handle, t->serial_number = smbios_add_prop_si(ctx, "serial", SYSID_SM_ENCLOSURE_SERIAL, NULL); t->asset_tag_number = smbios_add_prop_si(ctx, "asset-tag", - SYSID_SM_BASEBOARD_ASSET_TAG, + SYSID_SM_ENCLOSURE_ASSET_TAG, NULL); t->oem_defined = smbios_get_val_si(ctx, "oem-defined", SYSID_SM_ENCLOSURE_OEM, 0); diff --git a/lib/string.c b/lib/string.c index d56f88d4a84..302efe048b0 100644 --- a/lib/string.c +++ b/lib/string.c @@ -379,6 +379,37 @@ char * strndup(const char *s, size_t n) return new; } + +/** + * strdup_const - conditionally duplicate an existing const string + * @s: the string to duplicate + * + * Note: Strings allocated by kstrdup_const should be freed by kfree_const and + * must not be passed to krealloc(). + * + * Return: source string if it is in .rodata section otherwise + * fallback to kstrdup. + */ +const char *strdup_const(const char *s) +{ + if (is_kernel_rodata((unsigned long)s)) + return s; + + return strdup(s); +} + +/** + * kfree_const - conditionally free memory + * @x: pointer to the memory + * + * Function calls kfree only if @x is not in .rodata section. + */ +void kfree_const(const void *x) +{ + if (!is_kernel_rodata((unsigned long)x)) + free((void *)x); +} + #endif #ifndef __HAVE_ARCH_STRSPN diff --git a/lib/uuid.c b/lib/uuid.c index 3a666d0430d..d7c164ea06b 100644 --- a/lib/uuid.c +++ b/lib/uuid.c @@ -86,6 +86,7 @@ static const struct { {"swap", NULL, PARTITION_LINUX_SWAP_GUID}, {"lvm", NULL, PARTITION_LINUX_LVM_GUID}, {"u-boot-env", NULL, PARTITION_U_BOOT_ENVIRONMENT}, + {"xbootldr", NULL, PARTITION_XBOOTLDR}, {"cros-kern", NULL, PARTITION_CROS_KERNEL}, {"cros-root", NULL, PARTITION_CROS_ROOT}, {"cros-fw", NULL, PARTITION_CROS_FIRMWARE}, diff --git a/lib/vsprintf.c b/lib/vsprintf.c index c7340a047b2..49dc9c38c65 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -26,6 +26,11 @@ #include <linux/types.h> #include <linux/string.h> +/* For %pOF */ +#if CONFIG_IS_ENABLED(OF_CONTROL) +#include <dm/ofnode.h> +#endif + /* we use this so that we can do without the ctype library */ #define is_digit(c) ((c) >= '0' && (c) <= '9') @@ -438,6 +443,30 @@ static char *uuid_string(char *buf, char *end, u8 *addr, int field_width, } #endif +#if CONFIG_IS_ENABLED(OF_CONTROL) && !defined(API_BUILD) +static char *ofnode_string(char *buf, char *end, ofnode *dp, int field_width, + int precision, int flags) +{ +#define NP_PATH_MAX 64 + char str[NP_PATH_MAX] = { 0 }; + const char *err = "..."; + + /* If dp == NULL output the string '<NULL>' */ + if (!dp || !ofnode_valid(*dp)) + return string(buf, end, NULL, field_width, precision, flags); + + /* Get the path and indicate if it got cut off */ + if (ofnode_get_path(*dp, str, NP_PATH_MAX)) { + str[NP_PATH_MAX - 1] = '\0'; + char *p = str + min((NP_PATH_MAX - 2) - strlen(err), strlen(str)); + memcpy(p, err, strlen(err) + 1); + } + + return string(buf, end, str, field_width, precision, flags); +#undef NP_PATH_MAX +} +#endif + /* * Show a '%p' thing. A kernel extension is that the '%p' is followed * by an extra set of alphanumeric characters that are extended format @@ -474,6 +503,14 @@ static char *pointer(const char *fmt, char *buf, char *end, void *ptr, return device_path_string(buf, end, ptr, field_width, precision, flags); #endif +/* Device paths only exist in the EFI context. */ +#if CONFIG_IS_ENABLED(OF_CONTROL) && !defined(API_BUILD) + case 'O': + if (fmt[1] == 'F') + return ofnode_string(buf, end, ptr, field_width, + precision, flags); + break; +#endif case 'a': flags |= SPECIAL | ZEROPAD; |
