Pull allocator improvements from upstream
Signed-off-by: Robbie Harwood <rharwood@redhat.com>
This commit is contained in:
parent
217ae25d88
commit
7be2bf00c3
@ -1,105 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Julian Andres Klode <julian.klode@canonical.com>
|
||||
Date: Tue, 6 Dec 2022 15:29:13 +0100
|
||||
Subject: [PATCH] Allow internal grub allocations over 4GB
|
||||
|
||||
Previous commits introduced support for loading kernel and
|
||||
initrd over 4GB if necessary, but only for the actual loading.
|
||||
|
||||
Grub also needs to load large initrds into memory as part of
|
||||
the verifiers framework.
|
||||
|
||||
Increase the maximum allocation limit to the maximum usable
|
||||
address, and at the same time, to preserve existing behavior,
|
||||
define a 4G limit that behaves like the old one.
|
||||
|
||||
Signed-off-by: Julian Andres Klode <julian.klode@canonical.com>
|
||||
(cherry picked from commit cf6516128ea03294156fc59a50ce90856bd3ebd2)
|
||||
---
|
||||
grub-core/loader/i386/efi/linux.c | 20 +++++++++++---------
|
||||
include/grub/x86_64/efi/memory.h | 2 +-
|
||||
2 files changed, 12 insertions(+), 10 deletions(-)
|
||||
|
||||
diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
|
||||
index 9854b0defa..0cc1c0d9a5 100644
|
||||
--- a/grub-core/loader/i386/efi/linux.c
|
||||
+++ b/grub-core/loader/i386/efi/linux.c
|
||||
@@ -31,6 +31,8 @@
|
||||
#include <grub/tpm.h>
|
||||
#include <grub/safemath.h>
|
||||
|
||||
+#define GRUB_EFI_4G_ALLOCATION_ADDRESS 0x7fffffff
|
||||
+
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
static grub_dl_t my_mod;
|
||||
@@ -79,17 +81,17 @@ static struct allocation_choice max_addresses[] =
|
||||
/* the kernel overrides this one with pref_address and
|
||||
* GRUB_EFI_ALLOCATE_ADDRESS */
|
||||
[KERNEL_PREF_ADDRESS] =
|
||||
- { KERNEL_MEM, GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS },
|
||||
+ { KERNEL_MEM, GRUB_EFI_4G_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS },
|
||||
/* If the flag in params is set, this one gets changed to be above 4GB. */
|
||||
[KERNEL_4G_LIMIT] =
|
||||
- { KERNEL_MEM, GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS },
|
||||
+ { KERNEL_MEM, GRUB_EFI_4G_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS },
|
||||
/* this one is always below 4GB, which we still *prefer* even if the flag
|
||||
* is set. */
|
||||
[KERNEL_NO_LIMIT] =
|
||||
- { KERNEL_MEM, GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS },
|
||||
+ { KERNEL_MEM, GRUB_EFI_4G_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS },
|
||||
/* this is for the initrd */
|
||||
[INITRD_MAX_ADDRESS] =
|
||||
- { INITRD_MEM, GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS },
|
||||
+ { INITRD_MEM, GRUB_EFI_4G_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS },
|
||||
{ NO_MEM, 0, 0 }
|
||||
};
|
||||
static struct allocation_choice saved_addresses[sizeof(max_addresses) / sizeof(max_addresses[0])];
|
||||
@@ -190,7 +192,7 @@ grub_linuxefi_unload (void *data)
|
||||
cmd_initrdefi->data = 0;
|
||||
grub_free (context);
|
||||
|
||||
- max_addresses[INITRD_MAX_ADDRESS].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS;
|
||||
+ max_addresses[INITRD_MAX_ADDRESS].addr = GRUB_EFI_4G_ALLOCATION_ADDRESS;
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
@@ -506,13 +508,13 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
|
||||
*/
|
||||
save_addresses();
|
||||
grub_dprintf ("linux", "lh->pref_address: %p\n", (void *)(grub_addr_t)lh->pref_address);
|
||||
- if (lh->pref_address < (grub_uint64_t)GRUB_EFI_MAX_ALLOCATION_ADDRESS)
|
||||
+ if (lh->pref_address < (grub_uint64_t)GRUB_EFI_4G_ALLOCATION_ADDRESS)
|
||||
{
|
||||
max_addresses[KERNEL_PREF_ADDRESS].addr = lh->pref_address;
|
||||
max_addresses[KERNEL_PREF_ADDRESS].alloc_type = GRUB_EFI_ALLOCATE_ADDRESS;
|
||||
}
|
||||
- max_addresses[KERNEL_4G_LIMIT].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS;
|
||||
- max_addresses[KERNEL_NO_LIMIT].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS;
|
||||
+ max_addresses[KERNEL_4G_LIMIT].addr = GRUB_EFI_4G_ALLOCATION_ADDRESS;
|
||||
+ max_addresses[KERNEL_NO_LIMIT].addr = GRUB_EFI_4G_ALLOCATION_ADDRESS;
|
||||
kernel_size = lh->init_size;
|
||||
grub_dprintf ("linux", "Trying to allocate kernel mem\n");
|
||||
kernel_mem = kernel_alloc (KERNEL_MEM, kernel_size,
|
||||
@@ -564,7 +566,7 @@ fail:
|
||||
|
||||
grub_dl_unref (my_mod);
|
||||
|
||||
- max_addresses[INITRD_MAX_ADDRESS].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS;
|
||||
+ max_addresses[INITRD_MAX_ADDRESS].addr = GRUB_EFI_4G_ALLOCATION_ADDRESS;
|
||||
|
||||
if (lh)
|
||||
kernel_free (cmdline, lh->cmdline_size + 1);
|
||||
diff --git a/include/grub/x86_64/efi/memory.h b/include/grub/x86_64/efi/memory.h
|
||||
index e81cfb3221..547e3f82f8 100644
|
||||
--- a/include/grub/x86_64/efi/memory.h
|
||||
+++ b/include/grub/x86_64/efi/memory.h
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
#if defined (__code_model_large__)
|
||||
#define GRUB_EFI_MAX_USABLE_ADDRESS __UINTPTR_MAX__
|
||||
-#define GRUB_EFI_MAX_ALLOCATION_ADDRESS 0x7fffffff
|
||||
+#define GRUB_EFI_MAX_ALLOCATION_ADDRESS GRUB_EFI_MAX_USABLE_ADDRESS
|
||||
#else
|
||||
#define GRUB_EFI_MAX_USABLE_ADDRESS 0x7fffffff
|
||||
#define GRUB_EFI_MAX_ALLOCATION_ADDRESS GRUB_EFI_MAX_USABLE_ADDRESS
|
183
0302-mm-Clarify-grub_real_malloc.patch
Normal file
183
0302-mm-Clarify-grub_real_malloc.patch
Normal file
@ -0,0 +1,183 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Axtens <dja@axtens.net>
|
||||
Date: Thu, 25 Nov 2021 02:22:46 +1100
|
||||
Subject: [PATCH] mm: Clarify grub_real_malloc()
|
||||
|
||||
When iterating through the singly linked list of free blocks,
|
||||
grub_real_malloc() uses p and q for the current and previous blocks
|
||||
respectively. This isn't super clear, so swap to using prev and cur.
|
||||
|
||||
This makes another quirk more obvious. The comment at the top of
|
||||
grub_real_malloc() might lead you to believe that the function will
|
||||
allocate from *first if there is space in that block.
|
||||
|
||||
It actually doesn't do that, and it can't do that with the current
|
||||
data structures. If we used up all of *first, we would need to change
|
||||
the ->next of the previous block to point to *first->next, but we
|
||||
can't do that because it's a singly linked list and we don't have
|
||||
access to *first's previous block.
|
||||
|
||||
What grub_real_malloc() actually does is set *first to the initial
|
||||
previous block, and *first->next is the block we try to allocate
|
||||
from. That allows us to keep all the data structures consistent.
|
||||
|
||||
Document that.
|
||||
|
||||
Signed-off-by: Daniel Axtens <dja@axtens.net>
|
||||
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
|
||||
(cherry picked from commit 246ad6a44c281bb13486ddea0a26bb661db73106)
|
||||
---
|
||||
grub-core/kern/mm.c | 76 +++++++++++++++++++++++++++++------------------------
|
||||
1 file changed, 41 insertions(+), 35 deletions(-)
|
||||
|
||||
diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c
|
||||
index d8c8377578..fb20e93acf 100644
|
||||
--- a/grub-core/kern/mm.c
|
||||
+++ b/grub-core/kern/mm.c
|
||||
@@ -178,13 +178,20 @@ grub_mm_init_region (void *addr, grub_size_t size)
|
||||
}
|
||||
|
||||
/* Allocate the number of units N with the alignment ALIGN from the ring
|
||||
- buffer starting from *FIRST. ALIGN must be a power of two. Both N and
|
||||
- ALIGN are in units of GRUB_MM_ALIGN. Return a non-NULL if successful,
|
||||
- otherwise return NULL. */
|
||||
+ * buffer given in *FIRST. ALIGN must be a power of two. Both N and
|
||||
+ * ALIGN are in units of GRUB_MM_ALIGN. Return a non-NULL if successful,
|
||||
+ * otherwise return NULL.
|
||||
+ *
|
||||
+ * Note: because in certain circumstances we need to adjust the ->next
|
||||
+ * pointer of the previous block, we iterate over the singly linked
|
||||
+ * list with the pair (prev, cur). *FIRST is our initial previous, and
|
||||
+ * *FIRST->next is our initial current pointer. So we will actually
|
||||
+ * allocate from *FIRST->next first and *FIRST itself last.
|
||||
+ */
|
||||
static void *
|
||||
grub_real_malloc (grub_mm_header_t *first, grub_size_t n, grub_size_t align)
|
||||
{
|
||||
- grub_mm_header_t p, q;
|
||||
+ grub_mm_header_t cur, prev;
|
||||
|
||||
/* When everything is allocated side effect is that *first will have alloc
|
||||
magic marked, meaning that there is no room in this region. */
|
||||
@@ -192,24 +199,24 @@ grub_real_malloc (grub_mm_header_t *first, grub_size_t n, grub_size_t align)
|
||||
return 0;
|
||||
|
||||
/* Try to search free slot for allocation in this memory region. */
|
||||
- for (q = *first, p = q->next; ; q = p, p = p->next)
|
||||
+ for (prev = *first, cur = prev->next; ; prev = cur, cur = cur->next)
|
||||
{
|
||||
grub_off_t extra;
|
||||
|
||||
- extra = ((grub_addr_t) (p + 1) >> GRUB_MM_ALIGN_LOG2) & (align - 1);
|
||||
+ extra = ((grub_addr_t) (cur + 1) >> GRUB_MM_ALIGN_LOG2) & (align - 1);
|
||||
if (extra)
|
||||
extra = align - extra;
|
||||
|
||||
- if (! p)
|
||||
+ if (! cur)
|
||||
grub_fatal ("null in the ring");
|
||||
|
||||
- if (p->magic != GRUB_MM_FREE_MAGIC)
|
||||
- grub_fatal ("free magic is broken at %p: 0x%x", p, p->magic);
|
||||
+ if (cur->magic != GRUB_MM_FREE_MAGIC)
|
||||
+ grub_fatal ("free magic is broken at %p: 0x%x", cur, cur->magic);
|
||||
|
||||
- if (p->size >= n + extra)
|
||||
+ if (cur->size >= n + extra)
|
||||
{
|
||||
- extra += (p->size - extra - n) & (~(align - 1));
|
||||
- if (extra == 0 && p->size == n)
|
||||
+ extra += (cur->size - extra - n) & (~(align - 1));
|
||||
+ if (extra == 0 && cur->size == n)
|
||||
{
|
||||
/* There is no special alignment requirement and memory block
|
||||
is complete match.
|
||||
@@ -222,9 +229,9 @@ grub_real_malloc (grub_mm_header_t *first, grub_size_t n, grub_size_t align)
|
||||
| alloc, size=n | |
|
||||
+---------------+ v
|
||||
*/
|
||||
- q->next = p->next;
|
||||
+ prev->next = cur->next;
|
||||
}
|
||||
- else if (align == 1 || p->size == n + extra)
|
||||
+ else if (align == 1 || cur->size == n + extra)
|
||||
{
|
||||
/* There might be alignment requirement, when taking it into
|
||||
account memory block fits in.
|
||||
@@ -241,23 +248,22 @@ grub_real_malloc (grub_mm_header_t *first, grub_size_t n, grub_size_t align)
|
||||
| alloc, size=n | |
|
||||
+---------------+ v
|
||||
*/
|
||||
-
|
||||
- p->size -= n;
|
||||
- p += p->size;
|
||||
+ cur->size -= n;
|
||||
+ cur += cur->size;
|
||||
}
|
||||
else if (extra == 0)
|
||||
{
|
||||
grub_mm_header_t r;
|
||||
|
||||
- r = p + extra + n;
|
||||
+ r = cur + extra + n;
|
||||
r->magic = GRUB_MM_FREE_MAGIC;
|
||||
- r->size = p->size - extra - n;
|
||||
- r->next = p->next;
|
||||
- q->next = r;
|
||||
+ r->size = cur->size - extra - n;
|
||||
+ r->next = cur->next;
|
||||
+ prev->next = r;
|
||||
|
||||
- if (q == p)
|
||||
+ if (prev == cur)
|
||||
{
|
||||
- q = r;
|
||||
+ prev = r;
|
||||
r->next = r;
|
||||
}
|
||||
}
|
||||
@@ -284,32 +290,32 @@ grub_real_malloc (grub_mm_header_t *first, grub_size_t n, grub_size_t align)
|
||||
*/
|
||||
grub_mm_header_t r;
|
||||
|
||||
- r = p + extra + n;
|
||||
+ r = cur + extra + n;
|
||||
r->magic = GRUB_MM_FREE_MAGIC;
|
||||
- r->size = p->size - extra - n;
|
||||
- r->next = p;
|
||||
+ r->size = cur->size - extra - n;
|
||||
+ r->next = cur;
|
||||
|
||||
- p->size = extra;
|
||||
- q->next = r;
|
||||
- p += extra;
|
||||
+ cur->size = extra;
|
||||
+ prev->next = r;
|
||||
+ cur += extra;
|
||||
}
|
||||
|
||||
- p->magic = GRUB_MM_ALLOC_MAGIC;
|
||||
- p->size = n;
|
||||
+ cur->magic = GRUB_MM_ALLOC_MAGIC;
|
||||
+ cur->size = n;
|
||||
|
||||
/* Mark find as a start marker for next allocation to fasten it.
|
||||
This will have side effect of fragmenting memory as small
|
||||
pieces before this will be un-used. */
|
||||
/* So do it only for chunks under 64K. */
|
||||
if (n < (0x8000 >> GRUB_MM_ALIGN_LOG2)
|
||||
- || *first == p)
|
||||
- *first = q;
|
||||
+ || *first == cur)
|
||||
+ *first = prev;
|
||||
|
||||
- return p + 1;
|
||||
+ return cur + 1;
|
||||
}
|
||||
|
||||
/* Search was completed without result. */
|
||||
- if (p == *first)
|
||||
+ if (cur == *first)
|
||||
break;
|
||||
}
|
||||
|
@ -0,0 +1,32 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Axtens <dja@axtens.net>
|
||||
Date: Thu, 25 Nov 2021 02:22:47 +1100
|
||||
Subject: [PATCH] mm: grub_real_malloc(): Make small allocs comment match code
|
||||
|
||||
Small allocations move the region's *first pointer. The comment
|
||||
says that this happens for allocations under 64K. The code says
|
||||
it's for allocations under 32K. Commit 45bf8b3a7549 changed the
|
||||
code intentionally: make the comment match.
|
||||
|
||||
Fixes: 45bf8b3a7549 (* grub-core/kern/mm.c (grub_real_malloc): Decrease cut-off of moving the)
|
||||
|
||||
Signed-off-by: Daniel Axtens <dja@axtens.net>
|
||||
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
|
||||
(cherry picked from commit a847895a8d000bdf27ad4d4326f883a0eed769ca)
|
||||
---
|
||||
grub-core/kern/mm.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c
|
||||
index fb20e93acf..db7e0b2a5b 100644
|
||||
--- a/grub-core/kern/mm.c
|
||||
+++ b/grub-core/kern/mm.c
|
||||
@@ -306,7 +306,7 @@ grub_real_malloc (grub_mm_header_t *first, grub_size_t n, grub_size_t align)
|
||||
/* Mark find as a start marker for next allocation to fasten it.
|
||||
This will have side effect of fragmenting memory as small
|
||||
pieces before this will be un-used. */
|
||||
- /* So do it only for chunks under 64K. */
|
||||
+ /* So do it only for chunks under 32K. */
|
||||
if (n < (0x8000 >> GRUB_MM_ALIGN_LOG2)
|
||||
|| *first == cur)
|
||||
*first = prev;
|
120
0304-mm-Document-grub_free.patch
Normal file
120
0304-mm-Document-grub_free.patch
Normal file
@ -0,0 +1,120 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Axtens <dja@axtens.net>
|
||||
Date: Thu, 25 Nov 2021 02:22:48 +1100
|
||||
Subject: [PATCH] mm: Document grub_free()
|
||||
|
||||
The grub_free() possesses a surprising number of quirks, and also
|
||||
uses single-letter variable names confusingly to iterate through
|
||||
the free list.
|
||||
|
||||
Document what's going on.
|
||||
|
||||
Use prev and cur to iterate over the free list.
|
||||
|
||||
Signed-off-by: Daniel Axtens <dja@axtens.net>
|
||||
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
|
||||
(cherry picked from commit 1f8d0b01738e49767d662d6426af3570a64565f0)
|
||||
---
|
||||
grub-core/kern/mm.c | 63 ++++++++++++++++++++++++++++++++++-------------------
|
||||
1 file changed, 41 insertions(+), 22 deletions(-)
|
||||
|
||||
diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c
|
||||
index db7e0b2a5b..0351171cf9 100644
|
||||
--- a/grub-core/kern/mm.c
|
||||
+++ b/grub-core/kern/mm.c
|
||||
@@ -446,54 +446,73 @@ grub_free (void *ptr)
|
||||
}
|
||||
else
|
||||
{
|
||||
- grub_mm_header_t q, s;
|
||||
+ grub_mm_header_t cur, prev;
|
||||
|
||||
#if 0
|
||||
- q = r->first;
|
||||
+ cur = r->first;
|
||||
do
|
||||
{
|
||||
grub_printf ("%s:%d: q=%p, q->size=0x%x, q->magic=0x%x\n",
|
||||
- GRUB_FILE, __LINE__, q, q->size, q->magic);
|
||||
- q = q->next;
|
||||
+ GRUB_FILE, __LINE__, cur, cur->size, cur->magic);
|
||||
+ cur = cur->next;
|
||||
}
|
||||
- while (q != r->first);
|
||||
+ while (cur != r->first);
|
||||
#endif
|
||||
-
|
||||
- for (s = r->first, q = s->next; q <= p || q->next >= p; s = q, q = s->next)
|
||||
+ /* Iterate over all blocks in the free ring.
|
||||
+ *
|
||||
+ * The free ring is arranged from high addresses to low
|
||||
+ * addresses, modulo wraparound.
|
||||
+ *
|
||||
+ * We are looking for a block with a higher address than p or
|
||||
+ * whose next address is lower than p.
|
||||
+ */
|
||||
+ for (prev = r->first, cur = prev->next; cur <= p || cur->next >= p;
|
||||
+ prev = cur, cur = prev->next)
|
||||
{
|
||||
- if (q->magic != GRUB_MM_FREE_MAGIC)
|
||||
- grub_fatal ("free magic is broken at %p: 0x%x", q, q->magic);
|
||||
+ if (cur->magic != GRUB_MM_FREE_MAGIC)
|
||||
+ grub_fatal ("free magic is broken at %p: 0x%x", cur, cur->magic);
|
||||
|
||||
- if (q <= q->next && (q > p || q->next < p))
|
||||
+ /* Deal with wrap-around */
|
||||
+ if (cur <= cur->next && (cur > p || cur->next < p))
|
||||
break;
|
||||
}
|
||||
|
||||
+ /* mark p as free and insert it between cur and cur->next */
|
||||
p->magic = GRUB_MM_FREE_MAGIC;
|
||||
- p->next = q->next;
|
||||
- q->next = p;
|
||||
+ p->next = cur->next;
|
||||
+ cur->next = p;
|
||||
|
||||
+ /*
|
||||
+ * If the block we are freeing can be merged with the next
|
||||
+ * free block, do that.
|
||||
+ */
|
||||
if (p->next + p->next->size == p)
|
||||
{
|
||||
p->magic = 0;
|
||||
|
||||
p->next->size += p->size;
|
||||
- q->next = p->next;
|
||||
+ cur->next = p->next;
|
||||
p = p->next;
|
||||
}
|
||||
|
||||
- r->first = q;
|
||||
+ r->first = cur;
|
||||
|
||||
- if (q == p + p->size)
|
||||
+ /* Likewise if can be merged with the preceeding free block */
|
||||
+ if (cur == p + p->size)
|
||||
{
|
||||
- q->magic = 0;
|
||||
- p->size += q->size;
|
||||
- if (q == s)
|
||||
- s = p;
|
||||
- s->next = p;
|
||||
- q = s;
|
||||
+ cur->magic = 0;
|
||||
+ p->size += cur->size;
|
||||
+ if (cur == prev)
|
||||
+ prev = p;
|
||||
+ prev->next = p;
|
||||
+ cur = prev;
|
||||
}
|
||||
|
||||
- r->first = q;
|
||||
+ /*
|
||||
+ * Set r->first such that the just free()d block is tried first.
|
||||
+ * (An allocation is tried from *first->next, and cur->next == p.)
|
||||
+ */
|
||||
+ r->first = cur;
|
||||
}
|
||||
}
|
||||
|
73
0305-mm-Document-grub_mm_init_region.patch
Normal file
73
0305-mm-Document-grub_mm_init_region.patch
Normal file
@ -0,0 +1,73 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Axtens <dja@axtens.net>
|
||||
Date: Thu, 25 Nov 2021 02:22:49 +1100
|
||||
Subject: [PATCH] mm: Document grub_mm_init_region()
|
||||
|
||||
The grub_mm_init_region() does some things that seem magical, especially
|
||||
around region merging. Make it a bit clearer.
|
||||
|
||||
Signed-off-by: Daniel Axtens <dja@axtens.net>
|
||||
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
|
||||
(cherry picked from commit 246d69b7ea619fc1e77dcc5960e37aea45a9808c)
|
||||
---
|
||||
grub-core/kern/mm.c | 31 ++++++++++++++++++++++++++++++-
|
||||
1 file changed, 30 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c
|
||||
index 0351171cf9..1cbf98c7ab 100644
|
||||
--- a/grub-core/kern/mm.c
|
||||
+++ b/grub-core/kern/mm.c
|
||||
@@ -128,23 +128,52 @@ grub_mm_init_region (void *addr, grub_size_t size)
|
||||
if (((grub_addr_t) addr + 0x1000) > ~(grub_addr_t) size)
|
||||
size = ((grub_addr_t) -0x1000) - (grub_addr_t) addr;
|
||||
|
||||
+ /* Attempt to merge this region with every existing region */
|
||||
for (p = &grub_mm_base, q = *p; q; p = &(q->next), q = *p)
|
||||
+ /*
|
||||
+ * Is the new region immediately below an existing region? That
|
||||
+ * is, is the address of the memory we're adding now (addr) + size
|
||||
+ * of the memory we're adding (size) + the bytes we couldn't use
|
||||
+ * at the start of the region we're considering (q->pre_size)
|
||||
+ * equal to the address of q? In other words, does the memory
|
||||
+ * looks like this?
|
||||
+ *
|
||||
+ * addr q
|
||||
+ * |----size-----|-q->pre_size-|<q region>|
|
||||
+ */
|
||||
if ((grub_uint8_t *) addr + size + q->pre_size == (grub_uint8_t *) q)
|
||||
{
|
||||
+ /*
|
||||
+ * Yes, we can merge the memory starting at addr into the
|
||||
+ * existing region from below. Align up addr to GRUB_MM_ALIGN
|
||||
+ * so that our new region has proper alignment.
|
||||
+ */
|
||||
r = (grub_mm_region_t) ALIGN_UP ((grub_addr_t) addr, GRUB_MM_ALIGN);
|
||||
+ /* Copy the region data across */
|
||||
*r = *q;
|
||||
+ /* Consider all the new size as pre-size */
|
||||
r->pre_size += size;
|
||||
-
|
||||
+
|
||||
+ /*
|
||||
+ * If we have enough pre-size to create a block, create a
|
||||
+ * block with it. Mark it as allocated and pass it to
|
||||
+ * grub_free (), which will sort out getting it into the free
|
||||
+ * list.
|
||||
+ */
|
||||
if (r->pre_size >> GRUB_MM_ALIGN_LOG2)
|
||||
{
|
||||
h = (grub_mm_header_t) (r + 1);
|
||||
+ /* block size is pre-size converted to cells */
|
||||
h->size = (r->pre_size >> GRUB_MM_ALIGN_LOG2);
|
||||
h->magic = GRUB_MM_ALLOC_MAGIC;
|
||||
+ /* region size grows by block size converted back to bytes */
|
||||
r->size += h->size << GRUB_MM_ALIGN_LOG2;
|
||||
+ /* adjust pre_size to be accurate */
|
||||
r->pre_size &= (GRUB_MM_ALIGN - 1);
|
||||
*p = r;
|
||||
grub_free (h + 1);
|
||||
}
|
||||
+ /* Replace the old region with the new region */
|
||||
*p = r;
|
||||
return;
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Axtens <dja@axtens.net>
|
||||
Date: Thu, 25 Nov 2021 02:22:45 +1100
|
||||
Subject: [PATCH] mm: Document GRUB internal memory management structures
|
||||
|
||||
I spent more than a trivial quantity of time figuring out pre_size and
|
||||
whether a memory region's size contains the header cell or not.
|
||||
|
||||
Document the meanings of all the properties. Hopefully now no-one else
|
||||
has to figure it out!
|
||||
|
||||
Signed-off-by: Daniel Axtens <dja@axtens.net>
|
||||
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
|
||||
(cherry picked from commit a6c5c52ccffd2674d43db25fb4baa9c528526aa0)
|
||||
---
|
||||
include/grub/mm_private.h | 28 ++++++++++++++++++++++++++++
|
||||
1 file changed, 28 insertions(+)
|
||||
|
||||
diff --git a/include/grub/mm_private.h b/include/grub/mm_private.h
|
||||
index c2c4cb1511..203533cc3d 100644
|
||||
--- a/include/grub/mm_private.h
|
||||
+++ b/include/grub/mm_private.h
|
||||
@@ -21,15 +21,27 @@
|
||||
|
||||
#include <grub/mm.h>
|
||||
|
||||
+/* For context, see kern/mm.c */
|
||||
+
|
||||
/* Magic words. */
|
||||
#define GRUB_MM_FREE_MAGIC 0x2d3c2808
|
||||
#define GRUB_MM_ALLOC_MAGIC 0x6db08fa4
|
||||
|
||||
+/* A header describing a block of memory - either allocated or free */
|
||||
typedef struct grub_mm_header
|
||||
{
|
||||
+ /*
|
||||
+ * The 'next' free block in this region's circular free list.
|
||||
+ * Only meaningful if the block is free.
|
||||
+ */
|
||||
struct grub_mm_header *next;
|
||||
+ /* The block size, not in bytes but the number of cells of
|
||||
+ * GRUB_MM_ALIGN bytes. Includes the header cell.
|
||||
+ */
|
||||
grub_size_t size;
|
||||
+ /* either free or alloc magic, depending on the block type. */
|
||||
grub_size_t magic;
|
||||
+ /* pad to cell size: see the top of kern/mm.c. */
|
||||
#if GRUB_CPU_SIZEOF_VOID_P == 4
|
||||
char padding[4];
|
||||
#elif GRUB_CPU_SIZEOF_VOID_P == 8
|
||||
@@ -48,11 +60,27 @@ typedef struct grub_mm_header
|
||||
|
||||
#define GRUB_MM_ALIGN (1 << GRUB_MM_ALIGN_LOG2)
|
||||
|
||||
+/* A region from which we can make allocations. */
|
||||
typedef struct grub_mm_region
|
||||
{
|
||||
+ /* The first free block in this region. */
|
||||
struct grub_mm_header *first;
|
||||
+
|
||||
+ /*
|
||||
+ * The next region in the linked list of regions. Regions are initially
|
||||
+ * sorted in order of increasing size, but can grow, in which case the
|
||||
+ * ordering may not be preserved.
|
||||
+ */
|
||||
struct grub_mm_region *next;
|
||||
+
|
||||
+ /*
|
||||
+ * A grub_mm_region will always be aligned to cell size. The pre-size is
|
||||
+ * the number of bytes we were given but had to skip in order to get that
|
||||
+ * alignment.
|
||||
+ */
|
||||
grub_size_t pre_size;
|
||||
+
|
||||
+ /* How many bytes are in this region? (free and allocated) */
|
||||
grub_size_t size;
|
||||
}
|
||||
*grub_mm_region_t;
|
@ -0,0 +1,56 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Axtens <dja@axtens.net>
|
||||
Date: Thu, 21 Apr 2022 15:24:14 +1000
|
||||
Subject: [PATCH] mm: Assert that we preserve header vs region alignment
|
||||
|
||||
grub_mm_region_init() does:
|
||||
|
||||
h = (grub_mm_header_t) (r + 1);
|
||||
|
||||
where h is a grub_mm_header_t and r is a grub_mm_region_t.
|
||||
|
||||
Cells are supposed to be GRUB_MM_ALIGN aligned, but while grub_mm_dump
|
||||
ensures this vs the region header, grub_mm_region_init() does not.
|
||||
|
||||
It's better to be explicit than implicit here: rather than changing
|
||||
grub_mm_region_init() to ALIGN_UP(), require that the struct is
|
||||
explicitly a multiple of the header size.
|
||||
|
||||
Signed-off-by: Daniel Axtens <dja@axtens.net>
|
||||
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
|
||||
Tested-by: Patrick Steinhardt <ps@pks.im>
|
||||
(cherry picked from commit 1df8fe66c57087eb33bd6dc69f786ed124615aa7)
|
||||
---
|
||||
include/grub/mm_private.h | 14 ++++++++++++++
|
||||
1 file changed, 14 insertions(+)
|
||||
|
||||
diff --git a/include/grub/mm_private.h b/include/grub/mm_private.h
|
||||
index 203533cc3d..a688b92a83 100644
|
||||
--- a/include/grub/mm_private.h
|
||||
+++ b/include/grub/mm_private.h
|
||||
@@ -20,6 +20,7 @@
|
||||
#define GRUB_MM_PRIVATE_H 1
|
||||
|
||||
#include <grub/mm.h>
|
||||
+#include <grub/misc.h>
|
||||
|
||||
/* For context, see kern/mm.c */
|
||||
|
||||
@@ -89,4 +90,17 @@ typedef struct grub_mm_region
|
||||
extern grub_mm_region_t EXPORT_VAR (grub_mm_base);
|
||||
#endif
|
||||
|
||||
+static inline void
|
||||
+grub_mm_size_sanity_check (void) {
|
||||
+ /* Ensure we preserve alignment when doing h = (grub_mm_header_t) (r + 1). */
|
||||
+ COMPILE_TIME_ASSERT ((sizeof (struct grub_mm_region) %
|
||||
+ sizeof (struct grub_mm_header)) == 0);
|
||||
+
|
||||
+ /*
|
||||
+ * GRUB_MM_ALIGN is supposed to represent cell size, and a mm_header is
|
||||
+ * supposed to be 1 cell.
|
||||
+ */
|
||||
+ COMPILE_TIME_ASSERT (sizeof (struct grub_mm_header) == GRUB_MM_ALIGN);
|
||||
+}
|
||||
+
|
||||
#endif
|
203
0308-mm-When-adding-a-region-merge-with-region-after-as-w.patch
Normal file
203
0308-mm-When-adding-a-region-merge-with-region-after-as-w.patch
Normal file
@ -0,0 +1,203 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Axtens <dja@axtens.net>
|
||||
Date: Thu, 21 Apr 2022 15:24:15 +1000
|
||||
Subject: [PATCH] mm: When adding a region, merge with region after as well as
|
||||
before
|
||||
|
||||
On x86_64-efi (at least) regions seem to be added from top down. The mm
|
||||
code will merge a new region with an existing region that comes
|
||||
immediately before the new region. This allows larger allocations to be
|
||||
satisfied that would otherwise be the case.
|
||||
|
||||
On powerpc-ieee1275, however, regions are added from bottom up. So if
|
||||
we add 3x 32MB regions, we can still only satisfy a 32MB allocation,
|
||||
rather than the 96MB allocation we might otherwise be able to satisfy.
|
||||
|
||||
* Define 'post_size' as being bytes lost to the end of an allocation
|
||||
due to being given weird sizes from firmware that are not multiples
|
||||
of GRUB_MM_ALIGN.
|
||||
|
||||
* Allow merging of regions immediately _after_ existing regions, not
|
||||
just before. As with the other approach, we create an allocated
|
||||
block to represent the new space and the pass it to grub_free() to
|
||||
get the metadata right.
|
||||
|
||||
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 052e6068be622ff53f1238b449c300dbd0a8abcd)
|
||||
---
|
||||
grub-core/kern/mm.c | 128 +++++++++++++++++++++++++++++-----------------
|
||||
include/grub/mm_private.h | 9 ++++
|
||||
2 files changed, 91 insertions(+), 46 deletions(-)
|
||||
|
||||
diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c
|
||||
index 1cbf98c7ab..7be33e23bf 100644
|
||||
--- a/grub-core/kern/mm.c
|
||||
+++ b/grub-core/kern/mm.c
|
||||
@@ -130,53 +130,88 @@ grub_mm_init_region (void *addr, grub_size_t size)
|
||||
|
||||
/* Attempt to merge this region with every existing region */
|
||||
for (p = &grub_mm_base, q = *p; q; p = &(q->next), q = *p)
|
||||
- /*
|
||||
- * Is the new region immediately below an existing region? That
|
||||
- * is, is the address of the memory we're adding now (addr) + size
|
||||
- * of the memory we're adding (size) + the bytes we couldn't use
|
||||
- * at the start of the region we're considering (q->pre_size)
|
||||
- * equal to the address of q? In other words, does the memory
|
||||
- * looks like this?
|
||||
- *
|
||||
- * addr q
|
||||
- * |----size-----|-q->pre_size-|<q region>|
|
||||
- */
|
||||
- if ((grub_uint8_t *) addr + size + q->pre_size == (grub_uint8_t *) q)
|
||||
- {
|
||||
- /*
|
||||
- * Yes, we can merge the memory starting at addr into the
|
||||
- * existing region from below. Align up addr to GRUB_MM_ALIGN
|
||||
- * so that our new region has proper alignment.
|
||||
- */
|
||||
- r = (grub_mm_region_t) ALIGN_UP ((grub_addr_t) addr, GRUB_MM_ALIGN);
|
||||
- /* Copy the region data across */
|
||||
- *r = *q;
|
||||
- /* Consider all the new size as pre-size */
|
||||
- r->pre_size += size;
|
||||
+ {
|
||||
+ /*
|
||||
+ * Is the new region immediately below an existing region? That
|
||||
+ * is, is the address of the memory we're adding now (addr) + size
|
||||
+ * of the memory we're adding (size) + the bytes we couldn't use
|
||||
+ * at the start of the region we're considering (q->pre_size)
|
||||
+ * equal to the address of q? In other words, does the memory
|
||||
+ * looks like this?
|
||||
+ *
|
||||
+ * addr q
|
||||
+ * |----size-----|-q->pre_size-|<q region>|
|
||||
+ */
|
||||
+ if ((grub_uint8_t *) addr + size + q->pre_size == (grub_uint8_t *) q)
|
||||
+ {
|
||||
+ /*
|
||||
+ * Yes, we can merge the memory starting at addr into the
|
||||
+ * existing region from below. Align up addr to GRUB_MM_ALIGN
|
||||
+ * so that our new region has proper alignment.
|
||||
+ */
|
||||
+ r = (grub_mm_region_t) ALIGN_UP ((grub_addr_t) addr, GRUB_MM_ALIGN);
|
||||
+ /* Copy the region data across */
|
||||
+ *r = *q;
|
||||
+ /* Consider all the new size as pre-size */
|
||||
+ r->pre_size += size;
|
||||
|
||||
- /*
|
||||
- * If we have enough pre-size to create a block, create a
|
||||
- * block with it. Mark it as allocated and pass it to
|
||||
- * grub_free (), which will sort out getting it into the free
|
||||
- * list.
|
||||
- */
|
||||
- if (r->pre_size >> GRUB_MM_ALIGN_LOG2)
|
||||
- {
|
||||
- h = (grub_mm_header_t) (r + 1);
|
||||
- /* block size is pre-size converted to cells */
|
||||
- h->size = (r->pre_size >> GRUB_MM_ALIGN_LOG2);
|
||||
- h->magic = GRUB_MM_ALLOC_MAGIC;
|
||||
- /* region size grows by block size converted back to bytes */
|
||||
- r->size += h->size << GRUB_MM_ALIGN_LOG2;
|
||||
- /* adjust pre_size to be accurate */
|
||||
- r->pre_size &= (GRUB_MM_ALIGN - 1);
|
||||
- *p = r;
|
||||
- grub_free (h + 1);
|
||||
- }
|
||||
- /* Replace the old region with the new region */
|
||||
- *p = r;
|
||||
- return;
|
||||
- }
|
||||
+ /*
|
||||
+ * If we have enough pre-size to create a block, create a
|
||||
+ * block with it. Mark it as allocated and pass it to
|
||||
+ * grub_free (), which will sort out getting it into the free
|
||||
+ * list.
|
||||
+ */
|
||||
+ if (r->pre_size >> GRUB_MM_ALIGN_LOG2)
|
||||
+ {
|
||||
+ h = (grub_mm_header_t) (r + 1);
|
||||
+ /* block size is pre-size converted to cells */
|
||||
+ h->size = (r->pre_size >> GRUB_MM_ALIGN_LOG2);
|
||||
+ h->magic = GRUB_MM_ALLOC_MAGIC;
|
||||
+ /* region size grows by block size converted back to bytes */
|
||||
+ r->size += h->size << GRUB_MM_ALIGN_LOG2;
|
||||
+ /* adjust pre_size to be accurate */
|
||||
+ r->pre_size &= (GRUB_MM_ALIGN - 1);
|
||||
+ *p = r;
|
||||
+ grub_free (h + 1);
|
||||
+ }
|
||||
+ /* Replace the old region with the new region */
|
||||
+ *p = r;
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
+ * Is the new region immediately above an existing region? That
|
||||
+ * is:
|
||||
+ * q addr
|
||||
+ * |<q region>|-q->post_size-|----size-----|
|
||||
+ */
|
||||
+ if ((grub_uint8_t *) q + sizeof (*q) + q->size + q->post_size ==
|
||||
+ (grub_uint8_t *) addr)
|
||||
+ {
|
||||
+ /*
|
||||
+ * Yes! Follow a similar pattern to above, but simpler.
|
||||
+ * Our header starts at address - post_size, which should align us
|
||||
+ * to a cell boundary.
|
||||
+ *
|
||||
+ * Cast to (void *) first to avoid the following build error:
|
||||
+ * kern/mm.c: In function ‘grub_mm_init_region’:
|
||||
+ * kern/mm.c:211:15: error: cast increases required alignment of target type [-Werror=cast-align]
|
||||
+ * 211 | h = (grub_mm_header_t) ((grub_uint8_t *) addr - q->post_size);
|
||||
+ * | ^
|
||||
+ * It is safe to do that because proper alignment is enforced in grub_mm_size_sanity_check().
|
||||
+ */
|
||||
+ h = (grub_mm_header_t)(void *) ((grub_uint8_t *) addr - q->post_size);
|
||||
+ /* our size is the allocated size plus post_size, in cells */
|
||||
+ h->size = (size + q->post_size) >> GRUB_MM_ALIGN_LOG2;
|
||||
+ h->magic = GRUB_MM_ALLOC_MAGIC;
|
||||
+ /* region size grows by block size converted back to bytes */
|
||||
+ q->size += h->size << GRUB_MM_ALIGN_LOG2;
|
||||
+ /* adjust new post_size to be accurate */
|
||||
+ q->post_size = (q->post_size + size) & (GRUB_MM_ALIGN - 1);
|
||||
+ grub_free (h + 1);
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
|
||||
/* Allocate a region from the head. */
|
||||
r = (grub_mm_region_t) ALIGN_UP ((grub_addr_t) addr, GRUB_MM_ALIGN);
|
||||
@@ -195,6 +230,7 @@ grub_mm_init_region (void *addr, grub_size_t size)
|
||||
r->first = h;
|
||||
r->pre_size = (grub_addr_t) r - (grub_addr_t) addr;
|
||||
r->size = (h->size << GRUB_MM_ALIGN_LOG2);
|
||||
+ r->post_size = size - r->size;
|
||||
|
||||
/* Find where to insert this region. Put a smaller one before bigger ones,
|
||||
to prevent fragmentation. */
|
||||
diff --git a/include/grub/mm_private.h b/include/grub/mm_private.h
|
||||
index a688b92a83..96c2d816be 100644
|
||||
--- a/include/grub/mm_private.h
|
||||
+++ b/include/grub/mm_private.h
|
||||
@@ -81,8 +81,17 @@ typedef struct grub_mm_region
|
||||
*/
|
||||
grub_size_t pre_size;
|
||||
|
||||
+ /*
|
||||
+ * Likewise, the post-size is the number of bytes we wasted at the end
|
||||
+ * of the allocation because it wasn't a multiple of GRUB_MM_ALIGN
|
||||
+ */
|
||||
+ grub_size_t post_size;
|
||||
+
|
||||
/* How many bytes are in this region? (free and allocated) */
|
||||
grub_size_t size;
|
||||
+
|
||||
+ /* pad to a multiple of cell size */
|
||||
+ char padding[3 * GRUB_CPU_SIZEOF_VOID_P];
|
||||
}
|
||||
*grub_mm_region_t;
|
||||
|
71
0309-mm-Debug-support-for-region-operations.patch
Normal file
71
0309-mm-Debug-support-for-region-operations.patch
Normal file
@ -0,0 +1,71 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Axtens <dja@axtens.net>
|
||||
Date: Thu, 21 Apr 2022 15:24:16 +1000
|
||||
Subject: [PATCH] mm: Debug support for region operations
|
||||
|
||||
This is handy for debugging. Enable with "set debug=regions".
|
||||
|
||||
Signed-off-by: Daniel Axtens <dja@axtens.net>
|
||||
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
|
||||
Tested-by: Patrick Steinhardt <ps@pks.im>
|
||||
(cherry picked from commit 8afa5ef45b797ba5d8147ceee85ac2c59dcc7f09)
|
||||
---
|
||||
grub-core/kern/mm.c | 19 ++++++++++++++++---
|
||||
1 file changed, 16 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c
|
||||
index 7be33e23bf..38bfb01df9 100644
|
||||
--- a/grub-core/kern/mm.c
|
||||
+++ b/grub-core/kern/mm.c
|
||||
@@ -115,9 +115,8 @@ grub_mm_init_region (void *addr, grub_size_t size)
|
||||
grub_mm_header_t h;
|
||||
grub_mm_region_t r, *p, q;
|
||||
|
||||
-#if 0
|
||||
- grub_printf ("Using memory for heap: start=%p, end=%p\n", addr, addr + (unsigned int) size);
|
||||
-#endif
|
||||
+ grub_dprintf ("regions", "Using memory for heap: start=%p, end=%p\n",
|
||||
+ addr, (char *) addr + (unsigned int) size);
|
||||
|
||||
/* Exclude last 4K to avoid overflows. */
|
||||
/* If addr + 0x1000 overflows then whole region is in excluded zone. */
|
||||
@@ -142,8 +141,14 @@ grub_mm_init_region (void *addr, grub_size_t size)
|
||||
* addr q
|
||||
* |----size-----|-q->pre_size-|<q region>|
|
||||
*/
|
||||
+ grub_dprintf ("regions", "Can we extend into region above?"
|
||||
+ " %p + %" PRIxGRUB_SIZE " + %" PRIxGRUB_SIZE " ?=? %p\n",
|
||||
+ (grub_uint8_t *) addr, size, q->pre_size, (grub_uint8_t *) q);
|
||||
if ((grub_uint8_t *) addr + size + q->pre_size == (grub_uint8_t *) q)
|
||||
{
|
||||
+ grub_dprintf ("regions", "Yes: extending a region: (%p -> %p) -> (%p -> %p)\n",
|
||||
+ q, (grub_uint8_t *) q + sizeof (*q) + q->size,
|
||||
+ addr, (grub_uint8_t *) q + sizeof (*q) + q->size);
|
||||
/*
|
||||
* Yes, we can merge the memory starting at addr into the
|
||||
* existing region from below. Align up addr to GRUB_MM_ALIGN
|
||||
@@ -185,9 +190,15 @@ grub_mm_init_region (void *addr, grub_size_t size)
|
||||
* q addr
|
||||
* |<q region>|-q->post_size-|----size-----|
|
||||
*/
|
||||
+ grub_dprintf ("regions", "Can we extend into region below?"
|
||||
+ " %p + %" PRIxGRUB_SIZE " + %" PRIxGRUB_SIZE " + %" PRIxGRUB_SIZE " ?=? %p\n",
|
||||
+ (grub_uint8_t *) q, sizeof(*q), q->size, q->post_size, (grub_uint8_t *) addr);
|
||||
if ((grub_uint8_t *) q + sizeof (*q) + q->size + q->post_size ==
|
||||
(grub_uint8_t *) addr)
|
||||
{
|
||||
+ grub_dprintf ("regions", "Yes: extending a region: (%p -> %p) -> (%p -> %p)\n",
|
||||
+ q, (grub_uint8_t *) q + sizeof (*q) + q->size,
|
||||
+ q, (grub_uint8_t *) addr + size);
|
||||
/*
|
||||
* Yes! Follow a similar pattern to above, but simpler.
|
||||
* Our header starts at address - post_size, which should align us
|
||||
@@ -213,6 +224,8 @@ grub_mm_init_region (void *addr, grub_size_t size)
|
||||
}
|
||||
}
|
||||
|
||||
+ grub_dprintf ("regions", "No: considering a new region at %p of size %" PRIxGRUB_SIZE "\n",
|
||||
+ addr, size);
|
||||
/* Allocate a region from the head. */
|
||||
r = (grub_mm_region_t) ALIGN_UP ((grub_addr_t) addr, GRUB_MM_ALIGN);
|
||||
|
80
0310-mm-Drop-unused-unloading-of-modules-on-OOM.patch
Normal file
80
0310-mm-Drop-unused-unloading-of-modules-on-OOM.patch
Normal file
@ -0,0 +1,80 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Patrick Steinhardt <ps@pks.im>
|
||||
Date: Thu, 21 Apr 2022 15:24:17 +1000
|
||||
Subject: [PATCH] mm: Drop unused unloading of modules on OOM
|
||||
|
||||
In grub_memalign(), there's a commented section which would allow for
|
||||
unloading of unneeded modules in case where there is not enough free
|
||||
memory available to satisfy a request. Given that this code is never
|
||||
compiled in, let's remove it together with grub_dl_unload_unneeded().
|
||||
|
||||
Signed-off-by: Patrick Steinhardt <ps@pks.im>
|
||||
Signed-off-by: Daniel Axtens <dja@axtens.net>
|
||||
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
|
||||
Tested-by: Patrick Steinhardt <ps@pks.im>
|
||||
(cherry picked from commit 139fd9b134a01e0b5fe0ebefafa7f48d1ffb6d60)
|
||||
---
|
||||
grub-core/kern/dl.c | 20 --------------------
|
||||
grub-core/kern/mm.c | 8 --------
|
||||
include/grub/dl.h | 1 -
|
||||
3 files changed, 29 deletions(-)
|
||||
|
||||
diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c
|
||||
index d5de80186f..ab9101a5ad 100644
|
||||
--- a/grub-core/kern/dl.c
|
||||
+++ b/grub-core/kern/dl.c
|
||||
@@ -998,23 +998,3 @@ grub_dl_unload (grub_dl_t mod)
|
||||
grub_free (mod);
|
||||
return 1;
|
||||
}
|
||||
-
|
||||
-/* Unload unneeded modules. */
|
||||
-void
|
||||
-grub_dl_unload_unneeded (void)
|
||||
-{
|
||||
- /* Because grub_dl_remove modifies the list of modules, this
|
||||
- implementation is tricky. */
|
||||
- grub_dl_t p = grub_dl_head;
|
||||
-
|
||||
- while (p)
|
||||
- {
|
||||
- if (grub_dl_unload (p))
|
||||
- {
|
||||
- p = grub_dl_head;
|
||||
- continue;
|
||||
- }
|
||||
-
|
||||
- p = p->next;
|
||||
- }
|
||||
-}
|
||||
diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c
|
||||
index 38bfb01df9..1825dc8289 100644
|
||||
--- a/grub-core/kern/mm.c
|
||||
+++ b/grub-core/kern/mm.c
|
||||
@@ -444,14 +444,6 @@ grub_memalign (grub_size_t align, grub_size_t size)
|
||||
count++;
|
||||
goto again;
|
||||
|
||||
-#if 0
|
||||
- case 1:
|
||||
- /* Unload unneeded modules. */
|
||||
- grub_dl_unload_unneeded ();
|
||||
- count++;
|
||||
- goto again;
|
||||
-#endif
|
||||
-
|
||||
default:
|
||||
break;
|
||||
}
|
||||
diff --git a/include/grub/dl.h b/include/grub/dl.h
|
||||
index 45ac8e339f..6bc2560bf0 100644
|
||||
--- a/include/grub/dl.h
|
||||
+++ b/include/grub/dl.h
|
||||
@@ -206,7 +206,6 @@ grub_dl_t EXPORT_FUNC(grub_dl_load) (const char *name);
|
||||
grub_dl_t grub_dl_load_core (void *addr, grub_size_t size);
|
||||
grub_dl_t EXPORT_FUNC(grub_dl_load_core_noinit) (void *addr, grub_size_t size);
|
||||
int EXPORT_FUNC(grub_dl_unload) (grub_dl_t mod);
|
||||
-extern void grub_dl_unload_unneeded (void);
|
||||
extern int EXPORT_FUNC(grub_dl_ref) (grub_dl_t mod);
|
||||
extern int EXPORT_FUNC(grub_dl_unref) (grub_dl_t mod);
|
||||
extern int EXPORT_FUNC(grub_dl_ref_count) (grub_dl_t mod);
|
130
0311-mm-Allow-dynamically-requesting-additional-memory-re.patch
Normal file
130
0311-mm-Allow-dynamically-requesting-additional-memory-re.patch
Normal file
@ -0,0 +1,130 @@
|
||||
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);
|
103
0312-kern-efi-mm-Always-request-a-fixed-number-of-pages-o.patch
Normal file
103
0312-kern-efi-mm-Always-request-a-fixed-number-of-pages-o.patch
Normal file
@ -0,0 +1,103 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Patrick Steinhardt <ps@pks.im>
|
||||
Date: Thu, 21 Apr 2022 15:24:19 +1000
|
||||
Subject: [PATCH] kern/efi/mm: Always request a fixed number of pages on init
|
||||
|
||||
When initializing the EFI memory subsystem, we will by default request
|
||||
a quarter of the available memory, bounded by a minimum/maximum value.
|
||||
Given that we're about to extend the EFI memory system to dynamically
|
||||
request additional pages from the firmware as required, this scaling of
|
||||
requested memory based on available memory will not make a lot of sense
|
||||
anymore.
|
||||
|
||||
Remove this logic as a preparatory patch such that we'll instead defer
|
||||
to the runtime memory allocator. Note that ideally, we'd want to change
|
||||
this after dynamic requesting of pages has been implemented for the EFI
|
||||
platform. But because we'll need to split up initialization of the
|
||||
memory subsystem and the request of pages from the firmware, we'd have
|
||||
to duplicate quite some logic at first only to remove it afterwards
|
||||
again. This seems quite pointless, so we instead have patches slightly
|
||||
out of order.
|
||||
|
||||
Signed-off-by: Patrick Steinhardt <ps@pks.im>
|
||||
Signed-off-by: Daniel Axtens <dja@axtens.net>
|
||||
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
|
||||
Tested-by: Patrick Steinhardt <ps@pks.im>
|
||||
(cherry picked from commit 938c3760b8c0fca759140be48307179b50107ff6)
|
||||
---
|
||||
grub-core/kern/efi/mm.c | 35 +++--------------------------------
|
||||
1 file changed, 3 insertions(+), 32 deletions(-)
|
||||
|
||||
diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c
|
||||
index e460b072e6..782a1365a1 100644
|
||||
--- a/grub-core/kern/efi/mm.c
|
||||
+++ b/grub-core/kern/efi/mm.c
|
||||
@@ -38,9 +38,8 @@
|
||||
a multiplier of 4KB. */
|
||||
#define MEMORY_MAP_SIZE 0x3000
|
||||
|
||||
-/* The minimum and maximum heap size for GRUB itself. */
|
||||
-#define MIN_HEAP_SIZE 0x100000
|
||||
-#define MAX_HEAP_SIZE (1600 * 0x100000)
|
||||
+/* The default heap size for GRUB itself in bytes. */
|
||||
+#define DEFAULT_HEAP_SIZE 0x100000
|
||||
|
||||
static void *finish_mmap_buf = 0;
|
||||
static grub_efi_uintn_t finish_mmap_size = 0;
|
||||
@@ -514,23 +513,6 @@ filter_memory_map (grub_efi_memory_descriptor_t *memory_map,
|
||||
return filtered_desc;
|
||||
}
|
||||
|
||||
-/* Return the total number of pages. */
|
||||
-static grub_efi_uint64_t
|
||||
-get_total_pages (grub_efi_memory_descriptor_t *memory_map,
|
||||
- grub_efi_uintn_t desc_size,
|
||||
- grub_efi_memory_descriptor_t *memory_map_end)
|
||||
-{
|
||||
- grub_efi_memory_descriptor_t *desc;
|
||||
- grub_efi_uint64_t total = 0;
|
||||
-
|
||||
- for (desc = memory_map;
|
||||
- desc < memory_map_end;
|
||||
- desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size))
|
||||
- total += desc->num_pages;
|
||||
-
|
||||
- return total;
|
||||
-}
|
||||
-
|
||||
/* Add memory regions. */
|
||||
static void
|
||||
add_memory_regions (grub_efi_memory_descriptor_t *memory_map,
|
||||
@@ -694,8 +676,6 @@ grub_efi_mm_init (void)
|
||||
grub_efi_memory_descriptor_t *filtered_memory_map_end;
|
||||
grub_efi_uintn_t map_size;
|
||||
grub_efi_uintn_t desc_size;
|
||||
- grub_efi_uint64_t total_pages;
|
||||
- grub_efi_uint64_t required_pages;
|
||||
int mm_status;
|
||||
|
||||
grub_nx_init ();
|
||||
@@ -737,22 +717,13 @@ grub_efi_mm_init (void)
|
||||
filtered_memory_map_end = filter_memory_map (memory_map, filtered_memory_map,
|
||||
desc_size, memory_map_end);
|
||||
|
||||
- /* By default, request a quarter of the available memory. */
|
||||
- total_pages = get_total_pages (filtered_memory_map, desc_size,
|
||||
- filtered_memory_map_end);
|
||||
- required_pages = (total_pages >> 2);
|
||||
- if (required_pages < BYTES_TO_PAGES (MIN_HEAP_SIZE))
|
||||
- required_pages = BYTES_TO_PAGES (MIN_HEAP_SIZE);
|
||||
- else if (required_pages > BYTES_TO_PAGES (MAX_HEAP_SIZE))
|
||||
- required_pages = BYTES_TO_PAGES (MAX_HEAP_SIZE);
|
||||
-
|
||||
/* Sort the filtered descriptors, so that GRUB can allocate pages
|
||||
from smaller regions. */
|
||||
sort_memory_map (filtered_memory_map, desc_size, filtered_memory_map_end);
|
||||
|
||||
/* Allocate memory regions for GRUB's memory management. */
|
||||
add_memory_regions (filtered_memory_map, desc_size,
|
||||
- filtered_memory_map_end, required_pages);
|
||||
+ filtered_memory_map_end, BYTES_TO_PAGES (DEFAULT_HEAP_SIZE));
|
||||
|
||||
#if 0
|
||||
/* For debug. */
|
@ -0,0 +1,85 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Patrick Steinhardt <ps@pks.im>
|
||||
Date: Thu, 21 Apr 2022 15:24:20 +1000
|
||||
Subject: [PATCH] kern/efi/mm: Extract function to add memory regions
|
||||
|
||||
In preparation of support for runtime-allocating additional memory
|
||||
region, this patch extracts the function to retrieve the EFI memory
|
||||
map and add a subset of it to GRUB's own memory regions.
|
||||
|
||||
Signed-off-by: Patrick Steinhardt <ps@pks.im>
|
||||
Signed-off-by: Daniel Axtens <dja@axtens.net>
|
||||
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
|
||||
Tested-by: Patrick Steinhardt <ps@pks.im>
|
||||
(cherry picked from commit 96a7ea29e3cb61b6c2302e260e8e6a6117e17fa3)
|
||||
[rharwood: backport around our nx]
|
||||
---
|
||||
grub-core/kern/efi/mm.c | 21 +++++++++++++++------
|
||||
1 file changed, 15 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c
|
||||
index 782a1365a1..a1d3b51fe6 100644
|
||||
--- a/grub-core/kern/efi/mm.c
|
||||
+++ b/grub-core/kern/efi/mm.c
|
||||
@@ -667,8 +667,8 @@ grub_nx_init (void)
|
||||
}
|
||||
}
|
||||
|
||||
-void
|
||||
-grub_efi_mm_init (void)
|
||||
+static grub_err_t
|
||||
+grub_efi_mm_add_regions (grub_size_t required_bytes)
|
||||
{
|
||||
grub_efi_memory_descriptor_t *memory_map;
|
||||
grub_efi_memory_descriptor_t *memory_map_end;
|
||||
@@ -683,7 +683,7 @@ grub_efi_mm_init (void)
|
||||
/* Prepare a memory region to store two memory maps. */
|
||||
memory_map = grub_efi_allocate_any_pages (2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE));
|
||||
if (! memory_map)
|
||||
- grub_fatal ("cannot allocate memory");
|
||||
+ return grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate memory for memory map");
|
||||
|
||||
/* Obtain descriptors for available memory. */
|
||||
map_size = MEMORY_MAP_SIZE;
|
||||
@@ -701,14 +701,14 @@ grub_efi_mm_init (void)
|
||||
|
||||
memory_map = grub_efi_allocate_any_pages (2 * BYTES_TO_PAGES (map_size));
|
||||
if (! memory_map)
|
||||
- grub_fatal ("cannot allocate memory");
|
||||
+ return grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate memory for new memory map");
|
||||
|
||||
mm_status = grub_efi_get_memory_map (&map_size, memory_map, 0,
|
||||
&desc_size, 0);
|
||||
}
|
||||
|
||||
if (mm_status < 0)
|
||||
- grub_fatal ("cannot get memory map");
|
||||
+ return grub_error (GRUB_ERR_OUT_OF_MEMORY, "error fetching memory map from EFI");
|
||||
|
||||
memory_map_end = NEXT_MEMORY_DESCRIPTOR (memory_map, map_size);
|
||||
|
||||
@@ -723,7 +723,7 @@ grub_efi_mm_init (void)
|
||||
|
||||
/* Allocate memory regions for GRUB's memory management. */
|
||||
add_memory_regions (filtered_memory_map, desc_size,
|
||||
- filtered_memory_map_end, BYTES_TO_PAGES (DEFAULT_HEAP_SIZE));
|
||||
+ filtered_memory_map_end, BYTES_TO_PAGES (required_bytes));
|
||||
|
||||
#if 0
|
||||
/* For debug. */
|
||||
@@ -741,6 +741,15 @@ grub_efi_mm_init (void)
|
||||
/* Release the memory maps. */
|
||||
grub_efi_free_pages ((grub_addr_t) memory_map,
|
||||
2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE));
|
||||
+
|
||||
+ return GRUB_ERR_NONE;
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+grub_efi_mm_init (void)
|
||||
+{
|
||||
+ if (grub_efi_mm_add_regions (DEFAULT_HEAP_SIZE) != GRUB_ERR_NONE)
|
||||
+ grub_fatal ("%s", grub_errmsg);
|
||||
}
|
||||
|
||||
#if defined (__aarch64__) || defined (__arm__) || defined (__riscv)
|
@ -0,0 +1,87 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Patrick Steinhardt <ps@pks.im>
|
||||
Date: Thu, 21 Apr 2022 15:24:21 +1000
|
||||
Subject: [PATCH] kern/efi/mm: Pass up errors from add_memory_regions()
|
||||
|
||||
The function add_memory_regions() is currently only called on system
|
||||
initialization to allocate a fixed amount of pages. As such, it didn't
|
||||
need to return any errors: in case it failed, we cannot proceed anyway.
|
||||
This will change with the upcoming support for requesting more memory
|
||||
from the firmware at runtime, where it doesn't make sense anymore to
|
||||
fail hard.
|
||||
|
||||
Refactor the function to return an error to prepare for this. Note that
|
||||
this does not change the behaviour when initializing the memory system
|
||||
because grub_efi_mm_init() knows to call grub_fatal() in case
|
||||
grub_efi_mm_add_regions() returns an error.
|
||||
|
||||
Signed-off-by: Patrick Steinhardt <ps@pks.im>
|
||||
Signed-off-by: Daniel Axtens <dja@axtens.net>
|
||||
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
|
||||
Tested-by: Patrick Steinhardt <ps@pks.im>
|
||||
(cherry picked from commit 15a015698921240adc1ac266a3b5bc5fcbd81521)
|
||||
---
|
||||
grub-core/kern/efi/mm.c | 22 +++++++++++++++-------
|
||||
1 file changed, 15 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c
|
||||
index a1d3b51fe6..e0ebc65dba 100644
|
||||
--- a/grub-core/kern/efi/mm.c
|
||||
+++ b/grub-core/kern/efi/mm.c
|
||||
@@ -514,7 +514,7 @@ filter_memory_map (grub_efi_memory_descriptor_t *memory_map,
|
||||
}
|
||||
|
||||
/* Add memory regions. */
|
||||
-static void
|
||||
+static grub_err_t
|
||||
add_memory_regions (grub_efi_memory_descriptor_t *memory_map,
|
||||
grub_efi_uintn_t desc_size,
|
||||
grub_efi_memory_descriptor_t *memory_map_end,
|
||||
@@ -542,9 +542,9 @@ add_memory_regions (grub_efi_memory_descriptor_t *memory_map,
|
||||
GRUB_EFI_ALLOCATE_ADDRESS,
|
||||
GRUB_EFI_LOADER_CODE);
|
||||
if (! addr)
|
||||
- grub_fatal ("cannot allocate conventional memory %p with %u pages",
|
||||
- (void *) ((grub_addr_t) start),
|
||||
- (unsigned) pages);
|
||||
+ return grub_error (GRUB_ERR_OUT_OF_MEMORY,
|
||||
+ "Memory starting at %p (%u pages) marked as free, but EFI would not allocate",
|
||||
+ (void *) ((grub_addr_t) start), (unsigned) pages);
|
||||
|
||||
grub_mm_init_region (addr, PAGES_TO_BYTES (pages));
|
||||
|
||||
@@ -554,7 +554,11 @@ add_memory_regions (grub_efi_memory_descriptor_t *memory_map,
|
||||
}
|
||||
|
||||
if (required_pages > 0)
|
||||
- grub_fatal ("too little memory");
|
||||
+ return grub_error (GRUB_ERR_OUT_OF_MEMORY,
|
||||
+ "could not allocate all requested memory: %" PRIuGRUB_UINT64_T " pages still required after iterating EFI memory map",
|
||||
+ required_pages);
|
||||
+
|
||||
+ return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -676,6 +680,7 @@ grub_efi_mm_add_regions (grub_size_t required_bytes)
|
||||
grub_efi_memory_descriptor_t *filtered_memory_map_end;
|
||||
grub_efi_uintn_t map_size;
|
||||
grub_efi_uintn_t desc_size;
|
||||
+ grub_err_t err;
|
||||
int mm_status;
|
||||
|
||||
grub_nx_init ();
|
||||
@@ -722,8 +727,11 @@ grub_efi_mm_add_regions (grub_size_t required_bytes)
|
||||
sort_memory_map (filtered_memory_map, desc_size, filtered_memory_map_end);
|
||||
|
||||
/* Allocate memory regions for GRUB's memory management. */
|
||||
- add_memory_regions (filtered_memory_map, desc_size,
|
||||
- filtered_memory_map_end, BYTES_TO_PAGES (required_bytes));
|
||||
+ err = add_memory_regions (filtered_memory_map, desc_size,
|
||||
+ filtered_memory_map_end,
|
||||
+ BYTES_TO_PAGES (required_bytes));
|
||||
+ if (err != GRUB_ERR_NONE)
|
||||
+ return err;
|
||||
|
||||
#if 0
|
||||
/* For debug. */
|
75
0315-kern-efi-mm-Implement-runtime-addition-of-pages.patch
Normal file
75
0315-kern-efi-mm-Implement-runtime-addition-of-pages.patch
Normal file
@ -0,0 +1,75 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Patrick Steinhardt <ps@pks.im>
|
||||
Date: Thu, 21 Apr 2022 15:24:22 +1000
|
||||
Subject: [PATCH] kern/efi/mm: Implement runtime addition of pages
|
||||
|
||||
Adjust the interface of grub_efi_mm_add_regions() to take a set of
|
||||
GRUB_MM_ADD_REGION_* flags, which most notably is currently only the
|
||||
GRUB_MM_ADD_REGION_CONSECUTIVE flag. This allows us to set the function
|
||||
up as callback for the memory subsystem and have it call out to us in
|
||||
case there's not enough pages available in the current heap.
|
||||
|
||||
Signed-off-by: Patrick Steinhardt <ps@pks.im>
|
||||
Signed-off-by: Daniel Axtens <dja@axtens.net>
|
||||
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
|
||||
Tested-by: Patrick Steinhardt <ps@pks.im>
|
||||
(cherry picked from commit 1df2934822df4c1170dde069d97cfbf7a9572bba)
|
||||
---
|
||||
grub-core/kern/efi/mm.c | 15 +++++++++++----
|
||||
1 file changed, 11 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c
|
||||
index e0ebc65dba..016ba6cf2f 100644
|
||||
--- a/grub-core/kern/efi/mm.c
|
||||
+++ b/grub-core/kern/efi/mm.c
|
||||
@@ -518,7 +518,8 @@ static grub_err_t
|
||||
add_memory_regions (grub_efi_memory_descriptor_t *memory_map,
|
||||
grub_efi_uintn_t desc_size,
|
||||
grub_efi_memory_descriptor_t *memory_map_end,
|
||||
- grub_efi_uint64_t required_pages)
|
||||
+ grub_efi_uint64_t required_pages,
|
||||
+ unsigned int flags)
|
||||
{
|
||||
grub_efi_memory_descriptor_t *desc;
|
||||
|
||||
@@ -532,6 +533,10 @@ add_memory_regions (grub_efi_memory_descriptor_t *memory_map,
|
||||
|
||||
start = desc->physical_start;
|
||||
pages = desc->num_pages;
|
||||
+
|
||||
+ if (pages < required_pages && (flags & GRUB_MM_ADD_REGION_CONSECUTIVE))
|
||||
+ continue;
|
||||
+
|
||||
if (pages > required_pages)
|
||||
{
|
||||
start += PAGES_TO_BYTES (pages - required_pages);
|
||||
@@ -672,7 +677,7 @@ grub_nx_init (void)
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
-grub_efi_mm_add_regions (grub_size_t required_bytes)
|
||||
+grub_efi_mm_add_regions (grub_size_t required_bytes, unsigned int flags)
|
||||
{
|
||||
grub_efi_memory_descriptor_t *memory_map;
|
||||
grub_efi_memory_descriptor_t *memory_map_end;
|
||||
@@ -729,7 +734,8 @@ grub_efi_mm_add_regions (grub_size_t required_bytes)
|
||||
/* Allocate memory regions for GRUB's memory management. */
|
||||
err = add_memory_regions (filtered_memory_map, desc_size,
|
||||
filtered_memory_map_end,
|
||||
- BYTES_TO_PAGES (required_bytes));
|
||||
+ BYTES_TO_PAGES (required_bytes),
|
||||
+ flags);
|
||||
if (err != GRUB_ERR_NONE)
|
||||
return err;
|
||||
|
||||
@@ -756,8 +762,9 @@ grub_efi_mm_add_regions (grub_size_t required_bytes)
|
||||
void
|
||||
grub_efi_mm_init (void)
|
||||
{
|
||||
- if (grub_efi_mm_add_regions (DEFAULT_HEAP_SIZE) != GRUB_ERR_NONE)
|
||||
+ if (grub_efi_mm_add_regions (DEFAULT_HEAP_SIZE, GRUB_MM_ADD_REGION_NONE) != GRUB_ERR_NONE)
|
||||
grub_fatal ("%s", grub_errmsg);
|
||||
+ grub_mm_add_region_fn = grub_efi_mm_add_regions;
|
||||
}
|
||||
|
||||
#if defined (__aarch64__) || defined (__arm__) || defined (__riscv)
|
31
0316-efi-Increase-default-memory-allocation-to-32-MiB.patch
Normal file
31
0316-efi-Increase-default-memory-allocation-to-32-MiB.patch
Normal file
@ -0,0 +1,31 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Axtens <dja@axtens.net>
|
||||
Date: Tue, 20 Sep 2022 00:30:30 +1000
|
||||
Subject: [PATCH] efi: Increase default memory allocation to 32 MiB
|
||||
|
||||
We have multiple reports of things being slower with a 1 MiB initial static
|
||||
allocation, and a report (more difficult to nail down) of a boot failure
|
||||
as a result of the smaller initial allocation.
|
||||
|
||||
Make the initial memory allocation 32 MiB.
|
||||
|
||||
Signed-off-by: Daniel Axtens <dja@axtens.net>
|
||||
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
|
||||
(cherry picked from commit 75e38e86e7d9202f050b093f20500d9ad4c6dad9)
|
||||
---
|
||||
grub-core/kern/efi/mm.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c
|
||||
index 016ba6cf2f..b27e966e1f 100644
|
||||
--- a/grub-core/kern/efi/mm.c
|
||||
+++ b/grub-core/kern/efi/mm.c
|
||||
@@ -39,7 +39,7 @@
|
||||
#define MEMORY_MAP_SIZE 0x3000
|
||||
|
||||
/* The default heap size for GRUB itself in bytes. */
|
||||
-#define DEFAULT_HEAP_SIZE 0x100000
|
||||
+#define DEFAULT_HEAP_SIZE 0x2000000
|
||||
|
||||
static void *finish_mmap_buf = 0;
|
||||
static grub_efi_uintn_t finish_mmap_size = 0;
|
@ -0,0 +1,57 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Zhang Boyang <zhangboyang.id@gmail.com>
|
||||
Date: Sat, 15 Oct 2022 22:15:11 +0800
|
||||
Subject: [PATCH] mm: Try invalidate disk caches last when out of memory
|
||||
|
||||
Every heap grow will cause all disk caches invalidated which decreases
|
||||
performance severely. This patch moves disk cache invalidation code to
|
||||
the last of memory squeezing measures. So, disk caches are released only
|
||||
when there are no other ways to get free memory.
|
||||
|
||||
Signed-off-by: Zhang Boyang <zhangboyang.id@gmail.com>
|
||||
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
|
||||
Reviewed-by: Patrick Steinhardt <ps@pks.im>
|
||||
(cherry picked from commit 17975d10a80e2457e5237f87fa58a7943031983e)
|
||||
---
|
||||
grub-core/kern/mm.c | 14 +++++++-------
|
||||
1 file changed, 7 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c
|
||||
index f2e27f263b..da1ac9427c 100644
|
||||
--- a/grub-core/kern/mm.c
|
||||
+++ b/grub-core/kern/mm.c
|
||||
@@ -443,12 +443,6 @@ grub_memalign (grub_size_t align, grub_size_t size)
|
||||
switch (count)
|
||||
{
|
||||
case 0:
|
||||
- /* Invalidate disk caches. */
|
||||
- grub_disk_cache_invalidate_all ();
|
||||
- count++;
|
||||
- goto again;
|
||||
-
|
||||
- case 1:
|
||||
/* Request additional pages, contiguous */
|
||||
count++;
|
||||
|
||||
@@ -458,7 +452,7 @@ grub_memalign (grub_size_t align, grub_size_t size)
|
||||
|
||||
/* fallthrough */
|
||||
|
||||
- case 2:
|
||||
+ case 1:
|
||||
/* Request additional pages, anything at all */
|
||||
count++;
|
||||
|
||||
@@ -474,6 +468,12 @@ grub_memalign (grub_size_t align, grub_size_t size)
|
||||
|
||||
/* fallthrough */
|
||||
|
||||
+ case 2:
|
||||
+ /* Invalidate disk caches. */
|
||||
+ grub_disk_cache_invalidate_all ();
|
||||
+ count++;
|
||||
+ goto again;
|
||||
+
|
||||
default:
|
||||
break;
|
||||
}
|
17
grub.patches
17
grub.patches
@ -299,4 +299,19 @@ Patch0298: 0298-font-Assign-null_font-to-glyphs-in-ascii_font_glyph.patch
|
||||
Patch0299: 0299-normal-charset-Fix-an-integer-overflow-in-grub_unico.patch
|
||||
Patch0300: 0300-font-Try-opening-fonts-from-the-bundled-memdisk.patch
|
||||
Patch0301: 0301-Correction-in-vector-5-values.patch
|
||||
Patch0302: 0302-Allow-internal-grub-allocations-over-4GB.patch
|
||||
Patch0302: 0302-mm-Clarify-grub_real_malloc.patch
|
||||
Patch0303: 0303-mm-grub_real_malloc-Make-small-allocs-comment-match-.patch
|
||||
Patch0304: 0304-mm-Document-grub_free.patch
|
||||
Patch0305: 0305-mm-Document-grub_mm_init_region.patch
|
||||
Patch0306: 0306-mm-Document-GRUB-internal-memory-management-structur.patch
|
||||
Patch0307: 0307-mm-Assert-that-we-preserve-header-vs-region-alignmen.patch
|
||||
Patch0308: 0308-mm-When-adding-a-region-merge-with-region-after-as-w.patch
|
||||
Patch0309: 0309-mm-Debug-support-for-region-operations.patch
|
||||
Patch0310: 0310-mm-Drop-unused-unloading-of-modules-on-OOM.patch
|
||||
Patch0311: 0311-mm-Allow-dynamically-requesting-additional-memory-re.patch
|
||||
Patch0312: 0312-kern-efi-mm-Always-request-a-fixed-number-of-pages-o.patch
|
||||
Patch0313: 0313-kern-efi-mm-Extract-function-to-add-memory-regions.patch
|
||||
Patch0314: 0314-kern-efi-mm-Pass-up-errors-from-add_memory_regions.patch
|
||||
Patch0315: 0315-kern-efi-mm-Implement-runtime-addition-of-pages.patch
|
||||
Patch0316: 0316-efi-Increase-default-memory-allocation-to-32-MiB.patch
|
||||
Patch0317: 0317-mm-Try-invalidate-disk-caches-last-when-out-of-memor.patch
|
||||
|
@ -17,7 +17,7 @@
|
||||
Name: grub2
|
||||
Epoch: 1
|
||||
Version: 2.06
|
||||
Release: 74%{?dist}
|
||||
Release: 75%{?dist}
|
||||
Summary: Bootloader with support for Linux, Multiboot and more
|
||||
License: GPLv3+
|
||||
URL: http://www.gnu.org/software/grub/
|
||||
@ -544,6 +544,9 @@ mv ${EFI_HOME}/grub.cfg.stb ${EFI_HOME}/grub.cfg
|
||||
%endif
|
||||
|
||||
%changelog
|
||||
* Wed Jan 11 2023 Robbie Harwood <rharwood@redhat.com> - 2.06-75
|
||||
- Pull allocator improvements from upstream
|
||||
|
||||
* Wed Jan 11 2023 Robbie Harwood <rharwood@redhat.com> - 2.06-74
|
||||
- Apply more hardening to host binaries
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user