summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/Kconfig48
-rw-r--r--lib/Makefile3
-rw-r--r--lib/acpi/acpi_dp.c2
-rw-r--r--lib/acpi/acpigen.c2
-rw-r--r--lib/alist.c158
-rw-r--r--lib/asm-offsets.c2
-rw-r--r--lib/crypto/Kconfig2
-rw-r--r--lib/efi/Kconfig5
-rw-r--r--lib/efi/efi_app.c2
-rw-r--r--lib/efi_loader/Kconfig215
-rw-r--r--lib/efi_loader/efi_bootmgr.c28
-rw-r--r--lib/efi_loader/efi_capsule.c1
-rw-r--r--lib/efi_loader/efi_console.c2
-rw-r--r--lib/efi_loader/efi_device_path.c2
-rw-r--r--lib/efi_loader/efi_dt_fixup.c2
-rw-r--r--lib/efi_loader/efi_firmware.c55
-rw-r--r--lib/efi_loader/efi_helper.c2
-rw-r--r--lib/efi_loader/efi_variable.c2
-rw-r--r--lib/efi_loader/helloworld.c3
-rw-r--r--lib/elf.c14
-rw-r--r--lib/fdtdec.c1
-rw-r--r--lib/fwu_updates/fwu_mtd.c7
-rw-r--r--lib/lmb.c693
-rw-r--r--lib/strto.c4
-rw-r--r--lib/uuid.c103
-rw-r--r--lib/vsprintf.c2
26 files changed, 936 insertions, 424 deletions
diff --git a/lib/Kconfig b/lib/Kconfig
index 2059219a120..1dd4f271595 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -73,6 +73,7 @@ config HAVE_PRIVATE_LIBGCC
config LIB_UUID
bool
+ select SHA1
config RANDOM_UUID
bool "GPT Random UUID generation"
@@ -403,7 +404,7 @@ config TRACE_EARLY_CALL_DEPTH_LIMIT
config TRACE_EARLY_ADDR
hex "Address of early trace buffer in U-Boot"
depends on TRACE_EARLY
- default 0x00100000
+ default 0x00200000
help
Sets the address of the early trace buffer in U-Boot. This memory
must be accessible before relocation.
@@ -1081,8 +1082,6 @@ config SMBIOS_PARSER
help
A simple parser for SMBIOS data.
-source "lib/efi/Kconfig"
-source "lib/efi_loader/Kconfig"
source "lib/optee/Kconfig"
config TEST_FDTDEC
@@ -1102,42 +1101,19 @@ config LMB
bool "Enable the logical memory blocks library (lmb)"
default y if ARC || ARM || M68K || MICROBLAZE || MIPS || \
NIOS2 || PPC || RISCV || SANDBOX || SH || X86 || XTENSA
+ select ARCH_MISC_INIT if PPC
help
- Support the library logical memory blocks.
-
-config LMB_USE_MAX_REGIONS
- bool "Use a common number of memory and reserved regions in lmb lib"
- default y
- help
- Define the number of supported memory regions in the library logical
- memory blocks.
- This feature allow to reduce the lmb library size by using compiler
- optimization when LMB_MEMORY_REGIONS == LMB_RESERVED_REGIONS.
-
-config LMB_MAX_REGIONS
- int "Number of memory and reserved regions in lmb lib"
- depends on LMB_USE_MAX_REGIONS
- default 16
- help
- Define the number of supported regions, memory and reserved, in the
- library logical memory blocks.
-
-config LMB_MEMORY_REGIONS
- int "Number of memory regions in lmb lib"
- depends on !LMB_USE_MAX_REGIONS
- default 8
- help
- Define the number of supported memory regions in the library logical
- memory blocks.
- The minimal value is CONFIG_NR_DRAM_BANKS.
+ Support the library logical memory blocks. This will require
+ a malloc() implementation for defining the data structures
+ needed for maintaining the LMB memory map.
-config LMB_RESERVED_REGIONS
- int "Number of reserved regions in lmb lib"
- depends on !LMB_USE_MAX_REGIONS
- default 8
+config SPL_LMB
+ bool "Enable LMB module for SPL"
+ depends on SPL && SPL_FRAMEWORK && SPL_SYS_MALLOC
help
- Define the number of supported reserved regions in the library logical
- memory blocks.
+ Enable support for Logical Memory Block library routines in
+ SPL. This will require a malloc() implementation for defining
+ the data structures needed for maintaining the LMB memory map.
config PHANDLE_CHECK_SEQ
bool "Enable phandle check while getting sequence number"
diff --git a/lib/Makefile b/lib/Makefile
index e389ad014f8..d300249f57c 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -118,7 +118,7 @@ obj-$(CONFIG_$(SPL_TPL_)OF_LIBFDT) += fdtdec.o fdtdec_common.o
obj-y += hang.o
obj-y += linux_compat.o
obj-y += linux_string.o
-obj-$(CONFIG_LMB) += lmb.o
+obj-$(CONFIG_$(SPL_TPL_)LMB) += lmb.o
obj-y += membuff.o
obj-$(CONFIG_REGEX) += slre.o
obj-y += string.o
@@ -147,6 +147,7 @@ endif
obj-$(CONFIG_$(SPL_)OID_REGISTRY) += oid_registry.o
obj-y += abuf.o
+obj-y += alist.o
obj-y += date.o
obj-y += rtc-lib.o
obj-$(CONFIG_LIB_ELF) += elf.o
diff --git a/lib/acpi/acpi_dp.c b/lib/acpi/acpi_dp.c
index 6733809986a..5714acce088 100644
--- a/lib/acpi/acpi_dp.c
+++ b/lib/acpi/acpi_dp.c
@@ -9,7 +9,7 @@
#include <dm.h>
#include <log.h>
#include <malloc.h>
-#include <uuid.h>
+#include <u-boot/uuid.h>
#include <acpi/acpigen.h>
#include <acpi/acpi_dp.h>
#include <dm/acpi.h>
diff --git a/lib/acpi/acpigen.c b/lib/acpi/acpigen.c
index b95cabb9149..ecff5a50d50 100644
--- a/lib/acpi/acpigen.c
+++ b/lib/acpi/acpigen.c
@@ -10,7 +10,7 @@
#include <dm.h>
#include <log.h>
-#include <uuid.h>
+#include <u-boot/uuid.h>
#include <acpi/acpigen.h>
#include <acpi/acpi_device.h>
#include <acpi/acpi_table.h>
diff --git a/lib/alist.c b/lib/alist.c
new file mode 100644
index 00000000000..b7928cad520
--- /dev/null
+++ b/lib/alist.c
@@ -0,0 +1,158 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Handles a contiguous list of pointers which be allocated and freed
+ *
+ * Copyright 2023 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <alist.h>
+#include <display_options.h>
+#include <malloc.h>
+#include <stdio.h>
+#include <string.h>
+
+enum {
+ ALIST_INITIAL_SIZE = 4, /* default size of unsized list */
+};
+
+bool alist_init(struct alist *lst, uint obj_size, uint start_size)
+{
+ /* Avoid realloc for the initial size to help malloc_simple */
+ memset(lst, '\0', sizeof(struct alist));
+ if (start_size) {
+ lst->data = calloc(obj_size, start_size);
+ if (!lst->data) {
+ lst->flags = ALISTF_FAIL;
+ return false;
+ }
+ lst->alloc = start_size;
+ }
+ lst->obj_size = obj_size;
+
+ return true;
+}
+
+void alist_uninit(struct alist *lst)
+{
+ free(lst->data);
+
+ /* Clear fields to avoid any confusion */
+ memset(lst, '\0', sizeof(struct alist));
+}
+
+/**
+ * alist_expand_to() - Expand a list to the given size
+ *
+ * @lst: List to modify
+ * @inc_by: Amount to expand to
+ * Return: true if OK, false if out of memory
+ */
+static bool alist_expand_to(struct alist *lst, uint new_alloc)
+{
+ void *new_data;
+
+ if (lst->flags & ALISTF_FAIL)
+ return false;
+
+ /* avoid using realloc() since it increases code size */
+ new_data = malloc(lst->obj_size * new_alloc);
+ if (!new_data) {
+ lst->flags |= ALISTF_FAIL;
+ return false;
+ }
+
+ memcpy(new_data, lst->data, lst->obj_size * lst->alloc);
+ free(lst->data);
+
+ memset(new_data + lst->obj_size * lst->alloc, '\0',
+ lst->obj_size * (new_alloc - lst->alloc));
+ lst->alloc = new_alloc;
+ lst->data = new_data;
+
+ return true;
+}
+
+bool alist_expand_by(struct alist *lst, uint inc_by)
+{
+ return alist_expand_to(lst, lst->alloc + inc_by);
+}
+
+/**
+ * alist_expand_min() - Expand to at least the provided size
+ *
+ * Expands to the lowest power of two which can incorporate the new size
+ *
+ * @lst: alist to expand
+ * @min_alloc: Minimum new allocated size; if 0 then ALIST_INITIAL_SIZE is used
+ * Return: true if OK, false if out of memory
+ */
+static bool alist_expand_min(struct alist *lst, uint min_alloc)
+{
+ uint new_alloc;
+
+ for (new_alloc = lst->alloc ?: ALIST_INITIAL_SIZE;
+ new_alloc < min_alloc;)
+ new_alloc *= 2;
+
+ return alist_expand_to(lst, new_alloc);
+}
+
+const void *alist_get_ptr(const struct alist *lst, uint index)
+{
+ if (index >= lst->count)
+ return NULL;
+
+ return lst->data + index * lst->obj_size;
+}
+
+void *alist_ensure_ptr(struct alist *lst, uint index)
+{
+ uint minsize = index + 1;
+ void *ptr;
+
+ if (index >= lst->alloc && !alist_expand_min(lst, minsize))
+ return NULL;
+
+ ptr = lst->data + index * lst->obj_size;
+ if (minsize >= lst->count)
+ lst->count = minsize;
+
+ return ptr;
+}
+
+void *alist_add_placeholder(struct alist *lst)
+{
+ return alist_ensure_ptr(lst, lst->count);
+}
+
+void *alist_add_ptr(struct alist *lst, void *obj)
+{
+ void *ptr;
+
+ ptr = alist_add_placeholder(lst);
+ if (!ptr)
+ return NULL;
+ memcpy(ptr, obj, lst->obj_size);
+
+ return ptr;
+}
+
+void *alist_uninit_move_ptr(struct alist *alist, size_t *countp)
+{
+ void *ptr;
+
+ if (countp)
+ *countp = alist->count;
+ if (!alist->count) {
+ alist_uninit(alist);
+ return NULL;
+ }
+
+ ptr = alist->data;
+
+ /* Clear everything out so there is no record of the data */
+ alist_init(alist, alist->obj_size, 0);
+
+ return ptr;
+}
diff --git a/lib/asm-offsets.c b/lib/asm-offsets.c
index 4e2dbda9a71..b6bbcbf76ca 100644
--- a/lib/asm-offsets.c
+++ b/lib/asm-offsets.c
@@ -44,7 +44,9 @@ int main(void)
DEFINE(GD_NEW_GD, offsetof(struct global_data, new_gd));
+#if CONFIG_IS_ENABLED(ENV_SUPPORT)
DEFINE(GD_ENV_ADDR, offsetof(struct global_data, env_addr));
+#endif
return 0;
}
diff --git a/lib/crypto/Kconfig b/lib/crypto/Kconfig
index 6e0656ad1c5..742f6d9d4ed 100644
--- a/lib/crypto/Kconfig
+++ b/lib/crypto/Kconfig
@@ -1,6 +1,6 @@
menuconfig ASYMMETRIC_KEY_TYPE
bool "Asymmetric (public-key cryptographic) key Support"
- depends on FIT_SIGNATURE
+ depends on FIT_SIGNATURE || RSA_VERIFY_WITH_PKEY
help
This option provides support for a key type that holds the data for
the asymmetric keys used for public key cryptographic operations such
diff --git a/lib/efi/Kconfig b/lib/efi/Kconfig
index c2b9bb73f71..81ed3e66b34 100644
--- a/lib/efi/Kconfig
+++ b/lib/efi/Kconfig
@@ -1,3 +1,6 @@
+menu "U-Boot as UEFI application"
+ depends on X86
+
config EFI
bool "Support running U-Boot from EFI"
depends on X86
@@ -72,3 +75,5 @@ config EFI_RAM_SIZE
use. U-Boot allocates this from EFI on start-up (along with a few
other smaller amounts) and it can never be increased after that.
It is used as the RAM size in with U-Boot.
+
+endmenu
diff --git a/lib/efi/efi_app.c b/lib/efi/efi_app.c
index 88332c3c910..9b94a93ee4f 100644
--- a/lib/efi/efi_app.c
+++ b/lib/efi/efi_app.c
@@ -17,7 +17,7 @@
#include <init.h>
#include <malloc.h>
#include <sysreset.h>
-#include <uuid.h>
+#include <u-boot/uuid.h>
#include <asm/global_data.h>
#include <linux/err.h>
#include <linux/types.h>
diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig
index 6ffefa9103f..e58b8825605 100644
--- a/lib/efi_loader/Kconfig
+++ b/lib/efi_loader/Kconfig
@@ -1,3 +1,5 @@
+menu "UEFI Support"
+
config EFI_LOADER
bool "Support running UEFI applications"
depends on OF_LIBFDT && ( \
@@ -41,13 +43,58 @@ config EFI_BINARY_EXEC
You may enable CMD_BOOTEFI_BINARY so that you can use bootefi
command to do that.
-config EFI_BOOTMGR
- bool "UEFI Boot Manager"
+config EFI_SECURE_BOOT
+ bool "Enable EFI secure boot support"
+ depends on EFI_LOADER && FIT_SIGNATURE
+ select HASH
+ select SHA256
+ select RSA
+ select RSA_VERIFY_WITH_PKEY
+ select IMAGE_SIGN_INFO
+ select ASYMMETRIC_KEY_TYPE
+ select ASYMMETRIC_PUBLIC_KEY_SUBTYPE
+ select X509_CERTIFICATE_PARSER
+ select PKCS7_MESSAGE_PARSER
+ select PKCS7_VERIFY
+ select MSCODE_PARSER
+ select EFI_SIGNATURE_SUPPORT
+ help
+ Select this option to enable EFI secure boot support.
+ Once SecureBoot mode is enforced, any EFI binary can run only if
+ it is signed with a trusted key. To do that, you need to install,
+ at least, PK, KEK and db.
+
+config EFI_SIGNATURE_SUPPORT
+ bool
+
+menu "UEFI services"
+
+config EFI_GET_TIME
+ bool "GetTime() runtime service"
+ depends on DM_RTC
default y
help
- Select this option if you want to select the UEFI binary to be booted
- via UEFI variables Boot####, BootOrder, and BootNext. You should also
- normally enable CMD_BOOTEFI_BOOTMGR so that the command is available.
+ Provide the GetTime() runtime service at boottime. This service
+ can be used by an EFI application to read the real time clock.
+
+config EFI_SET_TIME
+ bool "SetTime() runtime service"
+ depends on EFI_GET_TIME
+ default y if ARCH_QEMU || SANDBOX
+ help
+ Provide the SetTime() runtime service at boottime. This service
+ 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
+ default y
+ depends on ARCH_BCM283X || FSL_LAYERSCAPE || PSCI_RESET || \
+ SANDBOX || SYSRESET_SBI || SYSRESET_X86
+
+endmenu
+
+menu "UEFI Variables"
choice
prompt "Store for non-volatile UEFI variables"
@@ -172,30 +219,18 @@ config EFI_VAR_BUF_SIZE
Minimum 4096, default 131072
-config EFI_GET_TIME
- bool "GetTime() runtime service"
- depends on DM_RTC
- default y
+config EFI_PLATFORM_LANG_CODES
+ string "Language codes supported by firmware"
+ default "en-US"
help
- Provide the GetTime() runtime service at boottime. This service
- can be used by an EFI application to read the real time clock.
+ This value is used to initialize the PlatformLangCodes variable. Its
+ value is a semicolon (;) separated list of language codes in native
+ RFC 4646 format, e.g. "en-US;de-DE". The first language code is used
+ to initialize the PlatformLang variable.
-config EFI_SET_TIME
- bool "SetTime() runtime service"
- depends on EFI_GET_TIME
- default y if ARCH_QEMU || SANDBOX
- help
- Provide the SetTime() runtime service at boottime. This service
- can be used by an EFI application to adjust the real time clock.
+endmenu
-config EFI_SCROLL_ON_CLEAR_SCREEN
- bool "Avoid overwriting previous output on clear screen"
- help
- Instead of erasing the screen content when the console screen should
- be cleared, emit blank new lines so that previous output is scrolled
- out of sight rather than overwritten. On serial consoles this allows
- to capture complete boot logs (except for interactive menus etc.)
- and can ease debugging related issues.
+menu "Capsule support"
config EFI_HAVE_CAPSULE_SUPPORT
bool
@@ -237,6 +272,18 @@ config EFI_CAPSULE_ON_DISK_EARLY
executed as part of U-Boot initialisation so that they will
surely take place whatever is set to distro_bootcmd.
+config EFI_CAPSULE_NAMESPACE_GUID
+ string "Namespace for dynamic capsule GUIDs"
+ # v4 UUID as a default for upstream U-Boot boards
+ default "8c9f137e-91dc-427b-b2d6-b420faebaf2a"
+ depends on EFI_HAVE_CAPSULE_SUPPORT
+ help
+ Define the namespace or "salt" GUID used to generate the per-image
+ GUIDs. This should be a GUID in the standard 8-4-4-4-12 format.
+
+ Device vendors are expected to generate their own namespace GUID
+ to avoid conflicts with upstream/community images.
+
config EFI_CAPSULE_FIRMWARE
bool
@@ -309,6 +356,10 @@ config EFI_CAPSULE_CRT_FILE
embedded in the platform's device tree and used for capsule
authentication at the time of capsule update.
+endmenu
+
+menu "UEFI protocol support"
+
config EFI_DEVICE_PATH_TO_TEXT
bool "Device path to text protocol"
default y
@@ -362,39 +413,6 @@ config EFI_UNICODE_CAPITALIZATION
endif
-config EFI_LOADER_BOUNCE_BUFFER
- bool "EFI Applications use bounce buffers for DMA operations"
- help
- Some hardware does not support DMA to full 64bit addresses. For this
- hardware we can create a bounce buffer so that payloads don't have to
- worry about platform details.
-
-config EFI_PLATFORM_LANG_CODES
- string "Language codes supported by firmware"
- default "en-US"
- help
- This value is used to initialize the PlatformLangCodes variable. Its
- value is a semicolon (;) separated list of language codes in native
- RFC 4646 format, e.g. "en-US;de-DE". The first language code is used
- to initialize the PlatformLang variable.
-
-config EFI_HAVE_RUNTIME_RESET
- # bool "Reset runtime service is available"
- bool
- default y
- depends on ARCH_BCM283X || FSL_LAYERSCAPE || PSCI_RESET || \
- SANDBOX || SYSRESET_SBI || SYSRESET_X86
-
-config EFI_GRUB_ARM32_WORKAROUND
- bool "Workaround for GRUB on 32bit ARM"
- default n if ARCH_BCM283X || ARCH_SUNXI || ARCH_QEMU
- default y
- depends on ARM && !ARM64
- help
- GRUB prior to version 2.04 requires U-Boot to disable caches. This
- workaround currently is also needed on systems with caches that
- cannot be managed via CP15.
-
config EFI_RNG_PROTOCOL
bool "EFI_RNG_PROTOCOL support"
depends on DM_RNG
@@ -447,29 +465,36 @@ config EFI_LOAD_FILE2_INITRD
installed and Linux 5.7+ will ignore any initrd=<ramdisk> command line
argument.
-config EFI_SECURE_BOOT
- bool "Enable EFI secure boot support"
- depends on EFI_LOADER && FIT_SIGNATURE
- select HASH
- select SHA256
- select RSA
- select RSA_VERIFY_WITH_PKEY
- select IMAGE_SIGN_INFO
- select ASYMMETRIC_KEY_TYPE
- select ASYMMETRIC_PUBLIC_KEY_SUBTYPE
- select X509_CERTIFICATE_PARSER
- select PKCS7_MESSAGE_PARSER
- select PKCS7_VERIFY
- select MSCODE_PARSER
- select EFI_SIGNATURE_SUPPORT
+config EFI_RISCV_BOOT_PROTOCOL
+ bool "RISCV_EFI_BOOT_PROTOCOL support"
+ default y
+ depends on RISCV
help
- Select this option to enable EFI secure boot support.
- Once SecureBoot mode is enforced, any EFI binary can run only if
- it is signed with a trusted key. To do that, you need to install,
- at least, PK, KEK and db.
+ The EFI_RISCV_BOOT_PROTOCOL is used to transfer the boot hart ID
+ to the next boot stage. It should be enabled as it is meant to
+ replace the transfer via the device-tree. The latter is not
+ possible on systems using ACPI.
-config EFI_SIGNATURE_SUPPORT
- bool
+endmenu
+
+menu "Misc options"
+config EFI_LOADER_BOUNCE_BUFFER
+ bool "EFI Applications use bounce buffers for DMA operations"
+ depends on ARM64
+ help
+ Some hardware does not support DMA to full 64bit addresses. For this
+ hardware we can create a bounce buffer so that payloads don't have to
+ worry about platform details.
+
+config EFI_GRUB_ARM32_WORKAROUND
+ bool "Workaround for GRUB on 32bit ARM"
+ default n if ARCH_BCM283X || ARCH_SUNXI || ARCH_QEMU
+ default y
+ depends on ARM && !ARM64
+ help
+ GRUB prior to version 2.04 requires U-Boot to disable caches. This
+ workaround currently is also needed on systems with caches that
+ cannot be managed via CP15.
config EFI_ESRT
bool "Enable the UEFI ESRT generation"
@@ -496,15 +521,26 @@ config EFI_EBBR_2_1_CONFORMANCE
help
Enabling this option adds the EBBRv2.1 conformance entry to the ECPT UEFI table.
-config EFI_RISCV_BOOT_PROTOCOL
- bool "RISCV_EFI_BOOT_PROTOCOL support"
+config EFI_SCROLL_ON_CLEAR_SCREEN
+ bool "Avoid overwriting previous output on clear screen"
+ help
+ Instead of erasing the screen content when the console screen should
+ be cleared, emit blank new lines so that previous output is scrolled
+ out of sight rather than overwritten. On serial consoles this allows
+ to capture complete boot logs (except for interactive menus etc.)
+ and can ease debugging related issues.
+
+endmenu
+
+menu "EFI bootmanager"
+
+config EFI_BOOTMGR
+ bool "UEFI Boot Manager"
default y
- depends on RISCV
help
- The EFI_RISCV_BOOT_PROTOCOL is used to transfer the boot hart ID
- to the next boot stage. It should be enabled as it is meant to
- replace the transfer via the device-tree. The latter is not
- possible on systems using ACPI.
+ Select this option if you want to select the UEFI binary to be booted
+ via UEFI variables Boot####, BootOrder, and BootNext. You should also
+ normally enable CMD_BOOTEFI_BOOTMGR so that the command is available.
config EFI_HTTP_BOOT
bool "EFI HTTP Boot support"
@@ -514,5 +550,10 @@ config EFI_HTTP_BOOT
help
Enabling this option adds EFI HTTP Boot support. It allows to
directly boot from network.
+endmenu
endif
+
+source "lib/efi/Kconfig"
+
+endmenu
diff --git a/lib/efi_loader/efi_bootmgr.c b/lib/efi_loader/efi_bootmgr.c
index 589d3996b68..a3aa2b8d1b9 100644
--- a/lib/efi_loader/efi_bootmgr.c
+++ b/lib/efi_loader/efi_bootmgr.c
@@ -380,14 +380,15 @@ err:
}
/**
- * efi_bootmgr_release_uridp_resource() - cleanup uri device path resource
+ * efi_bootmgr_release_uridp() - cleanup uri device path resource
*
* @ctx: event context
* Return: status code
*/
-efi_status_t efi_bootmgr_release_uridp_resource(struct uridp_context *ctx)
+efi_status_t efi_bootmgr_release_uridp(struct uridp_context *ctx)
{
efi_status_t ret = EFI_SUCCESS;
+ efi_status_t ret2 = EFI_SUCCESS;
if (!ctx)
return ret;
@@ -407,32 +408,33 @@ efi_status_t efi_bootmgr_release_uridp_resource(struct uridp_context *ctx)
/* cleanup for PE-COFF image */
if (ctx->mem_handle) {
- ret = efi_uninstall_multiple_protocol_interfaces(
- ctx->mem_handle, &efi_guid_device_path, ctx->loaded_dp,
- NULL);
- if (ret != EFI_SUCCESS)
+ ret2 = efi_uninstall_multiple_protocol_interfaces(ctx->mem_handle,
+ &efi_guid_device_path,
+ ctx->loaded_dp,
+ NULL);
+ if (ret2 != EFI_SUCCESS)
log_err("Uninstall device_path protocol failed\n");
}
efi_free_pool(ctx->loaded_dp);
free(ctx);
- return ret;
+ return ret == EFI_SUCCESS ? ret2 : ret;
}
/**
- * efi_bootmgr_image_return_notify() - return to efibootmgr callback
+ * efi_bootmgr_http_return() - return to efibootmgr callback
*
* @event: the event for which this notification function is registered
* @context: event context
*/
-static void EFIAPI efi_bootmgr_image_return_notify(struct efi_event *event,
- void *context)
+static void EFIAPI efi_bootmgr_http_return(struct efi_event *event,
+ void *context)
{
efi_status_t ret;
EFI_ENTRY("%p, %p", event, context);
- ret = efi_bootmgr_release_uridp_resource(context);
+ ret = efi_bootmgr_release_uridp(context);
EFI_EXIT(ret);
}
@@ -533,7 +535,7 @@ static efi_status_t try_load_from_uri_path(struct efi_device_path_uri *uridp,
/* create event for cleanup when the image returns or error occurs */
ret = efi_create_event(EVT_NOTIFY_SIGNAL, TPL_CALLBACK,
- efi_bootmgr_image_return_notify, ctx,
+ efi_bootmgr_http_return, ctx,
&efi_guid_event_group_return_to_efibootmgr,
&event);
if (ret != EFI_SUCCESS) {
@@ -544,7 +546,7 @@ static efi_status_t try_load_from_uri_path(struct efi_device_path_uri *uridp,
return ret;
err:
- efi_bootmgr_release_uridp_resource(ctx);
+ efi_bootmgr_release_uridp(ctx);
return ret;
}
diff --git a/lib/efi_loader/efi_capsule.c b/lib/efi_loader/efi_capsule.c
index 635088f25a1..a4ea2873038 100644
--- a/lib/efi_loader/efi_capsule.c
+++ b/lib/efi_loader/efi_capsule.c
@@ -20,6 +20,7 @@
#include <sort.h>
#include <sysreset.h>
#include <asm/global_data.h>
+#include <u-boot/uuid.h>
#include <crypto/pkcs7.h>
#include <crypto/pkcs7_parser.h>
diff --git a/lib/efi_loader/efi_console.c b/lib/efi_loader/efi_console.c
index c944c10b216..cea50c748aa 100644
--- a/lib/efi_loader/efi_console.c
+++ b/lib/efi_loader/efi_console.c
@@ -181,7 +181,7 @@ static efi_status_t EFIAPI efi_cout_output_string(
}
pos = buf;
utf16_utf8_strcpy(&pos, string);
- fputs(stdout, buf);
+ puts(buf);
free(buf);
/*
diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c
index 0f684590f22..9de3b95d073 100644
--- a/lib/efi_loader/efi_device_path.c
+++ b/lib/efi_loader/efi_device_path.c
@@ -17,7 +17,7 @@
#include <nvme.h>
#include <efi_loader.h>
#include <part.h>
-#include <uuid.h>
+#include <u-boot/uuid.h>
#include <asm-generic/unaligned.h>
#include <linux/compat.h> /* U16_MAX */
diff --git a/lib/efi_loader/efi_dt_fixup.c b/lib/efi_loader/efi_dt_fixup.c
index 9886e6897cd..9d017804eea 100644
--- a/lib/efi_loader/efi_dt_fixup.c
+++ b/lib/efi_loader/efi_dt_fixup.c
@@ -172,7 +172,7 @@ efi_dt_fixup(struct efi_dt_fixup_protocol *this, void *dtb,
}
fdt_set_totalsize(dtb, *buffer_size);
- if (image_setup_libfdt(&img, dtb, NULL)) {
+ if (image_setup_libfdt(&img, dtb, false)) {
log_err("failed to process device tree\n");
ret = EFI_INVALID_PARAMETER;
goto out;
diff --git a/lib/efi_loader/efi_firmware.c b/lib/efi_loader/efi_firmware.c
index ba5aba098c0..6650c2b8071 100644
--- a/lib/efi_loader/efi_firmware.c
+++ b/lib/efi_loader/efi_firmware.c
@@ -246,6 +246,55 @@ void efi_firmware_fill_version_info(struct efi_firmware_image_descriptor *image_
}
/**
+ * efi_gen_capsule_guids - generate GUIDs for the images
+ *
+ * Generate the image_type_id for each image in the update_info.images array
+ * using the first compatible from the device tree and a salt
+ * UUID defined at build time.
+ *
+ * Returns: status code
+ */
+static efi_status_t efi_gen_capsule_guids(void)
+{
+ int ret, i;
+ struct uuid namespace;
+ const char *compatible; /* Full array including null bytes */
+ struct efi_fw_image *fw_array;
+
+ fw_array = update_info.images;
+ /* Check if we need to run (there are images and we didn't already generate their IDs) */
+ if (!update_info.num_images ||
+ memchr_inv(&fw_array[0].image_type_id, 0, sizeof(fw_array[0].image_type_id)))
+ return EFI_SUCCESS;
+
+ ret = uuid_str_to_bin(CONFIG_EFI_CAPSULE_NAMESPACE_GUID,
+ (unsigned char *)&namespace, UUID_STR_FORMAT_GUID);
+ if (ret) {
+ log_debug("%s: EFI_CAPSULE_NAMESPACE_GUID is invalid: %d\n", __func__, ret);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ compatible = ofnode_read_string(ofnode_root(), "compatible");
+ if (!compatible) {
+ log_debug("%s: model or compatible not defined\n", __func__);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ for (i = 0; i < update_info.num_images; i++) {
+ gen_v5_guid(&namespace,
+ &fw_array[i].image_type_id,
+ compatible, strlen(compatible),
+ fw_array[i].fw_name, u16_strlen(fw_array[i].fw_name) * sizeof(uint16_t),
+ NULL);
+
+ log_debug("Image %ls UUID %pUl\n", fw_array[i].fw_name,
+ &fw_array[i].image_type_id);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
* efi_fill_image_desc_array - populate image descriptor array
* @image_info_size: Size of @image_info
* @image_info: Image information
@@ -272,7 +321,7 @@ static efi_status_t efi_fill_image_desc_array(
{
size_t total_size;
struct efi_fw_image *fw_array;
- int i;
+ int i, ret;
total_size = sizeof(*image_info) * update_info.num_images;
@@ -283,6 +332,10 @@ static efi_status_t efi_fill_image_desc_array(
}
*image_info_size = total_size;
+ ret = efi_gen_capsule_guids();
+ if (ret != EFI_SUCCESS)
+ return ret;
+
fw_array = update_info.images;
*descriptor_count = update_info.num_images;
*descriptor_version = EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION;
diff --git a/lib/efi_loader/efi_helper.c b/lib/efi_loader/efi_helper.c
index 916f43da26c..96f847652ec 100644
--- a/lib/efi_loader/efi_helper.c
+++ b/lib/efi_loader/efi_helper.c
@@ -514,7 +514,7 @@ efi_status_t efi_install_fdt(void *fdt)
return EFI_OUT_OF_RESOURCES;
}
- if (image_setup_libfdt(&img, fdt, NULL)) {
+ if (image_setup_libfdt(&img, fdt, false)) {
log_err("ERROR: failed to process device tree\n");
return EFI_LOAD_ERROR;
}
diff --git a/lib/efi_loader/efi_variable.c b/lib/efi_loader/efi_variable.c
index e888c52efe3..f3533f4def3 100644
--- a/lib/efi_loader/efi_variable.c
+++ b/lib/efi_loader/efi_variable.c
@@ -16,7 +16,7 @@
#include <malloc.h>
#include <rtc.h>
#include <search.h>
-#include <uuid.h>
+#include <u-boot/uuid.h>
#include <crypto/pkcs7_parser.h>
#include <linux/compat.h>
#include <u-boot/crc.h>
diff --git a/lib/efi_loader/helloworld.c b/lib/efi_loader/helloworld.c
index bd72822c0b7..586177de0c8 100644
--- a/lib/efi_loader/helloworld.c
+++ b/lib/efi_loader/helloworld.c
@@ -2,6 +2,9 @@
/*
* Hello world EFI application
*
+ * Copyright (c) 2016 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
* Copyright 2020, Heinrich Schuchardt <xypron.glpk@gmx.de>
*
* This test program is used to test the invocation of an EFI application.
diff --git a/lib/elf.c b/lib/elf.c
index dc13935e103..e767a42a3b3 100644
--- a/lib/elf.c
+++ b/lib/elf.c
@@ -86,10 +86,14 @@ unsigned long load_elf64_image_phdr(unsigned long addr)
phdr = (Elf64_Phdr *)(addr + (ulong)ehdr->e_phoff);
/* Load each program header */
- for (i = 0; i < ehdr->e_phnum; ++i) {
+ for (i = 0; i < ehdr->e_phnum; ++i, ++phdr) {
void *dst = (void *)(ulong)phdr->p_paddr;
void *src = (void *)addr + phdr->p_offset;
+ /* Only load PT_LOAD program header */
+ if (phdr->p_type != PT_LOAD)
+ continue;
+
debug("Loading phdr %i to 0x%p (%lu bytes)\n",
i, dst, (ulong)phdr->p_filesz);
if (phdr->p_filesz)
@@ -99,7 +103,6 @@ unsigned long load_elf64_image_phdr(unsigned long addr)
phdr->p_memsz - phdr->p_filesz);
flush_cache(rounddown((unsigned long)dst, ARCH_DMA_MINALIGN),
roundup(phdr->p_memsz, ARCH_DMA_MINALIGN));
- ++phdr;
}
if (ehdr->e_machine == EM_PPC64 && (ehdr->e_flags &
@@ -201,10 +204,14 @@ unsigned long load_elf_image_phdr(unsigned long addr)
phdr = (Elf32_Phdr *)(addr + ehdr->e_phoff);
/* Load each program header */
- for (i = 0; i < ehdr->e_phnum; ++i) {
+ for (i = 0; i < ehdr->e_phnum; ++i, ++phdr) {
void *dst = (void *)(uintptr_t)phdr->p_paddr;
void *src = (void *)addr + phdr->p_offset;
+ /* Only load PT_LOAD program header */
+ if (phdr->p_type != PT_LOAD)
+ continue;
+
debug("Loading phdr %i to 0x%p (%i bytes)\n",
i, dst, phdr->p_filesz);
if (phdr->p_filesz)
@@ -214,7 +221,6 @@ unsigned long load_elf_image_phdr(unsigned long addr)
phdr->p_memsz - phdr->p_filesz);
flush_cache(rounddown((unsigned long)dst, ARCH_DMA_MINALIGN),
roundup(phdr->p_memsz, ARCH_DMA_MINALIGN));
- ++phdr;
}
return ehdr->e_entry;
diff --git a/lib/fdtdec.c b/lib/fdtdec.c
index 6865f78c70d..5edc8dd2f9f 100644
--- a/lib/fdtdec.c
+++ b/lib/fdtdec.c
@@ -1685,6 +1685,7 @@ int fdtdec_setup(void)
gd->fdt_src = FDTSRC_BLOBLIST;
log_debug("Devicetree is in bloblist at %p\n",
gd->fdt_blob);
+ ret = 0;
} else {
log_debug("No FDT found in bloblist\n");
ret = -ENOENT;
diff --git a/lib/fwu_updates/fwu_mtd.c b/lib/fwu_updates/fwu_mtd.c
index ccaba3f3115..554723046f6 100644
--- a/lib/fwu_updates/fwu_mtd.c
+++ b/lib/fwu_updates/fwu_mtd.c
@@ -10,7 +10,7 @@
#include <log.h>
#include <malloc.h>
#include <mtd.h>
-#include <uuid.h>
+#include <u-boot/uuid.h>
#include <stdio.h>
#include <dm/ofnode.h>
@@ -60,10 +60,7 @@ int fwu_mtd_get_alt_num(efi_guid_t *image_id, u8 *alt_num,
if (ret)
return -ENOENT;
- nalt = 0;
- list_for_each_entry(dfu, &dfu_list, list)
- nalt++;
-
+ nalt = list_count_nodes(&dfu_list);
if (!nalt) {
log_warning("No entities in dfu_alt_info\n");
dfu_free_entities();
diff --git a/lib/lmb.c b/lib/lmb.c
index 44f98205310..3ed570fb29b 100644
--- a/lib/lmb.c
+++ b/lib/lmb.c
@@ -6,50 +6,72 @@
* Copyright (C) 2001 Peter Bergner.
*/
+#include <alist.h>
#include <efi_loader.h>
#include <image.h>
#include <mapmem.h>
#include <lmb.h>
#include <log.h>
#include <malloc.h>
+#include <spl.h>
#include <asm/global_data.h>
#include <asm/sections.h>
+#include <linux/kernel.h>
+#include <linux/sizes.h>
DECLARE_GLOBAL_DATA_PTR;
#define LMB_ALLOC_ANYWHERE 0
+#define LMB_ALIST_INITIAL_SIZE 4
-static void lmb_dump_region(struct lmb_region *rgn, char *name)
+static struct lmb lmb;
+
+static void lmb_print_region_flags(enum lmb_flags flags)
+{
+ u64 bitpos;
+ const char *flag_str[] = { "none", "no-map", "no-overwrite" };
+
+ do {
+ bitpos = flags ? fls(flags) - 1 : 0;
+ printf("%s", flag_str[bitpos]);
+ flags &= ~(1ull << bitpos);
+ puts(flags ? ", " : "\n");
+ } while (flags);
+}
+
+static void lmb_dump_region(struct alist *lmb_rgn_lst, char *name)
{
+ struct lmb_region *rgn = lmb_rgn_lst->data;
unsigned long long base, size, end;
enum lmb_flags flags;
int i;
- printf(" %s.cnt = 0x%lx / max = 0x%lx\n", name, rgn->cnt, rgn->max);
+ printf(" %s.count = 0x%x\n", name, lmb_rgn_lst->count);
- for (i = 0; i < rgn->cnt; i++) {
- base = rgn->region[i].base;
- size = rgn->region[i].size;
+ for (i = 0; i < lmb_rgn_lst->count; i++) {
+ base = rgn[i].base;
+ size = rgn[i].size;
end = base + size - 1;
- flags = rgn->region[i].flags;
+ flags = rgn[i].flags;
- printf(" %s[%d]\t[0x%llx-0x%llx], 0x%08llx bytes flags: %x\n",
- name, i, base, end, size, flags);
+ printf(" %s[%d]\t[0x%llx-0x%llx], 0x%08llx bytes flags: ",
+ name, i, base, end, size);
+ lmb_print_region_flags(flags);
}
}
-void lmb_dump_all_force(struct lmb *lmb)
+void lmb_dump_all_force(void)
{
printf("lmb_dump_all:\n");
- lmb_dump_region(&lmb->memory, "memory");
- lmb_dump_region(&lmb->reserved, "reserved");
+ lmb_dump_region(&lmb.free_mem, "memory");
+ lmb_dump_region(&lmb.used_mem, "reserved");
}
-void lmb_dump_all(struct lmb *lmb)
+void lmb_dump_all(void)
{
#ifdef DEBUG
- lmb_dump_all_force(lmb);
+ lmb_dump_all_force();
#endif
}
@@ -73,111 +95,71 @@ static long lmb_addrs_adjacent(phys_addr_t base1, phys_size_t size1,
return 0;
}
-static long lmb_regions_overlap(struct lmb_region *rgn, unsigned long r1,
+static long lmb_regions_overlap(struct alist *lmb_rgn_lst, unsigned long r1,
unsigned long r2)
{
- phys_addr_t base1 = rgn->region[r1].base;
- phys_size_t size1 = rgn->region[r1].size;
- phys_addr_t base2 = rgn->region[r2].base;
- phys_size_t size2 = rgn->region[r2].size;
+ struct lmb_region *rgn = lmb_rgn_lst->data;
+
+ phys_addr_t base1 = rgn[r1].base;
+ phys_size_t size1 = rgn[r1].size;
+ phys_addr_t base2 = rgn[r2].base;
+ phys_size_t size2 = rgn[r2].size;
return lmb_addrs_overlap(base1, size1, base2, size2);
}
-static long lmb_regions_adjacent(struct lmb_region *rgn, unsigned long r1,
+
+static long lmb_regions_adjacent(struct alist *lmb_rgn_lst, unsigned long r1,
unsigned long r2)
{
- phys_addr_t base1 = rgn->region[r1].base;
- phys_size_t size1 = rgn->region[r1].size;
- phys_addr_t base2 = rgn->region[r2].base;
- phys_size_t size2 = rgn->region[r2].size;
+ struct lmb_region *rgn = lmb_rgn_lst->data;
+
+ phys_addr_t base1 = rgn[r1].base;
+ phys_size_t size1 = rgn[r1].size;
+ phys_addr_t base2 = rgn[r2].base;
+ phys_size_t size2 = rgn[r2].size;
return lmb_addrs_adjacent(base1, size1, base2, size2);
}
-static void lmb_remove_region(struct lmb_region *rgn, unsigned long r)
+static void lmb_remove_region(struct alist *lmb_rgn_lst, unsigned long r)
{
unsigned long i;
+ struct lmb_region *rgn = lmb_rgn_lst->data;
- for (i = r; i < rgn->cnt - 1; i++) {
- rgn->region[i].base = rgn->region[i + 1].base;
- rgn->region[i].size = rgn->region[i + 1].size;
- rgn->region[i].flags = rgn->region[i + 1].flags;
+ for (i = r; i < lmb_rgn_lst->count - 1; i++) {
+ rgn[i].base = rgn[i + 1].base;
+ rgn[i].size = rgn[i + 1].size;
+ rgn[i].flags = rgn[i + 1].flags;
}
- rgn->cnt--;
+ lmb_rgn_lst->count--;
}
/* Assumption: base addr of region 1 < base addr of region 2 */
-static void lmb_coalesce_regions(struct lmb_region *rgn, unsigned long r1,
+static void lmb_coalesce_regions(struct alist *lmb_rgn_lst, unsigned long r1,
unsigned long r2)
{
- rgn->region[r1].size += rgn->region[r2].size;
- lmb_remove_region(rgn, r2);
+ struct lmb_region *rgn = lmb_rgn_lst->data;
+
+ rgn[r1].size += rgn[r2].size;
+ lmb_remove_region(lmb_rgn_lst, r2);
}
/*Assumption : base addr of region 1 < base addr of region 2*/
-static void lmb_fix_over_lap_regions(struct lmb_region *rgn, unsigned long r1,
- unsigned long r2)
+static void lmb_fix_over_lap_regions(struct alist *lmb_rgn_lst,
+ unsigned long r1, unsigned long r2)
{
- phys_addr_t base1 = rgn->region[r1].base;
- phys_size_t size1 = rgn->region[r1].size;
- phys_addr_t base2 = rgn->region[r2].base;
- phys_size_t size2 = rgn->region[r2].size;
+ struct lmb_region *rgn = lmb_rgn_lst->data;
+
+ phys_addr_t base1 = rgn[r1].base;
+ phys_size_t size1 = rgn[r1].size;
+ phys_addr_t base2 = rgn[r2].base;
+ phys_size_t size2 = rgn[r2].size;
if (base1 + size1 > base2 + size2) {
printf("This will not be a case any time\n");
return;
}
- rgn->region[r1].size = base2 + size2 - base1;
- lmb_remove_region(rgn, r2);
-}
-
-void lmb_init(struct lmb *lmb)
-{
-#if IS_ENABLED(CONFIG_LMB_USE_MAX_REGIONS)
- lmb->memory.max = CONFIG_LMB_MAX_REGIONS;
- lmb->reserved.max = CONFIG_LMB_MAX_REGIONS;
-#else
- lmb->memory.max = CONFIG_LMB_MEMORY_REGIONS;
- lmb->reserved.max = CONFIG_LMB_RESERVED_REGIONS;
- lmb->memory.region = lmb->memory_regions;
- lmb->reserved.region = lmb->reserved_regions;
-#endif
- lmb->memory.cnt = 0;
- lmb->reserved.cnt = 0;
-}
-
-void arch_lmb_reserve_generic(struct lmb *lmb, ulong sp, ulong end, ulong align)
-{
- ulong bank_end;
- int bank;
-
- /*
- * Reserve memory from aligned address below the bottom of U-Boot stack
- * until end of U-Boot area using LMB to prevent U-Boot from overwriting
- * that memory.
- */
- debug("## Current stack ends at 0x%08lx ", sp);
-
- /* adjust sp by 4K to be safe */
- sp -= align;
- for (bank = 0; bank < CONFIG_NR_DRAM_BANKS; bank++) {
- if (!gd->bd->bi_dram[bank].size ||
- sp < gd->bd->bi_dram[bank].start)
- continue;
- /* Watch out for RAM at end of address space! */
- bank_end = gd->bd->bi_dram[bank].start +
- gd->bd->bi_dram[bank].size - 1;
- if (sp > bank_end)
- continue;
- if (bank_end > end)
- bank_end = end - 1;
-
- lmb_reserve(lmb, sp, bank_end - sp + 1);
-
- if (gd->flags & GD_FLG_SKIP_RELOC)
- lmb_reserve(lmb, (phys_addr_t)(uintptr_t)_start, gd->mon_len);
-
- break;
- }
+ rgn[r1].size = base2 + size2 - base1;
+ lmb_remove_region(lmb_rgn_lst, r2);
}
/**
@@ -186,10 +168,9 @@ void arch_lmb_reserve_generic(struct lmb *lmb, ulong sp, ulong end, ulong align)
* Add reservations for all EFI memory areas that are not
* EFI_CONVENTIONAL_MEMORY.
*
- * @lmb: lmb environment
* Return: 0 on success, 1 on failure
*/
-static __maybe_unused int efi_lmb_reserve(struct lmb *lmb)
+static __maybe_unused int efi_lmb_reserve(void)
{
struct efi_mem_desc *memmap = NULL, *map;
efi_uintn_t i, map_size = 0;
@@ -201,8 +182,7 @@ static __maybe_unused int efi_lmb_reserve(struct lmb *lmb)
for (i = 0, map = memmap; i < map_size / sizeof(*map); ++map, ++i) {
if (map->type != EFI_CONVENTIONAL_MEMORY) {
- lmb_reserve_flags(lmb,
- map_to_sysmem((void *)(uintptr_t)
+ lmb_reserve_flags(map_to_sysmem((void *)(uintptr_t)
map->physical_start),
map->num_pages * EFI_PAGE_SIZE,
map->type == EFI_RESERVED_MEMORY_TYPE
@@ -214,64 +194,199 @@ static __maybe_unused int efi_lmb_reserve(struct lmb *lmb)
return 0;
}
-static void lmb_reserve_common(struct lmb *lmb, void *fdt_blob)
+static void lmb_reserve_uboot_region(void)
+{
+ int bank;
+ ulong end, bank_end;
+ phys_addr_t rsv_start;
+
+ rsv_start = gd->start_addr_sp - CONFIG_STACK_SIZE;
+ end = gd->ram_top;
+
+ /*
+ * Reserve memory from aligned address below the bottom of U-Boot stack
+ * until end of RAM area to prevent LMB from overwriting that memory.
+ */
+ debug("## Current stack ends at 0x%08lx ", (ulong)rsv_start);
+
+ /* adjust sp by 16K to be safe */
+ rsv_start -= SZ_16K;
+ for (bank = 0; bank < CONFIG_NR_DRAM_BANKS; bank++) {
+ if (!gd->bd->bi_dram[bank].size ||
+ rsv_start < gd->bd->bi_dram[bank].start)
+ continue;
+ /* Watch out for RAM at end of address space! */
+ bank_end = gd->bd->bi_dram[bank].start +
+ gd->bd->bi_dram[bank].size - 1;
+ if (rsv_start > bank_end)
+ continue;
+ if (bank_end > end)
+ bank_end = end - 1;
+
+ lmb_reserve_flags(rsv_start, bank_end - rsv_start + 1,
+ LMB_NOOVERWRITE);
+
+ if (gd->flags & GD_FLG_SKIP_RELOC)
+ lmb_reserve_flags((phys_addr_t)(uintptr_t)_start,
+ gd->mon_len, LMB_NOOVERWRITE);
+
+ break;
+ }
+}
+
+static void lmb_reserve_common(void *fdt_blob)
{
- arch_lmb_reserve(lmb);
- board_lmb_reserve(lmb);
+ lmb_reserve_uboot_region();
if (CONFIG_IS_ENABLED(OF_LIBFDT) && fdt_blob)
- boot_fdt_add_mem_rsv_regions(lmb, fdt_blob);
+ boot_fdt_add_mem_rsv_regions(fdt_blob);
if (CONFIG_IS_ENABLED(EFI_LOADER))
- efi_lmb_reserve(lmb);
+ efi_lmb_reserve();
+}
+
+static __maybe_unused void lmb_reserve_common_spl(void)
+{
+ phys_addr_t rsv_start;
+ phys_size_t rsv_size;
+
+ /*
+ * Assume a SPL stack of 16KB. This must be
+ * more than enough for the SPL stage.
+ */
+ if (IS_ENABLED(CONFIG_SPL_STACK_R_ADDR)) {
+ rsv_start = gd->start_addr_sp - 16384;
+ rsv_size = 16384;
+ lmb_reserve_flags(rsv_start, rsv_size, LMB_NOOVERWRITE);
+ }
+
+ if (IS_ENABLED(CONFIG_SPL_SEPARATE_BSS)) {
+ /* Reserve the bss region */
+ rsv_start = (phys_addr_t)(uintptr_t)__bss_start;
+ rsv_size = (phys_addr_t)(uintptr_t)__bss_end -
+ (phys_addr_t)(uintptr_t)__bss_start;
+ lmb_reserve_flags(rsv_start, rsv_size, LMB_NOOVERWRITE);
+ }
}
-/* Initialize the struct, add memory and call arch/board reserve functions */
-void lmb_init_and_reserve(struct lmb *lmb, struct bd_info *bd, void *fdt_blob)
+/**
+ * lmb_add_memory() - Add memory range for LMB allocations
+ *
+ * Add the entire available memory range to the pool of memory that
+ * can be used by the LMB module for allocations.
+ *
+ * Return: None
+ */
+void lmb_add_memory(void)
{
int i;
+ phys_size_t size;
+ phys_addr_t rgn_top;
+ u64 ram_top = gd->ram_top;
+ struct bd_info *bd = gd->bd;
- lmb_init(lmb);
+ /* Assume a 4GB ram_top if not defined */
+ if (!ram_top)
+ ram_top = 0x100000000ULL;
for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
- if (bd->bi_dram[i].size) {
- lmb_add(lmb, bd->bi_dram[i].start,
- bd->bi_dram[i].size);
+ size = bd->bi_dram[i].size;
+ if (size) {
+ if (bd->bi_dram[i].start > ram_top)
+ continue;
+
+ rgn_top = bd->bi_dram[i].start +
+ bd->bi_dram[i].size;
+
+ if (rgn_top > ram_top)
+ size -= rgn_top - ram_top;
+
+ lmb_add(bd->bi_dram[i].start, size);
}
}
-
- lmb_reserve_common(lmb, fdt_blob);
}
-/* Initialize the struct, add memory and call arch/board reserve functions */
-void lmb_init_and_reserve_range(struct lmb *lmb, phys_addr_t base,
- phys_size_t size, void *fdt_blob)
+static long lmb_resize_regions(struct alist *lmb_rgn_lst,
+ unsigned long idx_start,
+ phys_addr_t base, phys_size_t size)
{
- lmb_init(lmb);
- lmb_add(lmb, base, size);
- lmb_reserve_common(lmb, fdt_blob);
+ phys_size_t rgnsize;
+ unsigned long rgn_cnt, idx, idx_end;
+ phys_addr_t rgnbase, rgnend;
+ phys_addr_t mergebase, mergeend;
+ struct lmb_region *rgn = lmb_rgn_lst->data;
+
+ rgn_cnt = 0;
+ idx = idx_start;
+ idx_end = idx_start;
+
+ /*
+ * First thing to do is to identify how many regions
+ * the requested region overlaps.
+ * If the flags match, combine all these overlapping
+ * regions into a single region, and remove the merged
+ * regions.
+ */
+ while (idx <= lmb_rgn_lst->count - 1) {
+ rgnbase = rgn[idx].base;
+ rgnsize = rgn[idx].size;
+
+ if (lmb_addrs_overlap(base, size, rgnbase,
+ rgnsize)) {
+ if (rgn[idx].flags != LMB_NONE)
+ return -1;
+ rgn_cnt++;
+ idx_end = idx;
+ }
+ idx++;
+ }
+
+ /* The merged region's base and size */
+ rgnbase = rgn[idx_start].base;
+ mergebase = min(base, rgnbase);
+ rgnend = rgn[idx_end].base + rgn[idx_end].size;
+ mergeend = max(rgnend, (base + size));
+
+ rgn[idx_start].base = mergebase;
+ rgn[idx_start].size = mergeend - mergebase;
+
+ /* Now remove the merged regions */
+ while (--rgn_cnt)
+ lmb_remove_region(lmb_rgn_lst, idx_start + 1);
+
+ return 0;
}
-/* This routine called with relocation disabled. */
-static long lmb_add_region_flags(struct lmb_region *rgn, phys_addr_t base,
+/**
+ * lmb_add_region_flags() - Add an lmb region to the given list
+ * @lmb_rgn_lst: LMB list to which region is to be added(free/used)
+ * @base: Start address of the region
+ * @size: Size of the region to be added
+ * @flags: Attributes of the LMB region
+ *
+ * Add a region of memory to the list. If the region does not exist, add
+ * it to the list. Depending on the attributes of the region to be added,
+ * the function might resize an already existing region or coalesce two
+ * adjacent regions.
+ *
+ *
+ * Returns: 0 if the region addition successful, -1 on failure
+ */
+static long lmb_add_region_flags(struct alist *lmb_rgn_lst, phys_addr_t base,
phys_size_t size, enum lmb_flags flags)
{
unsigned long coalesced = 0;
- long adjacent, i;
+ long ret, i;
+ struct lmb_region *rgn = lmb_rgn_lst->data;
- if (rgn->cnt == 0) {
- rgn->region[0].base = base;
- rgn->region[0].size = size;
- rgn->region[0].flags = flags;
- rgn->cnt = 1;
- return 0;
- }
+ if (alist_err(lmb_rgn_lst))
+ return -1;
/* First try and coalesce this LMB with another. */
- for (i = 0; i < rgn->cnt; i++) {
- phys_addr_t rgnbase = rgn->region[i].base;
- phys_size_t rgnsize = rgn->region[i].size;
- phys_size_t rgnflags = rgn->region[i].flags;
+ for (i = 0; i < lmb_rgn_lst->count; i++) {
+ phys_addr_t rgnbase = rgn[i].base;
+ phys_size_t rgnsize = rgn[i].size;
+ phys_size_t rgnflags = rgn[i].flags;
phys_addr_t end = base + size - 1;
phys_addr_t rgnend = rgnbase + rgnsize - 1;
if (rgnbase <= base && end <= rgnend) {
@@ -282,119 +397,127 @@ static long lmb_add_region_flags(struct lmb_region *rgn, phys_addr_t base,
return -1; /* regions with new flags */
}
- adjacent = lmb_addrs_adjacent(base, size, rgnbase, rgnsize);
- if (adjacent > 0) {
+ ret = lmb_addrs_adjacent(base, size, rgnbase, rgnsize);
+ if (ret > 0) {
if (flags != rgnflags)
break;
- rgn->region[i].base -= size;
- rgn->region[i].size += size;
+ rgn[i].base -= size;
+ rgn[i].size += size;
coalesced++;
break;
- } else if (adjacent < 0) {
+ } else if (ret < 0) {
if (flags != rgnflags)
break;
- rgn->region[i].size += size;
+ rgn[i].size += size;
coalesced++;
break;
} else if (lmb_addrs_overlap(base, size, rgnbase, rgnsize)) {
- /* regions overlap */
- return -1;
+ if (flags == LMB_NONE) {
+ ret = lmb_resize_regions(lmb_rgn_lst, i, base,
+ size);
+ if (ret < 0)
+ return -1;
+
+ coalesced++;
+ break;
+ } else {
+ return -1;
+ }
}
}
- if (i < rgn->cnt - 1 && rgn->region[i].flags == rgn->region[i + 1].flags) {
- if (lmb_regions_adjacent(rgn, i, i + 1)) {
- lmb_coalesce_regions(rgn, i, i + 1);
- coalesced++;
- } else if (lmb_regions_overlap(rgn, i, i + 1)) {
- /* fix overlapping area */
- lmb_fix_over_lap_regions(rgn, i, i + 1);
- coalesced++;
+ if (lmb_rgn_lst->count && i < lmb_rgn_lst->count - 1) {
+ rgn = lmb_rgn_lst->data;
+ if (rgn[i].flags == rgn[i + 1].flags) {
+ if (lmb_regions_adjacent(lmb_rgn_lst, i, i + 1)) {
+ lmb_coalesce_regions(lmb_rgn_lst, i, i + 1);
+ coalesced++;
+ } else if (lmb_regions_overlap(lmb_rgn_lst, i, i + 1)) {
+ /* fix overlapping area */
+ lmb_fix_over_lap_regions(lmb_rgn_lst, i, i + 1);
+ coalesced++;
+ }
}
}
if (coalesced)
return coalesced;
- if (rgn->cnt >= rgn->max)
+
+ if (alist_full(lmb_rgn_lst) &&
+ !alist_expand_by(lmb_rgn_lst, lmb_rgn_lst->alloc))
return -1;
+ rgn = lmb_rgn_lst->data;
/* Couldn't coalesce the LMB, so add it to the sorted table. */
- for (i = rgn->cnt-1; i >= 0; i--) {
- if (base < rgn->region[i].base) {
- rgn->region[i + 1].base = rgn->region[i].base;
- rgn->region[i + 1].size = rgn->region[i].size;
- rgn->region[i + 1].flags = rgn->region[i].flags;
+ for (i = lmb_rgn_lst->count; i >= 0; i--) {
+ if (i && base < rgn[i - 1].base) {
+ rgn[i] = rgn[i - 1];
} else {
- rgn->region[i + 1].base = base;
- rgn->region[i + 1].size = size;
- rgn->region[i + 1].flags = flags;
+ rgn[i].base = base;
+ rgn[i].size = size;
+ rgn[i].flags = flags;
break;
}
}
- if (base < rgn->region[0].base) {
- rgn->region[0].base = base;
- rgn->region[0].size = size;
- rgn->region[0].flags = flags;
- }
-
- rgn->cnt++;
+ lmb_rgn_lst->count++;
return 0;
}
-static long lmb_add_region(struct lmb_region *rgn, phys_addr_t base,
+static long lmb_add_region(struct alist *lmb_rgn_lst, phys_addr_t base,
phys_size_t size)
{
- return lmb_add_region_flags(rgn, base, size, LMB_NONE);
+ return lmb_add_region_flags(lmb_rgn_lst, base, size, LMB_NONE);
}
/* This routine may be called with relocation disabled. */
-long lmb_add(struct lmb *lmb, phys_addr_t base, phys_size_t size)
+long lmb_add(phys_addr_t base, phys_size_t size)
{
- struct lmb_region *_rgn = &(lmb->memory);
+ struct alist *lmb_rgn_lst = &lmb.free_mem;
- return lmb_add_region(_rgn, base, size);
+ return lmb_add_region(lmb_rgn_lst, base, size);
}
-long lmb_free(struct lmb *lmb, phys_addr_t base, phys_size_t size)
+long lmb_free(phys_addr_t base, phys_size_t size)
{
- struct lmb_region *rgn = &(lmb->reserved);
+ struct lmb_region *rgn;
+ struct alist *lmb_rgn_lst = &lmb.used_mem;
phys_addr_t rgnbegin, rgnend;
phys_addr_t end = base + size - 1;
int i;
rgnbegin = rgnend = 0; /* supress gcc warnings */
-
+ rgn = lmb_rgn_lst->data;
/* Find the region where (base, size) belongs to */
- for (i = 0; i < rgn->cnt; i++) {
- rgnbegin = rgn->region[i].base;
- rgnend = rgnbegin + rgn->region[i].size - 1;
+ for (i = 0; i < lmb_rgn_lst->count; i++) {
+ rgnbegin = rgn[i].base;
+ rgnend = rgnbegin + rgn[i].size - 1;
if ((rgnbegin <= base) && (end <= rgnend))
break;
}
/* Didn't find the region */
- if (i == rgn->cnt)
+ if (i == lmb_rgn_lst->count)
return -1;
/* Check to see if we are removing entire region */
if ((rgnbegin == base) && (rgnend == end)) {
- lmb_remove_region(rgn, i);
+ lmb_remove_region(lmb_rgn_lst, i);
return 0;
}
/* Check to see if region is matching at the front */
if (rgnbegin == base) {
- rgn->region[i].base = end + 1;
- rgn->region[i].size -= size;
+ rgn[i].base = end + 1;
+ rgn[i].size -= size;
return 0;
}
/* Check to see if the region is matching at the end */
if (rgnend == end) {
- rgn->region[i].size -= size;
+ rgn[i].size -= size;
return 0;
}
@@ -402,55 +525,37 @@ long lmb_free(struct lmb *lmb, phys_addr_t base, phys_size_t size)
* We need to split the entry - adjust the current one to the
* beginging of the hole and add the region after hole.
*/
- rgn->region[i].size = base - rgn->region[i].base;
- return lmb_add_region_flags(rgn, end + 1, rgnend - end,
- rgn->region[i].flags);
+ rgn[i].size = base - rgn[i].base;
+ return lmb_add_region_flags(lmb_rgn_lst, end + 1, rgnend - end,
+ rgn[i].flags);
}
-long lmb_reserve_flags(struct lmb *lmb, phys_addr_t base, phys_size_t size,
- enum lmb_flags flags)
+long lmb_reserve_flags(phys_addr_t base, phys_size_t size, enum lmb_flags flags)
{
- struct lmb_region *_rgn = &(lmb->reserved);
+ struct alist *lmb_rgn_lst = &lmb.used_mem;
- return lmb_add_region_flags(_rgn, base, size, flags);
+ return lmb_add_region_flags(lmb_rgn_lst, base, size, flags);
}
-long lmb_reserve(struct lmb *lmb, phys_addr_t base, phys_size_t size)
+long lmb_reserve(phys_addr_t base, phys_size_t size)
{
- return lmb_reserve_flags(lmb, base, size, LMB_NONE);
+ return lmb_reserve_flags(base, size, LMB_NONE);
}
-static long lmb_overlaps_region(struct lmb_region *rgn, phys_addr_t base,
+static long lmb_overlaps_region(struct alist *lmb_rgn_lst, phys_addr_t base,
phys_size_t size)
{
unsigned long i;
+ struct lmb_region *rgn = lmb_rgn_lst->data;
- for (i = 0; i < rgn->cnt; i++) {
- phys_addr_t rgnbase = rgn->region[i].base;
- phys_size_t rgnsize = rgn->region[i].size;
+ for (i = 0; i < lmb_rgn_lst->count; i++) {
+ phys_addr_t rgnbase = rgn[i].base;
+ phys_size_t rgnsize = rgn[i].size;
if (lmb_addrs_overlap(base, size, rgnbase, rgnsize))
break;
}
- return (i < rgn->cnt) ? i : -1;
-}
-
-phys_addr_t lmb_alloc(struct lmb *lmb, phys_size_t size, ulong align)
-{
- return lmb_alloc_base(lmb, size, align, LMB_ALLOC_ANYWHERE);
-}
-
-phys_addr_t lmb_alloc_base(struct lmb *lmb, phys_size_t size, ulong align, phys_addr_t max_addr)
-{
- phys_addr_t alloc;
-
- alloc = __lmb_alloc_base(lmb, size, align, max_addr);
-
- if (alloc == 0)
- printf("ERROR: Failed to allocate 0x%lx bytes below 0x%lx.\n",
- (ulong)size, (ulong)max_addr);
-
- return alloc;
+ return (i < lmb_rgn_lst->count) ? i : -1;
}
static phys_addr_t lmb_align_down(phys_addr_t addr, phys_size_t size)
@@ -458,15 +563,18 @@ static phys_addr_t lmb_align_down(phys_addr_t addr, phys_size_t size)
return addr & ~(size - 1);
}
-phys_addr_t __lmb_alloc_base(struct lmb *lmb, phys_size_t size, ulong align, phys_addr_t max_addr)
+static phys_addr_t __lmb_alloc_base(phys_size_t size, ulong align,
+ phys_addr_t max_addr, enum lmb_flags flags)
{
long i, rgn;
phys_addr_t base = 0;
phys_addr_t res_base;
+ struct lmb_region *lmb_used = lmb.used_mem.data;
+ struct lmb_region *lmb_memory = lmb.free_mem.data;
- for (i = lmb->memory.cnt - 1; i >= 0; i--) {
- phys_addr_t lmbbase = lmb->memory.region[i].base;
- phys_size_t lmbsize = lmb->memory.region[i].size;
+ for (i = lmb.free_mem.count - 1; i >= 0; i--) {
+ phys_addr_t lmbbase = lmb_memory[i].base;
+ phys_size_t lmbsize = lmb_memory[i].size;
if (lmbsize < size)
continue;
@@ -482,15 +590,16 @@ phys_addr_t __lmb_alloc_base(struct lmb *lmb, phys_size_t size, ulong align, phy
continue;
while (base && lmbbase <= base) {
- rgn = lmb_overlaps_region(&lmb->reserved, base, size);
+ rgn = lmb_overlaps_region(&lmb.used_mem, base, size);
if (rgn < 0) {
/* This area isn't reserved, take it */
- if (lmb_add_region(&lmb->reserved, base,
- size) < 0)
+ if (lmb_add_region_flags(&lmb.used_mem, base,
+ size, flags) < 0)
return 0;
return base;
}
- res_base = lmb->reserved.region[rgn].base;
+
+ res_base = lmb_used[rgn].base;
if (res_base < size)
break;
base = lmb_align_down(res_base - size, align);
@@ -499,83 +608,177 @@ phys_addr_t __lmb_alloc_base(struct lmb *lmb, phys_size_t size, ulong align, phy
return 0;
}
-/*
- * Try to allocate a specific address range: must be in defined memory but not
- * reserved
- */
-phys_addr_t lmb_alloc_addr(struct lmb *lmb, phys_addr_t base, phys_size_t size)
+phys_addr_t lmb_alloc(phys_size_t size, ulong align)
+{
+ return lmb_alloc_base(size, align, LMB_ALLOC_ANYWHERE);
+}
+
+phys_addr_t lmb_alloc_base(phys_size_t size, ulong align, phys_addr_t max_addr)
+{
+ phys_addr_t alloc;
+
+ alloc = __lmb_alloc_base(size, align, max_addr, LMB_NONE);
+
+ if (alloc == 0)
+ printf("ERROR: Failed to allocate 0x%lx bytes below 0x%lx.\n",
+ (ulong)size, (ulong)max_addr);
+
+ return alloc;
+}
+
+static phys_addr_t __lmb_alloc_addr(phys_addr_t base, phys_size_t size,
+ enum lmb_flags flags)
{
long rgn;
+ struct lmb_region *lmb_memory = lmb.free_mem.data;
/* Check if the requested address is in one of the memory regions */
- rgn = lmb_overlaps_region(&lmb->memory, base, size);
+ rgn = lmb_overlaps_region(&lmb.free_mem, base, size);
if (rgn >= 0) {
/*
* Check if the requested end address is in the same memory
* region we found.
*/
- if (lmb_addrs_overlap(lmb->memory.region[rgn].base,
- lmb->memory.region[rgn].size,
+ if (lmb_addrs_overlap(lmb_memory[rgn].base,
+ lmb_memory[rgn].size,
base + size - 1, 1)) {
/* ok, reserve the memory */
- if (lmb_reserve(lmb, base, size) >= 0)
+ if (lmb_reserve_flags(base, size, flags) >= 0)
return base;
}
}
+
return 0;
}
+/*
+ * Try to allocate a specific address range: must be in defined memory but not
+ * reserved
+ */
+phys_addr_t lmb_alloc_addr(phys_addr_t base, phys_size_t size)
+{
+ return __lmb_alloc_addr(base, size, LMB_NONE);
+}
+
/* Return number of bytes from a given address that are free */
-phys_size_t lmb_get_free_size(struct lmb *lmb, phys_addr_t addr)
+phys_size_t lmb_get_free_size(phys_addr_t addr)
{
int i;
long rgn;
+ struct lmb_region *lmb_used = lmb.used_mem.data;
+ struct lmb_region *lmb_memory = lmb.free_mem.data;
/* check if the requested address is in the memory regions */
- rgn = lmb_overlaps_region(&lmb->memory, addr, 1);
+ rgn = lmb_overlaps_region(&lmb.free_mem, addr, 1);
if (rgn >= 0) {
- for (i = 0; i < lmb->reserved.cnt; i++) {
- if (addr < lmb->reserved.region[i].base) {
+ for (i = 0; i < lmb.used_mem.count; i++) {
+ if (addr < lmb_used[i].base) {
/* first reserved range > requested address */
- return lmb->reserved.region[i].base - addr;
+ return lmb_used[i].base - addr;
}
- if (lmb->reserved.region[i].base +
- lmb->reserved.region[i].size > addr) {
+ if (lmb_used[i].base +
+ lmb_used[i].size > addr) {
/* requested addr is in this reserved range */
return 0;
}
}
/* if we come here: no reserved ranges above requested addr */
- return lmb->memory.region[lmb->memory.cnt - 1].base +
- lmb->memory.region[lmb->memory.cnt - 1].size - addr;
+ return lmb_memory[lmb.free_mem.count - 1].base +
+ lmb_memory[lmb.free_mem.count - 1].size - addr;
}
return 0;
}
-int lmb_is_reserved_flags(struct lmb *lmb, phys_addr_t addr, int flags)
+int lmb_is_reserved_flags(phys_addr_t addr, int flags)
{
int i;
+ struct lmb_region *lmb_used = lmb.used_mem.data;
- for (i = 0; i < lmb->reserved.cnt; i++) {
- phys_addr_t upper = lmb->reserved.region[i].base +
- lmb->reserved.region[i].size - 1;
- if ((addr >= lmb->reserved.region[i].base) && (addr <= upper))
- return (lmb->reserved.region[i].flags & flags) == flags;
+ for (i = 0; i < lmb.used_mem.count; i++) {
+ phys_addr_t upper = lmb_used[i].base +
+ lmb_used[i].size - 1;
+ if (addr >= lmb_used[i].base && addr <= upper)
+ return (lmb_used[i].flags & flags) == flags;
}
return 0;
}
-int lmb_is_reserved(struct lmb *lmb, phys_addr_t addr)
+static int lmb_setup(void)
{
- return lmb_is_reserved_flags(lmb, addr, LMB_NONE);
+ bool ret;
+
+ ret = alist_init(&lmb.free_mem, sizeof(struct lmb_region),
+ (uint)LMB_ALIST_INITIAL_SIZE);
+ if (!ret) {
+ log_debug("Unable to initialise the list for LMB free memory\n");
+ return -ENOMEM;
+ }
+
+ ret = alist_init(&lmb.used_mem, sizeof(struct lmb_region),
+ (uint)LMB_ALIST_INITIAL_SIZE);
+ if (!ret) {
+ log_debug("Unable to initialise the list for LMB used memory\n");
+ return -ENOMEM;
+ }
+
+ return 0;
}
-__weak void board_lmb_reserve(struct lmb *lmb)
+/**
+ * lmb_init() - Initialise the LMB module
+ *
+ * Initialise the LMB lists needed for keeping the memory map. There
+ * are two lists, in form of alloced list data structure. One for the
+ * available memory, and one for the used memory. Initialise the two
+ * lists as part of board init. Add memory to the available memory
+ * list and reserve common areas by adding them to the used memory
+ * list.
+ *
+ * Return: 0 on success, -ve on error
+ */
+int lmb_init(void)
{
- /* please define platform specific board_lmb_reserve() */
+ int ret;
+
+ ret = lmb_setup();
+ if (ret) {
+ log_info("Unable to init LMB\n");
+ return ret;
+ }
+
+ lmb_add_memory();
+
+ /* Reserve the U-Boot image region once U-Boot has relocated */
+ if (spl_phase() == PHASE_SPL)
+ lmb_reserve_common_spl();
+ else if (spl_phase() == PHASE_BOARD_R)
+ lmb_reserve_common((void *)gd->fdt_blob);
+
+ return 0;
+}
+
+#if CONFIG_IS_ENABLED(UNIT_TEST)
+struct lmb *lmb_get(void)
+{
+ return &lmb;
+}
+
+int lmb_push(struct lmb *store)
+{
+ int ret;
+
+ *store = lmb;
+ ret = lmb_setup();
+ if (ret)
+ return ret;
+
+ return 0;
}
-__weak void arch_lmb_reserve(struct lmb *lmb)
+void lmb_pop(struct lmb *store)
{
- /* please define platform specific arch_lmb_reserve() */
+ alist_uninit(&lmb.free_mem);
+ alist_uninit(&lmb.used_mem);
+ lmb = *store;
}
+#endif /* UNIT_TEST */
diff --git a/lib/strto.c b/lib/strto.c
index 5157332d6c1..f83ac67c666 100644
--- a/lib/strto.c
+++ b/lib/strto.c
@@ -236,12 +236,14 @@ const char **str_to_list(const char *instr)
return NULL;
/* count the number of space-separated strings */
- for (count = *str != '\0', p = str; *p; p++) {
+ for (count = 0, p = str; *p; p++) {
if (*p == ' ') {
count++;
*p = '\0';
}
}
+ if (p != str && p[-1])
+ count++;
/* allocate the pointer array, allowing for a NULL terminator */
ptr = calloc(count + 1, sizeof(char *));
diff --git a/lib/uuid.c b/lib/uuid.c
index dfa2320ba26..11b86ffb02e 100644
--- a/lib/uuid.c
+++ b/lib/uuid.c
@@ -7,21 +7,35 @@
* Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
*/
-#define LOG_CATEGOT LOGC_CORE
-
+#ifndef USE_HOSTCC
#include <command.h>
#include <efi_api.h>
#include <env.h>
#include <rand.h>
#include <time.h>
-#include <uuid.h>
-#include <linux/ctype.h>
-#include <errno.h>
#include <asm/io.h>
#include <part_efi.h>
#include <malloc.h>
#include <dm/uclass.h>
#include <rng.h>
+#include <linux/ctype.h>
+#include <hexdump.h>
+#else
+#include <stdarg.h>
+#include <stdint.h>
+#include <eficapsule.h>
+#include <ctype.h>
+#endif
+#include <linux/types.h>
+#include <errno.h>
+#include <linux/kconfig.h>
+#include <u-boot/uuid.h>
+#include <u-boot/sha1.h>
+
+#ifdef USE_HOSTCC
+/* polyfill hextoul to avoid pulling in strto.c */
+#define hextoul(cp, endp) strtoul(cp, endp, 16)
+#endif
int uuid_str_valid(const char *uuid)
{
@@ -51,6 +65,7 @@ static const struct {
const char *string;
efi_guid_t guid;
} list_guid[] = {
+#ifndef USE_HOSTCC
#ifdef CONFIG_PARTITION_TYPE_GUID
{"system", PARTITION_SYSTEM_GUID},
{"mbr", LEGACY_MBR_PARTITION_GUID},
@@ -231,6 +246,7 @@ static const struct {
{ "EFI_MEM_STATUS_CODE_REC", EFI_MEM_STATUS_CODE_REC },
{ "EFI_GUID_EFI_ACPI1", EFI_GUID_EFI_ACPI1 },
#endif
+#endif /* !USE_HOSTCC */
};
int uuid_guid_get_bin(const char *guid_str, unsigned char *guid_bin)
@@ -266,7 +282,6 @@ int uuid_str_to_bin(const char *uuid_str, unsigned char *uuid_bin,
uint64_t tmp64;
if (!uuid_str_valid(uuid_str)) {
- log_debug("not valid\n");
#ifdef CONFIG_PARTITION_TYPE_GUID
if (!uuid_guid_get_bin(uuid_str, uuid_bin))
return 0;
@@ -297,7 +312,7 @@ int uuid_str_to_bin(const char *uuid_str, unsigned char *uuid_bin,
tmp16 = cpu_to_be16(hextoul(uuid_str + 19, NULL));
memcpy(uuid_bin + 8, &tmp16, 2);
- tmp64 = cpu_to_be64(simple_strtoull(uuid_str + 24, NULL, 16));
+ tmp64 = cpu_to_be64(hextoul(uuid_str + 24, NULL));
memcpy(uuid_bin + 10, (char *)&tmp64 + 2, 6);
return 0;
@@ -305,9 +320,9 @@ int uuid_str_to_bin(const char *uuid_str, unsigned char *uuid_bin,
int uuid_str_to_le_bin(const char *uuid_str, unsigned char *uuid_bin)
{
- u16 tmp16;
- u32 tmp32;
- u64 tmp64;
+ uint16_t tmp16;
+ uint32_t tmp32;
+ uint64_t tmp64;
if (!uuid_str_valid(uuid_str) || !uuid_bin)
return -EINVAL;
@@ -324,7 +339,7 @@ int uuid_str_to_le_bin(const char *uuid_str, unsigned char *uuid_bin)
tmp16 = cpu_to_le16(hextoul(uuid_str + 19, NULL));
memcpy(uuid_bin + 8, &tmp16, 2);
- tmp64 = cpu_to_le64(simple_strtoull(uuid_str + 24, NULL, 16));
+ tmp64 = cpu_to_le64(hextoul(uuid_str + 24, NULL));
memcpy(uuid_bin + 10, &tmp64, 6);
return 0;
@@ -333,11 +348,11 @@ int uuid_str_to_le_bin(const char *uuid_str, unsigned char *uuid_bin)
void uuid_bin_to_str(const unsigned char *uuid_bin, char *uuid_str,
int str_format)
{
- const u8 uuid_char_order[UUID_BIN_LEN] = {0, 1, 2, 3, 4, 5, 6, 7, 8,
+ const uint8_t uuid_char_order[UUID_BIN_LEN] = {0, 1, 2, 3, 4, 5, 6, 7, 8,
9, 10, 11, 12, 13, 14, 15};
- const u8 guid_char_order[UUID_BIN_LEN] = {3, 2, 1, 0, 5, 4, 7, 6, 8,
+ const uint8_t guid_char_order[UUID_BIN_LEN] = {3, 2, 1, 0, 5, 4, 7, 6, 8,
9, 10, 11, 12, 13, 14, 15};
- const u8 *char_order;
+ const uint8_t *char_order;
const char *format;
int i;
@@ -369,6 +384,57 @@ void uuid_bin_to_str(const unsigned char *uuid_bin, char *uuid_str,
}
}
+static void configure_uuid(struct uuid *uuid, unsigned char version)
+{
+ uint16_t tmp;
+
+ /* Configure variant/version bits */
+ tmp = be16_to_cpu(uuid->time_hi_and_version);
+ tmp = (tmp & ~UUID_VERSION_MASK) | (version << UUID_VERSION_SHIFT);
+ uuid->time_hi_and_version = cpu_to_be16(tmp);
+
+ uuid->clock_seq_hi_and_reserved &= ~UUID_VARIANT_MASK;
+ uuid->clock_seq_hi_and_reserved |= (UUID_VARIANT << UUID_VARIANT_SHIFT);
+}
+
+void gen_v5_guid(const struct uuid *namespace, struct efi_guid *guid, ...)
+{
+ sha1_context ctx;
+ va_list args;
+ const uint8_t *data;
+ uint32_t *tmp32;
+ uint16_t *tmp16;
+ uint8_t hash[SHA1_SUM_LEN];
+
+ sha1_starts(&ctx);
+ /* Hash the namespace UUID as salt */
+ sha1_update(&ctx, (unsigned char *)namespace, UUID_BIN_LEN);
+ va_start(args, guid);
+
+ while ((data = va_arg(args, const uint8_t *))) {
+ unsigned int len = va_arg(args, size_t);
+
+ sha1_update(&ctx, data, len);
+ }
+
+ va_end(args);
+ sha1_finish(&ctx, hash);
+
+ /* Truncate the hash into output UUID, it is already big endian */
+ memcpy(guid, hash, sizeof(*guid));
+
+ configure_uuid((struct uuid *)guid, 5);
+
+ /* Make little endian */
+ tmp32 = (uint32_t *)&guid->b[0];
+ *tmp32 = cpu_to_le32(be32_to_cpu(*tmp32));
+ tmp16 = (uint16_t *)&guid->b[4];
+ *tmp16 = cpu_to_le16(be16_to_cpu(*tmp16));
+ tmp16 = (uint16_t *)&guid->b[6];
+ *tmp16 = cpu_to_le16(be16_to_cpu(*tmp16));
+}
+
+#ifndef USE_HOSTCC
#if defined(CONFIG_RANDOM_UUID) || defined(CONFIG_CMD_UUID)
void gen_rand_uuid(unsigned char *uuid_bin)
{
@@ -395,13 +461,7 @@ void gen_rand_uuid(unsigned char *uuid_bin)
for (i = 0; i < 4; i++)
ptr[i] = rand();
- clrsetbits_be16(&uuid->time_hi_and_version,
- UUID_VERSION_MASK,
- UUID_VERSION << UUID_VERSION_SHIFT);
-
- clrsetbits_8(&uuid->clock_seq_hi_and_reserved,
- UUID_VARIANT_MASK,
- UUID_VARIANT << UUID_VARIANT_SHIFT);
+ configure_uuid(uuid, UUID_VERSION);
memcpy(uuid_bin, uuid, 16);
}
@@ -458,3 +518,4 @@ U_BOOT_CMD(guid, CONFIG_SYS_MAXARGS, 1, do_uuid,
);
#endif /* CONFIG_CMD_UUID */
#endif /* CONFIG_RANDOM_UUID || CONFIG_CMD_UUID */
+#endif /* !USE_HOSTCC */
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index cfd1f1914ed..e5802866632 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -18,7 +18,7 @@
#include <div64.h>
#include <hexdump.h>
#include <stdarg.h>
-#include <uuid.h>
+#include <u-boot/uuid.h>
#include <stdio.h>
#include <vsprintf.h>
#include <linux/ctype.h>