131 lines
4.5 KiB
Diff
131 lines
4.5 KiB
Diff
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|||
|
From: Patrick Steinhardt <ps@pks.im>
|
|||
|
Date: Thu, 21 Apr 2022 15:24:18 +1000
|
|||
|
Subject: [PATCH] mm: Allow dynamically requesting additional memory regions
|
|||
|
|
|||
|
Currently, all platforms will set up their heap on initialization of the
|
|||
|
platform code. While this works mostly fine, it poses some limitations
|
|||
|
on memory management on us. Most notably, allocating big chunks of
|
|||
|
memory in the gigabyte range would require us to pre-request this many
|
|||
|
bytes from the firmware and add it to the heap from the beginning on
|
|||
|
some platforms like EFI. As this isn't needed for most configurations,
|
|||
|
it is inefficient and may even negatively impact some usecases when,
|
|||
|
e.g., chainloading. Nonetheless, allocating big chunks of memory is
|
|||
|
required sometimes, where one example is the upcoming support for the
|
|||
|
Argon2 key derival function in LUKS2.
|
|||
|
|
|||
|
In order to avoid pre-allocating big chunks of memory, this commit
|
|||
|
implements a runtime mechanism to add more pages to the system. When
|
|||
|
a given allocation cannot be currently satisfied, we'll call a given
|
|||
|
callback set up by the platform's own memory management subsystem,
|
|||
|
asking it to add a memory area with at least "n" bytes. If this
|
|||
|
succeeds, we retry searching for a valid memory region, which should
|
|||
|
now succeed.
|
|||
|
|
|||
|
If this fails, we try asking for "n" bytes, possibly spread across
|
|||
|
multiple regions, in hopes that region merging means that we end up
|
|||
|
with enough memory for things to work out.
|
|||
|
|
|||
|
Signed-off-by: Patrick Steinhardt <ps@pks.im>
|
|||
|
Signed-off-by: Daniel Axtens <dja@axtens.net>
|
|||
|
Tested-by: Stefan Berger <stefanb@linux.ibm.com>
|
|||
|
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
|
|||
|
Tested-by: Patrick Steinhardt <ps@pks.im>
|
|||
|
(cherry picked from commit 887f98f0db43e33fba4ec1f85e42fae1185700bc)
|
|||
|
---
|
|||
|
grub-core/kern/mm.c | 30 ++++++++++++++++++++++++++++++
|
|||
|
include/grub/mm.h | 18 ++++++++++++++++++
|
|||
|
2 files changed, 48 insertions(+)
|
|||
|
|
|||
|
diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c
|
|||
|
index 1825dc8289..f2e27f263b 100644
|
|||
|
--- a/grub-core/kern/mm.c
|
|||
|
+++ b/grub-core/kern/mm.c
|
|||
|
@@ -28,6 +28,9 @@
|
|||
|
- multiple regions may be used as free space. They may not be
|
|||
|
contiguous.
|
|||
|
|
|||
|
+ - if existing regions are insufficient to satisfy an allocation, a new
|
|||
|
+ region can be requested from firmware.
|
|||
|
+
|
|||
|
Regions are managed by a singly linked list, and the meta information is
|
|||
|
stored in the beginning of each region. Space after the meta information
|
|||
|
is used to allocate memory.
|
|||
|
@@ -81,6 +84,7 @@
|
|||
|
|
|||
|
|
|||
|
grub_mm_region_t grub_mm_base;
|
|||
|
+grub_mm_add_region_func_t grub_mm_add_region_fn;
|
|||
|
|
|||
|
/* Get a header from the pointer PTR, and set *P and *R to a pointer
|
|||
|
to the header and a pointer to its region, respectively. PTR must
|
|||
|
@@ -444,6 +448,32 @@ grub_memalign (grub_size_t align, grub_size_t size)
|
|||
|
count++;
|
|||
|
goto again;
|
|||
|
|
|||
|
+ case 1:
|
|||
|
+ /* Request additional pages, contiguous */
|
|||
|
+ count++;
|
|||
|
+
|
|||
|
+ if (grub_mm_add_region_fn != NULL &&
|
|||
|
+ grub_mm_add_region_fn (size, GRUB_MM_ADD_REGION_CONSECUTIVE) == GRUB_ERR_NONE)
|
|||
|
+ goto again;
|
|||
|
+
|
|||
|
+ /* fallthrough */
|
|||
|
+
|
|||
|
+ case 2:
|
|||
|
+ /* Request additional pages, anything at all */
|
|||
|
+ count++;
|
|||
|
+
|
|||
|
+ if (grub_mm_add_region_fn != NULL)
|
|||
|
+ {
|
|||
|
+ /*
|
|||
|
+ * Try again even if this fails, in case it was able to partially
|
|||
|
+ * satisfy the request
|
|||
|
+ */
|
|||
|
+ grub_mm_add_region_fn (size, GRUB_MM_ADD_REGION_NONE);
|
|||
|
+ goto again;
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ /* fallthrough */
|
|||
|
+
|
|||
|
default:
|
|||
|
break;
|
|||
|
}
|
|||
|
diff --git a/include/grub/mm.h b/include/grub/mm.h
|
|||
|
index d81623d226..7c6f925ffd 100644
|
|||
|
--- a/include/grub/mm.h
|
|||
|
+++ b/include/grub/mm.h
|
|||
|
@@ -20,6 +20,7 @@
|
|||
|
#ifndef GRUB_MM_H
|
|||
|
#define GRUB_MM_H 1
|
|||
|
|
|||
|
+#include <grub/err.h>
|
|||
|
#include <grub/types.h>
|
|||
|
#include <grub/symbol.h>
|
|||
|
#include <grub/err.h>
|
|||
|
@@ -29,6 +30,23 @@
|
|||
|
# define NULL ((void *) 0)
|
|||
|
#endif
|
|||
|
|
|||
|
+#define GRUB_MM_ADD_REGION_NONE 0
|
|||
|
+#define GRUB_MM_ADD_REGION_CONSECUTIVE (1 << 0)
|
|||
|
+
|
|||
|
+/*
|
|||
|
+ * Function used to request memory regions of `grub_size_t` bytes. The second
|
|||
|
+ * parameter is a bitfield of `GRUB_MM_ADD_REGION` flags.
|
|||
|
+ */
|
|||
|
+typedef grub_err_t (*grub_mm_add_region_func_t) (grub_size_t, unsigned int);
|
|||
|
+
|
|||
|
+/*
|
|||
|
+ * Set this function pointer to enable adding memory-regions at runtime in case
|
|||
|
+ * a memory allocation cannot be satisfied with existing regions.
|
|||
|
+ */
|
|||
|
+#ifndef GRUB_MACHINE_EMU
|
|||
|
+extern grub_mm_add_region_func_t EXPORT_VAR(grub_mm_add_region_fn);
|
|||
|
+#endif
|
|||
|
+
|
|||
|
void grub_mm_init_region (void *addr, grub_size_t size);
|
|||
|
void *EXPORT_FUNC(grub_calloc) (grub_size_t nmemb, grub_size_t size);
|
|||
|
void *EXPORT_FUNC(grub_malloc) (grub_size_t size);
|