From c98013c0b1e07cd8f36fd3908804260c8d9f73dc Mon Sep 17 00:00:00 2001 From: Alex Richardson Date: Mon, 8 Jun 2020 08:52:02 +0000 Subject: [PATCH] RISC-V: Check that the DTB doesn't overlap with kernel This can happen with very large kernels (e.g. ones embedding a root filesystem). The DTB written by OpenSBI/BBL is quite small so this is unlikely to hit important data, but if it does this can result in very confusing and hard-to-debug crashes. Add a KASSERT() and a verbose print to catch this problem with debug kernels. While this will not print any output by default if it fails (that would depend on EARLY_PRINTF), at least the kernel now halts reliably instead of randomly crashing. Reviewed By: mhorne Differential Revision: https://reviews.freebsd.org/D25153 --- sys/riscv/include/machdep.h | 1 + sys/riscv/riscv/genassym.c | 1 + sys/riscv/riscv/locore.S | 1 + sys/riscv/riscv/machdep.c | 11 +++++++++++ 4 files changed, 14 insertions(+) diff --git a/sys/riscv/include/machdep.h b/sys/riscv/include/machdep.h index e022e26264b6..ad9af4c8dfc1 100644 --- a/sys/riscv/include/machdep.h +++ b/sys/riscv/include/machdep.h @@ -42,6 +42,7 @@ struct riscv_bootparams { vm_offset_t kern_phys; /* Kernel base (physical) addr */ vm_offset_t kern_stack; vm_offset_t dtbp_virt; /* Device tree blob virtual addr */ + vm_offset_t dtbp_phys; /* Device tree blob physical addr */ }; extern vm_paddr_t physmap[PHYS_AVAIL_ENTRIES]; diff --git a/sys/riscv/riscv/genassym.c b/sys/riscv/riscv/genassym.c index fa5ca242102a..321bdf533a0b 100644 --- a/sys/riscv/riscv/genassym.c +++ b/sys/riscv/riscv/genassym.c @@ -106,3 +106,4 @@ ASSYM(RISCV_BOOTPARAMS_KERN_PHYS, offsetof(struct riscv_bootparams, kern_phys)); ASSYM(RISCV_BOOTPARAMS_KERN_STACK, offsetof(struct riscv_bootparams, kern_stack)); ASSYM(RISCV_BOOTPARAMS_DTBP_VIRT, offsetof(struct riscv_bootparams, dtbp_virt)); +ASSYM(RISCV_BOOTPARAMS_DTBP_PHYS, offsetof(struct riscv_bootparams, dtbp_phys)); diff --git a/sys/riscv/riscv/locore.S b/sys/riscv/riscv/locore.S index caaf75726294..ce644a8667d1 100644 --- a/sys/riscv/riscv/locore.S +++ b/sys/riscv/riscv/locore.S @@ -221,6 +221,7 @@ va: and t1, a1, t1 add t0, t0, t1 sd t0, RISCV_BOOTPARAMS_DTBP_VIRT(sp) + sd a1, RISCV_BOOTPARAMS_DTBP_PHYS(sp) mv a0, sp call _C_LABEL(initriscv) /* Off we go */ diff --git a/sys/riscv/riscv/machdep.c b/sys/riscv/riscv/machdep.c index 5e3847423ddf..f90525337137 100644 --- a/sys/riscv/riscv/machdep.c +++ b/sys/riscv/riscv/machdep.c @@ -776,9 +776,20 @@ fake_preload_metadata(struct riscv_bootparams *rvbp) PRELOAD_PUSH_VALUE(uint32_t, 0); preload_metadata = (caddr_t)fake_preload; + /* Check if bootloader clobbered part of the kernel with the DTB. */ + KASSERT(rvbp->dtbp_phys + dtb_size <= rvbp->kern_phys || + rvbp->dtbp_phys >= rvbp->kern_phys + (lastaddr - KERNBASE), + ("FDT (%lx-%lx) and kernel (%lx-%lx) overlap", rvbp->dtbp_phys, + rvbp->dtbp_phys + dtb_size, rvbp->kern_phys, + rvbp->kern_phys + (lastaddr - KERNBASE))); KASSERT(fake_size < sizeof(fake_preload), ("Too many fake_preload items")); + if (boothowto & RB_VERBOSE) + printf("FDT phys (%lx-%lx), kernel phys (%lx-%lx)\n", + rvbp->dtbp_phys, rvbp->dtbp_phys + dtb_size, + rvbp->kern_phys, rvbp->kern_phys + (lastaddr - KERNBASE)); + return (lastaddr); }