Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/arch/x86/x86 Fix startup crashes caused by wrong memory ...



details:   https://anonhg.NetBSD.org/src/rev/1001704c8daa
branches:  trunk
changeset: 1006827:1001704c8daa
user:      manu <manu%NetBSD.org@localhost>
date:      Wed Jan 29 01:54:34 2020 +0000

description:
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.

diffstat:

 sys/arch/x86/x86/x86_machdep.c |  78 +++++++++++++++++++++++++++++++++++++++--
 1 files changed, 73 insertions(+), 5 deletions(-)

diffs (125 lines):

diff -r 1fc0b3a26847 -r 1001704c8daa sys/arch/x86/x86/x86_machdep.c
--- a/sys/arch/x86/x86/x86_machdep.c    Tue Jan 28 23:24:09 2020 +0000
+++ b/sys/arch/x86/x86/x86_machdep.c    Wed Jan 29 01:54:34 2020 +0000
@@ -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 @@
                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 @@
                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);



Home | Main Index | Thread Index | Old Index