summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/Kconfig13
-rw-r--r--lib/acpi/base.c4
-rw-r--r--lib/efi_loader/Kconfig8
-rw-r--r--lib/efi_loader/efi_bootbin.c7
-rw-r--r--lib/efi_loader/efi_bootmgr.c7
-rw-r--r--lib/efi_loader/efi_console.c7
-rw-r--r--lib/efi_loader/efi_device_path.c4
-rw-r--r--lib/efi_loader/efi_dt_fixup.c3
-rw-r--r--lib/efi_loader/efi_hii.c3
-rw-r--r--lib/efi_loader/efi_image_loader.c86
-rw-r--r--lib/efi_loader/efi_memory.c51
-rw-r--r--lib/efi_loader/efi_setup.c2
-rw-r--r--lib/efi_selftest/efi_selftest_hii.c67
-rw-r--r--lib/efi_selftest/efi_selftest_hii_data.c12
-rw-r--r--lib/efi_selftest/efi_selftest_memory.c21
-rw-r--r--lib/fdtdec.c129
-rw-r--r--lib/fwu_updates/fwu.c33
-rw-r--r--lib/gunzip.c76
-rw-r--r--lib/lmb.c20
-rw-r--r--lib/smbios.c4
-rw-r--r--lib/string.c31
-rw-r--r--lib/uuid.c1
-rw-r--r--lib/vsprintf.c37
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;