mail archive of the barebox mailing list
 help / color / mirror / Atom feed
From: Ahmad Fatoum <a.fatoum@pengutronix.de>
To: barebox@lists.infradead.org
Cc: Ahmad Fatoum <a.fatoum@pengutronix.de>
Subject: [PATCH v1 06/54] efi: loader: add pool allocator
Date: Thu, 18 Dec 2025 11:37:26 +0100	[thread overview]
Message-ID: <20251218111242.1527495-7-a.fatoum@pengutronix.de> (raw)
In-Reply-To: <20251218111242.1527495-1-a.fatoum@pengutronix.de>

In addition to the AllocatePages EFI boot service, there is also
AllocatePool, which allows allocating a number of bytes.

Make things easy to us and just map it to AllocatePages with an header
that holds the size to support the API.

Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
 efi/loader/Makefile     |   2 +-
 efi/loader/pool_alloc.c | 205 ++++++++++++++++++++++++++++++++++++++++
 include/efi/loader.h    |  10 ++
 3 files changed, 216 insertions(+), 1 deletion(-)
 create mode 100644 efi/loader/pool_alloc.c

diff --git a/efi/loader/Makefile b/efi/loader/Makefile
index dea1e06c18cf..0475cfc7452f 100644
--- a/efi/loader/Makefile
+++ b/efi/loader/Makefile
@@ -1,3 +1,3 @@
 # SPDX-License-Identifier: GPL-2.0
 
-obj-y += memory.o
+obj-y += memory.o pool_alloc.o
diff --git a/efi/loader/pool_alloc.c b/efi/loader/pool_alloc.c
new file mode 100644
index 000000000000..be10dd77e643
--- /dev/null
+++ b/efi/loader/pool_alloc.c
@@ -0,0 +1,205 @@
+// SPDX-License-Identifier: GPL-2.0+
+// SPDX-FileCopyrightText: 2016 Alexander Graf
+// SPDX-Comment: Origin-URL: https://github.com/u-boot/u-boot/blob/aa703a816a62deb876a1e77ccff030a7cc60f344/lib/efi_loader/efi_memory.c
+
+#define pr_fmt(fmt) "efi-loader: pool: " fmt
+
+#include <efi/memory.h>
+#include <efi/loader.h>
+#include <efi/error.h>
+#include <linux/printk.h>
+#include <linux/minmax.h>
+#include <init.h>
+#include <memory.h>
+#include <linux/list_sort.h>
+#include <linux/sizes.h>
+#include <dma.h>
+
+/* Magic number identifying memory allocated from pool */
+#define EFI_ALLOC_POOL_MAGIC 0x1fe67ddf6491caa2
+
+/**
+ * struct efi_pool_allocation - memory block allocated from pool
+ *
+ * @num_pages:	number of pages allocated
+ * @checksum:	checksum
+ * @data:	allocated pool memory
+ *
+ * Each UEFI AllocatePool() request is serviced as a separate
+ * (multiple) page allocation. We have to track the number of pages
+ * to be able to free the correct amount later.
+ *
+ * The checksum calculated in function checksum() is used in FreePool() to avoid
+ * freeing memory not allocated by AllocatePool() and duplicate freeing.
+ *
+ * EFI requires 8 byte alignment for pool allocations, so we can
+ * prepend each allocation with these header fields.
+ */
+struct efi_pool_allocation {
+	u64 num_pages;
+	u64 checksum;
+	char data[] __aligned(ARCH_DMA_MINALIGN);
+};
+
+/**
+ * checksum() - calculate checksum for memory allocated from pool
+ *
+ * @alloc:	allocation header
+ * Return:	checksum, always non-zero
+ */
+static u64 checksum(struct efi_pool_allocation *alloc)
+{
+	u64 addr = (uintptr_t)alloc;
+	u64 ret = (addr >> 32) ^ (addr << 32) ^ alloc->num_pages ^
+		  EFI_ALLOC_POOL_MAGIC;
+	if (!ret)
+		++ret;
+	return ret;
+}
+
+/**
+ * efi_allocate_pool - allocate memory from pool
+ *
+ * @pool_type:	type of the pool from which memory is to be allocated
+ * @size:	number of bytes to be allocated
+ * @buffer:	allocated memory
+ * @name:	name for informational purposes
+ * Return:	status code
+ */
+efi_status_t efi_allocate_pool(enum efi_memory_type pool_type, efi_uintn_t size,
+			       void **buffer, const char *name)
+{
+	efi_status_t r;
+	u64 addr;
+	struct efi_pool_allocation *alloc;
+	u64 num_pages = efi_size_in_pages(size +
+					  sizeof(struct efi_pool_allocation));
+
+	if (!buffer)
+		return EFI_INVALID_PARAMETER;
+
+	if (size == 0) {
+		*buffer = NULL;
+		return EFI_SUCCESS;
+	}
+
+	r = efi_allocate_pages(EFI_ALLOCATE_ANY_PAGES, pool_type, num_pages,
+			       &addr, name);
+	if (r == EFI_SUCCESS) {
+		alloc = (struct efi_pool_allocation *)(uintptr_t)addr;
+		alloc->num_pages = num_pages;
+		alloc->checksum = checksum(alloc);
+		*buffer = alloc->data;
+	}
+
+	return r;
+}
+
+/**
+ * efi_alloc() - allocate boot services data pool memory
+ *
+ * Allocate memory from pool and zero it out.
+ *
+ * @size:	number of bytes to allocate
+ * @name:		name for informational purposes
+ * Return:	pointer to allocated memory or NULL
+ */
+void *efi_alloc(size_t size, const char *name)
+{
+	void *buf;
+
+	if (efi_allocate_pool(EFI_BOOT_SERVICES_DATA, size, &buf, name) !=
+	    EFI_SUCCESS) {
+		pr_err("out of memory\n");
+		return NULL;
+	}
+	memset(buf, 0, size);
+
+	return buf;
+}
+
+/**
+ * efi_realloc() - reallocate boot services data pool memory
+ *
+ * Reallocate memory from pool for a new size and copy the data from old one.
+ *
+ * @ptr:	pointer to old buffer
+ * @size:	number of bytes to allocate
+ * @name:	name for informational purposes
+ * Return:	EFI status to indicate success or not
+ */
+efi_status_t efi_realloc(void **ptr, size_t size, const char *name)
+{
+	void *new_ptr;
+	struct efi_pool_allocation *alloc;
+	u64 num_pages = efi_size_in_pages(size +
+					  sizeof(struct efi_pool_allocation));
+	size_t old_size;
+
+	if (!*ptr) {
+		*ptr = efi_alloc(size, name);
+		if (*ptr)
+			return EFI_SUCCESS;
+		return EFI_OUT_OF_RESOURCES;
+	}
+
+	alloc = container_of(*ptr, struct efi_pool_allocation, data);
+
+	/* Check that this memory was allocated by efi_allocate_pool() */
+	if (((uintptr_t)alloc & EFI_PAGE_MASK) ||
+	    alloc->checksum != checksum(alloc)) {
+		pr_err("%s: illegal realloc 0x%p\n", __func__, *ptr);
+		return EFI_INVALID_PARAMETER;
+	}
+
+	/* Don't realloc. The actual size in pages is the same. */
+	if (alloc->num_pages == num_pages)
+		return EFI_SUCCESS;
+
+	old_size = alloc->num_pages * EFI_PAGE_SIZE -
+		sizeof(struct efi_pool_allocation);
+
+	new_ptr = efi_alloc(size, name);
+	if (!new_ptr)
+		return EFI_OUT_OF_RESOURCES;
+
+	/* copy old data to new alloced buffer */
+	memcpy(new_ptr, *ptr, min(size, old_size));
+
+	/* free the old buffer */
+	efi_free_pool(*ptr);
+
+	*ptr = new_ptr;
+
+	return EFI_SUCCESS;
+}
+
+/**
+ * efi_free_pool() - free memory from pool
+ *
+ * @buffer:	start of memory to be freed
+ * Return:	status code
+ */
+efi_status_t efi_free_pool(void *buffer)
+{
+	efi_status_t ret;
+	struct efi_pool_allocation *alloc;
+
+	if (!buffer)
+		return EFI_INVALID_PARAMETER;
+
+	alloc = container_of(buffer, struct efi_pool_allocation, data);
+
+	/* Check that this memory was allocated by efi_allocate_pool() */
+	if (((uintptr_t)alloc & EFI_PAGE_MASK) ||
+	    alloc->checksum != checksum(alloc)) {
+		pr_err("%s: illegal free 0x%p\n", __func__, buffer);
+		return EFI_INVALID_PARAMETER;
+	}
+	/* Avoid double free */
+	alloc->checksum = 0;
+
+	ret = efi_free_pages((uintptr_t)alloc, alloc->num_pages);
+
+	return ret;
+}
diff --git a/include/efi/loader.h b/include/efi/loader.h
index a5359f07f125..4a5670bcf672 100644
--- a/include/efi/loader.h
+++ b/include/efi/loader.h
@@ -13,6 +13,10 @@
 /* Key identifying current memory map */
 extern efi_uintn_t efi_memory_map_key;
 
+/* Allocate boot service data pool memory */
+void *efi_alloc(size_t len, const char *name);
+/* Reallocate boot service data pool memory */
+efi_status_t efi_realloc(void **ptr, size_t len, const char *name);
 /* Allocate pages on the specified alignment */
 void *efi_alloc_aligned_pages(u64 len, int memory_type, size_t align,
 			      const char *name);
@@ -23,6 +27,12 @@ efi_status_t efi_allocate_pages(enum efi_allocate_type type,
 				const char *name);
 /* EFI memory free function. */
 efi_status_t efi_free_pages(uint64_t memory, efi_uintn_t pages);
+/* EFI memory allocator for small allocations */
+efi_status_t efi_allocate_pool(enum efi_memory_type pool_type,
+			       efi_uintn_t size, void **buffer,
+			       const char *name);
+/* EFI pool memory free function. */
+efi_status_t efi_free_pool(void *buffer);
 /* Returns the EFI memory map */
 efi_status_t efi_get_memory_map(efi_uintn_t *memory_map_size,
 				struct efi_memory_desc *memory_map,
-- 
2.47.3




  parent reply	other threads:[~2025-12-18 11:13 UTC|newest]

Thread overview: 55+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-12-18 10:37 [PATCH v1 00/54] efi: implement EFI loader support in barebox Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 01/54] efi: payload: initrd: fix type mismatch on 32-bit Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 02/54] efi: loader: switch over event/memory key type to efi_uintn_t Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 03/54] lib: vsprintf: print human-readable EFI GUIDs with %pUs Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 04/54] fs: fat: don't duplicate dentries when resolving differently cased paths Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 05/54] efi: loader: add memory accounting Ahmad Fatoum
2025-12-18 10:37 ` Ahmad Fatoum [this message]
2025-12-18 10:37 ` [PATCH v1 07/54] efi: types: add EFI_RUNTIME_SECTION Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 08/54] resource: assign memory banks a default type and attr Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 09/54] ARM: lds: add EFI runtime service section Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 10/54] ARM: move needed assembly routines into EFI runtime section Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 11/54] crypto: crc32: implement position independent CRC32 Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 12/54] efi: loader: add support for tracing calls back into UEFI Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 13/54] efi: loader: add table utility functions Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 14/54] lib: add charset helpers Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 15/54] efi: loader: add object handling API Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 16/54] efi: loader: add devicepath support Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 17/54] efi: loader: add debug support Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 18/54] efi: loader: add boot services support Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 19/54] efi: loader: add support for runtime services before ExitBootServices Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 20/54] efi: loader: setup root node Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 21/54] efi: loader: add watchdog support Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 22/54] efi: loader: move PE implementation out of common code Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 23/54] efi: loader: protocol: add file protocol support Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 24/54] efi: loader: protocol: add Block IO support Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 25/54] efi: loader: protocol: implement efi_file_from_path Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 26/54] efi: loader: boot: implement LoadImage BootService Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 27/54] efi: loader: add EFI load option handling Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 28/54] efi: loader: protocol: add graphical output protocol support Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 29/54] efi: loader: protocol: add console support Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 30/54] efi: loader: protocol: add HII support Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 31/54] efi: loader: protocol: add unicode collation support Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 32/54] efi: loader: protocol: add random number generator protocol Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 33/54] efi: loader: protocol: add device_path_utilities Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 34/54] efi: loader: support formatting only first device path node to text Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 35/54] efi: loader: protocol: add efi_device_path_to_text support Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 36/54] restart: allow drivers to register runtime restart handler Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 37/54] poweroff: allow drivers to register runtime poweroff handler Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 38/54] ARM: psci: client: register runtime service " Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 39/54] ARM: psci: client: register runtime service restart handler Ahmad Fatoum
2025-12-18 10:38 ` [PATCH v1 40/54] hardening: disable some features when EFI runtime support is enabled Ahmad Fatoum
2025-12-18 10:38 ` [PATCH v1 41/54] filetype: add new filetype for efi-stubbed ARM zImages Ahmad Fatoum
2025-12-18 10:38 ` [PATCH v1 42/54] bootm: add global.bootm.efi toggle Ahmad Fatoum
2025-12-18 10:38 ` [PATCH v1 43/54] efi: loader: add ESP boot entry provider Ahmad Fatoum
2025-12-18 10:38 ` [PATCH v1 44/54] efi: loader: add rudimentary EFI boot manager Ahmad Fatoum
2025-12-18 10:38 ` [PATCH v1 45/54] efi: loader: implement bootm handler Ahmad Fatoum
2025-12-18 10:38 ` [PATCH v1 46/54] efi: runtime: add EFI variable support Ahmad Fatoum
2025-12-18 10:38 ` [PATCH v1 47/54] efi: loader: populate OsIndicationsSupported/PlatformLang variables Ahmad Fatoum
2025-12-18 10:38 ` [PATCH v1 48/54] ARM: don't disable MMU when EFI booting Ahmad Fatoum
2025-12-18 10:38 ` [PATCH v1 49/54] efi: runtime: add runtime service support after ExitBootServices Ahmad Fatoum
2025-12-18 10:38 ` [PATCH v1 50/54] efi: runtime: add relocation check Ahmad Fatoum
2025-12-18 10:38 ` [PATCH v1 51/54] efi: loader: CONFIG_EFI_RT_VOLATILE_STORE Ahmad Fatoum
2025-12-18 10:38 ` [PATCH v1 52/54] efi: loader: support ExitBootServices Ahmad Fatoum
2025-12-18 10:38 ` [PATCH v1 53/54] efi: loader: pass along SMBIOS table Ahmad Fatoum
2025-12-18 10:38 ` [PATCH v1 54/54] ARM: configs: add multi_v7/8_efiloader_defconfig Ahmad Fatoum

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20251218111242.1527495-7-a.fatoum@pengutronix.de \
    --to=a.fatoum@pengutronix.de \
    --cc=barebox@lists.infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox