Blame SOURCES/0302-mm-Allow-dynamically-requesting-additional-memory-re.patch

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