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
This commit is contained in:
Alex Richardson 2020-06-08 08:52:02 +00:00
parent f7910a3df9
commit c98013c0b1
4 changed files with 14 additions and 0 deletions

View File

@ -42,6 +42,7 @@ struct riscv_bootparams {
vm_offset_t kern_phys; /* Kernel base (physical) addr */ vm_offset_t kern_phys; /* Kernel base (physical) addr */
vm_offset_t kern_stack; vm_offset_t kern_stack;
vm_offset_t dtbp_virt; /* Device tree blob virtual addr */ 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]; extern vm_paddr_t physmap[PHYS_AVAIL_ENTRIES];

View File

@ -106,3 +106,4 @@ ASSYM(RISCV_BOOTPARAMS_KERN_PHYS, offsetof(struct riscv_bootparams, kern_phys));
ASSYM(RISCV_BOOTPARAMS_KERN_STACK, offsetof(struct riscv_bootparams, ASSYM(RISCV_BOOTPARAMS_KERN_STACK, offsetof(struct riscv_bootparams,
kern_stack)); kern_stack));
ASSYM(RISCV_BOOTPARAMS_DTBP_VIRT, offsetof(struct riscv_bootparams, dtbp_virt)); ASSYM(RISCV_BOOTPARAMS_DTBP_VIRT, offsetof(struct riscv_bootparams, dtbp_virt));
ASSYM(RISCV_BOOTPARAMS_DTBP_PHYS, offsetof(struct riscv_bootparams, dtbp_phys));

View File

@ -221,6 +221,7 @@ va:
and t1, a1, t1 and t1, a1, t1
add t0, t0, t1 add t0, t0, t1
sd t0, RISCV_BOOTPARAMS_DTBP_VIRT(sp) sd t0, RISCV_BOOTPARAMS_DTBP_VIRT(sp)
sd a1, RISCV_BOOTPARAMS_DTBP_PHYS(sp)
mv a0, sp mv a0, sp
call _C_LABEL(initriscv) /* Off we go */ call _C_LABEL(initriscv) /* Off we go */

View File

@ -776,9 +776,20 @@ fake_preload_metadata(struct riscv_bootparams *rvbp)
PRELOAD_PUSH_VALUE(uint32_t, 0); PRELOAD_PUSH_VALUE(uint32_t, 0);
preload_metadata = (caddr_t)fake_preload; 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), KASSERT(fake_size < sizeof(fake_preload),
("Too many fake_preload items")); ("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); return (lastaddr);
} }