From 650a9addf1aa6411b6dfefe94fcf78fe0b856fe8 Mon Sep 17 00:00:00 2001 From: ian Date: Sun, 24 Jan 2016 22:00:36 +0000 Subject: MFC r293053, r293061, r293063, r293064, r293065, r293775, r293792: Use 64-bit math when finding a block of ram to hold the kernel. This fixes a problem on 32-bit systems which have ram occupying the end of the physical address space -- for example, a block of ram at 0x80000000 with a size of 0x80000000 was overflowing 32 bit math and ending up with a calculated size of zero. Use 64-bit math when processing the lists of physical and excluded memory to generate the phys_avail and dump_avail arrays. Work around problems that happen when there is ram at the end of the physical address space. Cast pointer through uintptr_t on the way to uint64_t to squelch a warning. Reword the comment to better describe what I found while researching the problem that led to this temporary workaround (and also so I can properly cite the PR in the commit this time). Cast using uintfptr_t and eliminate the cast to uint64_t which is uneeded because rounding down cannot increase the number of bits needed to express the result. Go back to using uintptr_t, because code that actually compiles is infinitely less buggy than code that is theoretically correct in some alternate universe. PR: 201614 --- sys/arm/arm/physmem.c | 29 +++++++++++++++++++++-------- sys/boot/uboot/lib/copy.c | 22 ++++++++++++---------- 2 files changed, 33 insertions(+), 18 deletions(-) (limited to 'sys') diff --git a/sys/arm/arm/physmem.c b/sys/arm/arm/physmem.c index bc72ce2..8c41fbb 100644 --- a/sys/arm/arm/physmem.c +++ b/sys/arm/arm/physmem.c @@ -161,7 +161,7 @@ static size_t regions_to_avail(vm_paddr_t *avail, uint32_t exflags, long *pavail) { size_t acnt, exi, hwi; - vm_paddr_t end, start, xend, xstart; + uint64_t end, start, xend, xstart; long availmem; const struct region *exp, *hwp; @@ -171,7 +171,7 @@ regions_to_avail(vm_paddr_t *avail, uint32_t exflags, long *pavail) for (hwi = 0, hwp = hwregions; hwi < hwcnt; ++hwi, ++hwp) { start = hwp->addr; end = hwp->size + start; - realmem += arm32_btop(end - start); + realmem += arm32_btop((vm_offset_t)(end - start)); for (exi = 0, exp = exregions; exi < excnt; ++exi, ++exp) { /* * If the excluded region does not match given flags, @@ -212,9 +212,10 @@ regions_to_avail(vm_paddr_t *avail, uint32_t exflags, long *pavail) * could affect the remainder of this hw region. */ if ((xstart > start) && (xend < end)) { - avail[acnt++] = start; - avail[acnt++] = xstart; - availmem += arm32_btop(xstart - start); + avail[acnt++] = (vm_paddr_t)start; + avail[acnt++] = (vm_paddr_t)xstart; + availmem += + arm32_btop((vm_offset_t)(xstart - start)); start = xend; continue; } @@ -233,9 +234,9 @@ regions_to_avail(vm_paddr_t *avail, uint32_t exflags, long *pavail) * available entry for it. */ if (end > start) { - avail[acnt++] = start; - avail[acnt++] = end; - availmem += arm32_btop(end - start); + avail[acnt++] = (vm_paddr_t)start; + avail[acnt++] = (vm_paddr_t)end; + availmem += arm32_btop((vm_offset_t)(end - start)); } if (acnt >= MAX_AVAIL_ENTRIES) panic("Not enough space in the dump/phys_avail arrays"); @@ -279,10 +280,22 @@ arm_physmem_hardware_region(vm_paddr_t pa, vm_size_t sz) /* * Filter out the page at PA 0x00000000. The VM can't handle it, as * pmap_extract() == 0 means failure. + * + * Also filter out the page at the end of the physical address space -- + * if addr is non-zero and addr+size is zero we wrapped to the next byte + * beyond what vm_paddr_t can express. That leads to a NULL pointer + * deref early in startup; work around it by leaving the last page out. + * + * XXX This just in: subtract out a whole megabyte, not just 1 page. + * Reducing the size by anything less than 1MB results in the NULL + * pointer deref in _vm_map_lock_read(). Better to give up a megabyte + * than leave some folks with an unusable system while we investigate. */ if (pa == 0) { pa = PAGE_SIZE; sz -= PAGE_SIZE; + } else if (pa + sz == 0) { + sz -= 1024 * 1024; } /* diff --git a/sys/boot/uboot/lib/copy.c b/sys/boot/uboot/lib/copy.c index bb658e3..76f2faf 100644 --- a/sys/boot/uboot/lib/copy.c +++ b/sys/boot/uboot/lib/copy.c @@ -69,11 +69,11 @@ uint64_t uboot_loadaddr(u_int type, void *data, uint64_t addr) { struct sys_info *si; - uintptr_t sblock, eblock, subldr, eubldr; - uintptr_t biggest_block, this_block; - size_t biggest_size, this_size; + uint64_t sblock, eblock, subldr, eubldr; + uint64_t biggest_block, this_block; + uint64_t biggest_size, this_size; int i; - char * envstr; + char *envstr; if (addr == 0) { /* @@ -101,13 +101,14 @@ uboot_loadaddr(u_int type, void *data, uint64_t addr) biggest_block = 0; biggest_size = 0; subldr = rounddown2((uintptr_t)_start, KERN_ALIGN); - eubldr = roundup2(uboot_heap_end, KERN_ALIGN); + eubldr = roundup2((uint64_t)uboot_heap_end, KERN_ALIGN); for (i = 0; i < si->mr_no; i++) { if (si->mr[i].flags != MR_ATTR_DRAM) continue; - sblock = roundup2(si->mr[i].start, KERN_ALIGN); - eblock = rounddown2(si->mr[i].start + si->mr[i].size, + sblock = roundup2((uint64_t)si->mr[i].start, KERN_ALIGN); + eblock = rounddown2((uint64_t)si->mr[i].start + + si->mr[i].size, KERN_ALIGN); if (biggest_size == 0) sblock += KERN_MINADDR; if (subldr >= sblock && subldr < eblock) { @@ -127,9 +128,10 @@ uboot_loadaddr(u_int type, void *data, uint64_t addr) if (biggest_size == 0) panic("Not enough DRAM to load kernel\n"); #if 0 - printf("Loading kernel into region 0x%08x-0x%08x (%u MiB)\n", - biggest_block, biggest_block + biggest_size - 1, - biggest_size / 1024 / 1024); + printf("Loading kernel into region 0x%08jx-0x%08jx (%ju MiB)\n", + (uintmax_t)biggest_block, + (uintmax_t)biggest_block + biggest_size - 1, + (uintmax_t)biggest_size / 1024 / 1024); #endif return (biggest_block); } -- cgit v1.1