Skip to content

Commit 0d9daff

Browse files
committed
x86/boot/e820: Make sure e820_search_gap() finds all gaps
The current implementation of e820_search_gap() searches gaps in a reverse search from MAX_GAP_END back to 0, contrary to what its main comment claims: * Search for a gap in the E820 memory space from 0 to MAX_GAP_END (4GB). But gaps can not only be beyond E820 RAM ranges, they can be below them as well. For example this function will not find the proper PCI gap for simplified memory map layouts that have a single RAM range that crosses the 4GB boundary. Rework the function to have a proper forward search of E820 table entries. This makes the code somewhat bigger: text data bss dec hex filename 7613 44072 0 51685 c9e5 e820.o.before 7645 44072 0 51717 ca05 e820.o.after but it now both implements what it claims to do, and is more straightforward to read. ( This also allows 'idx' to be the regular u32 again, not an 'int' underflowing to -1. ) Signed-off-by: Ingo Molnar <mingo@kernel.org> Cc: H . Peter Anvin <hpa@zytor.com> Cc: Andy Shevchenko <andy@kernel.org> Cc: Arnd Bergmann <arnd@kernel.org> Cc: David Woodhouse <dwmw@amazon.co.uk> Cc: Juergen Gross <jgross@suse.com> Cc: Kees Cook <keescook@chromium.org> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Mike Rapoport <rppt@kernel.org> Cc: Paul Menzel <pmenzel@molgen.mpg.de> Cc: Peter Zijlstra <peterz@infradead.org> Link: https://patch.msgid.link/20250515120549.2820541-29-mingo@kernel.org
1 parent 4ad03f1 commit 0d9daff

1 file changed

Lines changed: 41 additions & 18 deletions

File tree

arch/x86/kernel/e820.c

Lines changed: 41 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -624,30 +624,52 @@ __init static void e820__update_table_kexec(void)
624624
*/
625625
__init static int e820_search_gap(unsigned long *max_gap_start, unsigned long *max_gap_size)
626626
{
627-
u64 last = MAX_GAP_END;
628-
int idx = e820_table->nr_entries;
627+
struct e820_entry *entry;
628+
u64 range_end_prev = 0;
629629
int found = 0;
630+
u32 idx;
630631

631-
while (--idx >= 0) {
632-
u64 start = e820_table->entries[idx].addr;
633-
u64 end = start + e820_table->entries[idx].size;
632+
for (idx = 0; idx < e820_table->nr_entries; idx++) {
633+
u64 range_start, range_end;
634634

635-
/*
636-
* Since "last" is at most 4GB, we know we'll
637-
* fit in 32 bits if this condition is true:
638-
*/
639-
if (last > end) {
640-
unsigned long gap = last - end;
635+
entry = e820_table->entries + idx;
636+
range_start = entry->addr;
637+
range_end = entry->addr + entry->size;
641638

642-
if (gap > *max_gap_size) {
643-
*max_gap_size = gap;
644-
*max_gap_start = end;
645-
found = 1;
639+
/* Process any gap before this entry: */
640+
if (range_start > range_end_prev) {
641+
u64 gap_start = range_end_prev;
642+
u64 gap_end = range_start;
643+
u64 gap_size;
644+
645+
if (gap_start < MAX_GAP_END) {
646+
/* Make sure the entirety of the gap is below MAX_GAP_END: */
647+
gap_end = min(gap_end, MAX_GAP_END);
648+
gap_size = gap_end-gap_start;
649+
650+
if (gap_size >= *max_gap_size) {
651+
*max_gap_start = gap_start;
652+
*max_gap_size = gap_size;
653+
found = 1;
654+
}
646655
}
647656
}
648-
if (start < last)
649-
last = start;
657+
658+
range_end_prev = range_end;
659+
}
660+
661+
/* Is there a usable gap beyond the last entry: */
662+
if (entry->addr + entry->size < MAX_GAP_END) {
663+
u64 gap_start = entry->addr + entry->size;
664+
u64 gap_size = MAX_GAP_END-gap_start;
665+
666+
if (gap_size >= *max_gap_size) {
667+
*max_gap_start = gap_start;
668+
*max_gap_size = gap_size;
669+
found = 1;
670+
}
650671
}
672+
651673
return found;
652674
}
653675

@@ -664,6 +686,7 @@ __init void e820__setup_pci_gap(void)
664686
unsigned long max_gap_start, max_gap_size;
665687
int found;
666688

689+
/* The minimum eligible gap size is 4MB: */
667690
max_gap_size = SZ_4M;
668691
found = e820_search_gap(&max_gap_start, &max_gap_size);
669692

@@ -683,7 +706,7 @@ __init void e820__setup_pci_gap(void)
683706
pci_mem_start = max_gap_start;
684707

685708
pr_info("[gap %#010lx-%#010lx] available for PCI devices\n",
686-
max_gap_start, max_gap_start + max_gap_size - 1);
709+
max_gap_start, max_gap_start + max_gap_size-1);
687710
}
688711

689712
/*

0 commit comments

Comments
 (0)