Module Name: src Committed By: manu Date: Wed Jan 29 01:54:34 UTC 2020
Modified Files: src/sys/arch/x86/x86: x86_machdep.c Log Message: Fix startup crashes caused by wrong memory map handling init_x86_vm() takes the memory map from BIOS and EFI and selects regions suitable for memory allocation. This involves removing areas used by the kernel, but the logic missed some corner cases, which led to possible allocation in regions for which later memory access would cause a panic. The typical panic from this bug in GENERIC is at SVS startup: cpu_svs_init / uvm_pagealloc_strat / pagezero We fix the bug by adding logic for the missing cases of memory regions overlapping with the kernel. While there, add more #idef'ed debug output. To generate a diff of this commit: cvs rdiff -u -r1.134 -r1.135 src/sys/arch/x86/x86/x86_machdep.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/arch/x86/x86/x86_machdep.c diff -u src/sys/arch/x86/x86/x86_machdep.c:1.134 src/sys/arch/x86/x86/x86_machdep.c:1.135 --- src/sys/arch/x86/x86/x86_machdep.c:1.134 Sat Dec 28 00:38:08 2019 +++ src/sys/arch/x86/x86/x86_machdep.c Wed Jan 29 01:54:34 2020 @@ -1,4 +1,4 @@ -/* $NetBSD: x86_machdep.c,v 1.134 2019/12/28 00:38:08 pgoyette Exp $ */ +/* $NetBSD: x86_machdep.c,v 1.135 2020/01/29 01:54:34 manu Exp $ */ /*- * Copyright (c) 2002, 2006, 2007 YAMAMOTO Takashi, @@ -31,7 +31,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: x86_machdep.c,v 1.134 2019/12/28 00:38:08 pgoyette Exp $"); +__KERNEL_RCSID(0, "$NetBSD: x86_machdep.c,v 1.135 2020/01/29 01:54:34 manu Exp $"); #include "opt_modular.h" #include "opt_physmem.h" @@ -669,7 +669,7 @@ x86_parse_clusters(struct btinfo_memmap type = bim->entry[x].type; #ifdef DEBUG_MEMLOAD printf("MEMMAP: 0x%016" PRIx64 "-0x%016" PRIx64 - ", size=0x%016" PRIx64 ", type=%d(%s)\n", + "\n\tsize=0x%016" PRIx64 ", type=%d(%s)\n", addr, addr + size - 1, size, type, (type == BIM_Memory) ? "Memory" : (type == BIM_Reserved) ? "Reserved" : @@ -909,27 +909,95 @@ init_x86_vm(paddr_t pa_kend) seg_start1 = 0; seg_end1 = 0; +#ifdef DEBUG_MEMLOAD + printf("segment %" PRIx64 " - %" PRIx64 "\n", + seg_start, seg_end); +#endif + /* Skip memory before our available starting point. */ - if (seg_end <= lowmem_rsvd) + if (seg_end <= lowmem_rsvd) { +#ifdef DEBUG_MEMLOAD + printf("discard segment below starting point " + "%" PRIx64 " - %" PRIx64 "\n", seg_start, seg_end); +#endif continue; + } if (seg_start <= lowmem_rsvd && lowmem_rsvd < seg_end) { seg_start = lowmem_rsvd; - if (seg_start == seg_end) + if (seg_start == seg_end) { +#ifdef DEBUG_MEMLOAD + printf("discard segment below starting point " + "%" PRIx64 " - %" PRIx64 "\n", + seg_start, seg_end); + + +#endif continue; + } } /* * If this segment contains the kernel, split it in two, around * the kernel. + * [seg_start seg_end] + * [pa_kstart pa_kend] */ if (seg_start <= pa_kstart && pa_kend <= seg_end) { +#ifdef DEBUG_MEMLOAD + printf("split kernel overlapping to " + "%" PRIx64 " - %lx and %lx - %" PRIx64 "\n", + seg_start, pa_kstart, pa_kend, seg_end); +#endif seg_start1 = pa_kend; seg_end1 = seg_end; seg_end = pa_kstart; KASSERT(seg_end < seg_end1); } + /* + * Discard a segment inside the kernel + * [pa_kstart pa_kend] + * [seg_start seg_end] + */ + if (pa_kstart < seg_start && seg_end < pa_kend) { +#ifdef DEBUG_MEMLOAD + printf("discard complete kernel overlap " + "%" PRIx64 " - %" PRIx64 "\n", seg_start, seg_end); +#endif + continue; + } + + /* + * Discard leading hunk that overlaps the kernel + * [pa_kstart pa_kend] + * [seg_start seg_end] + */ + if (pa_kstart < seg_start && + seg_start < pa_kend && + pa_kend < seg_end) { +#ifdef DEBUG_MEMLOAD + printf("discard leading kernel overlap " + "%" PRIx64 " - %lx\n", seg_start, pa_kend); +#endif + seg_start = pa_kend; + } + + /* + * Discard trailing hunk that overlaps the kernel + * [pa_kstart pa_kend] + * [seg_start seg_end] + */ + if (seg_start < pa_kstart && + pa_kstart < seg_end && + seg_end < pa_kend) { +#ifdef DEBUG_MEMLOAD + printf("discard trailing kernel overlap " + "%lx - %" PRIx64 "\n", pa_kstart, seg_end); +#endif + seg_end = pa_kstart; + } + /* First hunk */ if (seg_start != seg_end) { x86_load_region(seg_start, seg_end);