From 1b5faf7bd57ff3733271ec16038ddd782d9dd5ea Mon Sep 17 00:00:00 2001 From: Niklas Femerstrand Date: Thu, 12 Feb 2026 15:45:42 -0500 Subject: [PATCH] Fix Xen PVH boot and init_physical_heap low-memory trimming bug https://github.com/nanovms/nanos/issues/2136 --- platform/pc/service.c | 39 ++++++++++++++++++++++++--------------- src/x86_64/init.s | 2 ++ src/x86_64/interrupt.c | 9 ++++++--- 3 files changed, 32 insertions(+), 18 deletions(-) diff --git a/platform/pc/service.c b/platform/pc/service.c index 7c798384b..4c7950bb5 100644 --- a/platform/pc/service.c +++ b/platform/pc/service.c @@ -78,6 +78,7 @@ range kern_get_elf(void) BSS_RO_AFTER_INIT static boolean have_rdseed; BSS_RO_AFTER_INIT static boolean have_rdrand; +BSS_RO_AFTER_INIT boolean pvh_boot; static boolean hw_seed(u64 * seed, boolean rdseed) { @@ -205,8 +206,9 @@ void start_secondary_cores(kernel_heaps kh) void count_cpus_present(void) { - /* Read ACPI tables for MADT access */ - init_acpi_tables(get_kernel_heaps()); + /* Read ACPI tables for MADT access (not available on PVH) */ + if (!pvh_boot) + init_acpi_tables(get_kernel_heaps()); #ifdef SMP_ENABLE if (acpi_walk_madt(stack_closure_func(madt_handler, count_processors_handler))) { @@ -265,21 +267,24 @@ static void find_initial_pages(void) void init_physical_heap(void) { - /* Carve the bootstrap heap out of a physical memory region. */ + /* Remove low memory area from physical regions so it can be used for things + like starting secondary CPUs. This must be a separate pass because the + search below may break early, skipping remaining regions. */ for_regions(e) { - if (e->type == REGION_PHYSICAL) { - /* Remove low memory area from physical memory regions, so that it can be used for - * things like starting secondary CPUs. */ - if (e->base < MB) { - u64 end = e->base + e->length; - if (end > MB) { - e->base = MB; - e->length = end - MB; - } else { - e->length = 0; - } + if (e->type == REGION_PHYSICAL && e->base < MB) { + u64 end = e->base + e->length; + if (end > MB) { + e->base = MB; + e->length = end - MB; + } else { + e->length = 0; } + } + } + /* Carve the bootstrap heap out of a physical memory region. */ + for_regions(e) { + if (e->type == REGION_PHYSICAL) { u64 base = pad(e->base, PAGESIZE); u64 end = e->base + e->length; u64 length = (end & ~MASK(PAGELOG)) - base; @@ -437,12 +442,15 @@ void pvh_start(hvm_start_info start_info) { if (start_info->magic != HVM_START_MAGIC_VALUE) return; + pvh_boot = true; regions->type = 0; hvm_memmap_entry mem_table = pointer_from_u64(start_info->memmap_paddr); for (int i = 0; i < start_info->memmap_entries; i++) { if (mem_table[i].type == HVM_MEMMAP_TYPE_RAM) create_region(mem_table[i].addr, mem_table[i].size, REGION_PHYSICAL); } + if (start_info->rsdp_paddr) + create_region(start_info->rsdp_paddr, sizeof(u64), REGION_RSDP); init_service(0, 0, start_info); } @@ -528,7 +536,8 @@ void detect_devices(kernel_heaps kh, storage_attach sa) } /* misc / platform */ - init_acpi(kh); + if (!pvh_boot) + init_acpi(kh); init_virtio_balloon(kh); init_virtio_rng(kh); diff --git a/src/x86_64/init.s b/src/x86_64/init.s index a76dee5d2..c298125f8 100644 --- a/src/x86_64/init.s +++ b/src/x86_64/init.s @@ -107,6 +107,8 @@ extern pvh_start bits 32 pvh_start32: + ; ESP is undefined at PVH entry, we need a temporary stack before calls + mov esp, 0xa000 PREPARE_LONG_MODE eax ; set up minimal mapping to be able to run in 64-bit mode, carving page ; tables from the top of the first 1MB of memory (which will not be diff --git a/src/x86_64/interrupt.c b/src/x86_64/interrupt.c index f58e289b6..0b14bc234 100644 --- a/src/x86_64/interrupt.c +++ b/src/x86_64/interrupt.c @@ -5,6 +5,8 @@ #include #include +extern boolean pvh_boot; + //#define INT_DEBUG #ifdef INT_DEBUG #define int_debug(x, ...) do {tprintf(sym(int), 0, ss(x), ##__VA_ARGS__);} while(0) @@ -212,7 +214,7 @@ void common_handler() if (handlers[i]) { ci->state = cpu_interrupt; apply(handlers[i]); - if (i >= INTERRUPT_VECTOR_START) + if (i >= INTERRUPT_VECTOR_START && !pvh_boot) lapic_eoi(); /* enqueue interrupted user thread */ @@ -383,8 +385,9 @@ void init_interrupts(kernel_heaps kh) assert(v != INVALID_PHYSICAL); spurious_int_vector = v; - /* APIC initialization */ - init_apic(kh); + /* APIC initialization, skip for PVH (Xen uses event channels) */ + if (!pvh_boot) + init_apic(kh); } void triple_fault(void)