* [PATCH v2] x86/unaccepted_memory: Do not accept ranges that are no longer E820 RAM
@ 2026-11-13 10:55 Pankaj Gupta
2026-11-13 12:55 ` Kiryl Shutsemau
0 siblings, 1 reply; 3+ messages in thread
From: Pankaj Gupta @ 2026-11-13 10:55 UTC (permalink / raw)
To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86
Cc: H . Peter Anvin, Tom Lendacky, Ard Biesheuvel, Kiryl Shutsemau,
Ilias Apalodimas, linux-kernel, Mike Rapoport, linux-mm,
linux-efi, Pankaj.gupta.linux, Pankaj Gupta, stable
The EFI stub builds the unaccepted memory bitmap before the kernel parses
its command line. Option memmap=<size>$<addr> removes RAM from the E820 map
while its bits are still set in the bitmap.
The removed range, such as a memmap=...$... hole, is then still treated as
unaccepted RAM and accept_memory() tries to accept it. The hole is not
mapped, so on SEV-SNP the PVALIDATE faults and the guest crashes early in
the boot:
BUG: unable to handle page fault for address: ffff8a14bfe00000
RIP: 0010:pvalidate_pages+0xc0/0x250
set_pages_state+0x41a/0x440
snp_accept_memory+0x3e/0x50
accept_memory+0x186/0x260
__free_pages_core+0xd2/0x240
memblock_free_pages+0x1b/0x30
memblock_free_all+0x275/0x2d0
This was seen with memmap=2M$0x1ffe00000, a 2 MiB hole in RAM, on a 19 GiB
SNP guest with lazy acceptance.
Accept only whole pages of E820 RAM, and clear the bitmap bits only for the
units in which memory was accepted.
Fixes: 2053bc57f367 ("efi: Add unaccepted memory support")
Cc: stable@vger.kernel.org
Signed-off-by: Pankaj Gupta <pankaj.gupta@amd.com>
---
v1 -> v2:
- Clear the bitmap bits only for the accepted memory
- Round E820 RAM range to page boundaries
v1: https://lore.kernel.org/all/20261102113127.161823-1-pankaj.gupta@amd.com/
arch/x86/include/asm/unaccepted_memory.h | 44 +++++++++++++++++++++++-
drivers/firmware/efi/unaccepted_memory.c | 4 +--
2 files changed, 45 insertions(+), 3 deletions(-)
diff --git a/arch/x86/include/asm/unaccepted_memory.h b/arch/x86/include/asm/unaccepted_memory.h
index f5937e9866ac..9e27a9953dd8 100644
--- a/arch/x86/include/asm/unaccepted_memory.h
+++ b/arch/x86/include/asm/unaccepted_memory.h
@@ -2,10 +2,11 @@
#define _ASM_X86_UNACCEPTED_MEMORY_H
#include <linux/efi.h>
+#include <asm/e820/api.h>
#include <asm/tdx.h>
#include <asm/sev.h>
-static inline void arch_accept_memory(phys_addr_t start, phys_addr_t end)
+static inline void __arch_accept_memory(phys_addr_t start, phys_addr_t end)
{
/* Platform-specific memory-acceptance call goes here */
if (cpu_feature_enabled(X86_FEATURE_TDX_GUEST)) {
@@ -18,6 +19,47 @@ static inline void arch_accept_memory(phys_addr_t start, phys_addr_t end)
}
}
+static inline bool e820_ram_pages(struct e820_entry *entry, phys_addr_t start,
+ phys_addr_t end, phys_addr_t *s, phys_addr_t *e)
+{
+ if (entry->type != E820_TYPE_RAM)
+ return false;
+
+ *s = PAGE_ALIGN(max_t(phys_addr_t, start, entry->addr));
+ *e = PAGE_ALIGN_DOWN(min_t(phys_addr_t, end, entry->addr + entry->size));
+ return *s < *e;
+}
+
+static inline void arch_accept_memory(phys_addr_t start, phys_addr_t end)
+{
+ phys_addr_t s, e;
+ u32 i;
+
+ for (i = 0; i < e820_table->nr_entries; i++) {
+ if (e820_ram_pages(&e820_table->entries[i], start, end, &s, &e))
+ __arch_accept_memory(s, e);
+ }
+}
+
+static inline void arch_clear_accepted(unsigned long *bitmap, phys_addr_t base,
+ unsigned long unit_size,
+ phys_addr_t start, phys_addr_t end)
+{
+ phys_addr_t s, e;
+ u32 i;
+
+ for (i = 0; i < e820_table->nr_entries; i++) {
+ unsigned long first, last;
+
+ if (!e820_ram_pages(&e820_table->entries[i], start, end, &s, &e))
+ continue;
+
+ first = (s - base) / unit_size;
+ last = DIV_ROUND_UP(e - base, unit_size);
+ bitmap_clear(bitmap, first, last - first);
+ }
+}
+
static inline struct efi_unaccepted_memory *efi_get_unaccepted_table(void)
{
if (efi.unaccepted == EFI_INVALID_TABLE_ADDR)
diff --git a/drivers/firmware/efi/unaccepted_memory.c b/drivers/firmware/efi/unaccepted_memory.c
index 4a8ec8d6a571..b8a0c0d1d289 100644
--- a/drivers/firmware/efi/unaccepted_memory.c
+++ b/drivers/firmware/efi/unaccepted_memory.c
@@ -130,7 +130,6 @@ void accept_memory(phys_addr_t start, unsigned long size)
for_each_set_bitrange_from(range_start, range_end, unaccepted->bitmap,
range.end) {
unsigned long phys_start, phys_end;
- unsigned long len = range_end - range_start;
phys_start = range_start * unit_size + unaccepted->phys_base;
phys_end = range_end * unit_size + unaccepted->phys_base;
@@ -150,7 +149,8 @@ void accept_memory(phys_addr_t start, unsigned long size)
arch_accept_memory(phys_start, phys_end);
spin_lock(&unaccepted_memory_lock);
- bitmap_clear(unaccepted->bitmap, range_start, len);
+ arch_clear_accepted(unaccepted->bitmap, unaccepted->phys_base,
+ unit_size, phys_start, phys_end);
}
list_del(&range.list);
--
2.34.1
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH v2] x86/unaccepted_memory: Do not accept ranges that are no longer E820 RAM
2026-11-13 10:55 [PATCH v2] x86/unaccepted_memory: Do not accept ranges that are no longer E820 RAM Pankaj Gupta
@ 2026-11-13 12:55 ` Kiryl Shutsemau
2026-11-13 14:10 ` Gupta, Pankaj
0 siblings, 1 reply; 3+ messages in thread
From: Kiryl Shutsemau @ 2026-11-13 12:55 UTC (permalink / raw)
To: Pankaj Gupta
Cc: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
H . Peter Anvin, Tom Lendacky, Ard Biesheuvel, Ilias Apalodimas,
linux-kernel, Mike Rapoport, linux-mm, linux-efi,
Pankaj.gupta.linux, stable
On Fri, Nov 13, 2026 at 04:55:54AM -0600, Pankaj Gupta wrote:
> Accept only whole pages of E820 RAM, and clear the bitmap bits only for the
> units in which memory was accepted.
A bit in the bitmap covers the whole unit. If the hole doesn't start and
end on a unit boundary, the unit at its edge is only partly accepted, but
its bit gets cleared. The rest of the unit stays unaccepted and nothing
records it.
This kernel never touches the hole, but the next one can. memmap= and mem=
only edit e820_table. kexec_file_load() hands the next kernel
e820_table_kexec, which is copied before the command line is parsed and
still has the hole as RAM. The next kernel finds RAM with a clear bit and
uses it. memmap=1M$0x1fff00000, then kexec into a kernel without it.
On TDX this is new. tdx_accept_memory() works on physical addresses, so
today the hole is accepted together with the rest of the unit and the
bitmap stays correct. Only SNP needs the direct mapping.
A unit cannot be half accepted. Given that, should we go with what Ard
suggested and refuse memmap= holes in unaccepted memory instead?
--
Kiryl Shutsemau / Kirill A. Shutemov
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH v2] x86/unaccepted_memory: Do not accept ranges that are no longer E820 RAM
2026-11-13 12:55 ` Kiryl Shutsemau
@ 2026-11-13 14:10 ` Gupta, Pankaj
0 siblings, 0 replies; 3+ messages in thread
From: Gupta, Pankaj @ 2026-11-13 14:10 UTC (permalink / raw)
To: Kiryl Shutsemau
Cc: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
H . Peter Anvin, Tom Lendacky, Ard Biesheuvel, Ilias Apalodimas,
linux-kernel, Mike Rapoport, linux-mm, linux-efi,
Pankaj.gupta.linux, stable
>> Accept only whole pages of E820 RAM, and clear the bitmap bits only for the
>> units in which memory was accepted.
> A bit in the bitmap covers the whole unit. If the hole doesn't start and
> end on a unit boundary, the unit at its edge is only partly accepted, but
> its bit gets cleared. The rest of the unit stays unaccepted and nothing
> records it.
Right.
>
> This kernel never touches the hole, but the next one can. memmap= and mem=
> only edit e820_table. kexec_file_load() hands the next kernel
> e820_table_kexec, which is copied before the command line is parsed and
> still has the hole as RAM. The next kernel finds RAM with a clear bit and
> uses it. memmap=1M$0x1fff00000, then kexec into a kernel without it.
>
> On TDX this is new. tdx_accept_memory() works on physical addresses, so
> today the hole is accepted together with the rest of the unit and the
> bitmap stays correct. Only SNP needs the direct mapping.
o.k.
>
> A unit cannot be half accepted. Given that, should we go with what Ard
> suggested and refuse memmap= holes in unaccepted memory instead?
Sure, I will go with Ard's suggestion and drop this patch. I will send
the series that
refuses memmap= holes in confidential guests instead.
Thanks for looking!
Pankaj
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-11-13 14:10 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-11-13 10:55 [PATCH v2] x86/unaccepted_memory: Do not accept ranges that are no longer E820 RAM Pankaj Gupta
2026-11-13 12:55 ` Kiryl Shutsemau
2026-11-13 14:10 ` Gupta, Pankaj
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®