Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 24 Jan 2016 22:00:36 +0000 (UTC)
From:      Ian Lepore <ian@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org
Subject:   svn commit: r294685 - in stable/10/sys: arm/arm boot/uboot/lib
Message-ID:  <201601242200.u0OM0anN024060@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: ian
Date: Sun Jan 24 22:00:36 2016
New Revision: 294685
URL: https://svnweb.freebsd.org/changeset/base/294685

Log:
  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

Modified:
  stable/10/sys/arm/arm/physmem.c
  stable/10/sys/boot/uboot/lib/copy.c
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/sys/arm/arm/physmem.c
==============================================================================
--- stable/10/sys/arm/arm/physmem.c	Sun Jan 24 21:18:54 2016	(r294684)
+++ stable/10/sys/arm/arm/physmem.c	Sun Jan 24 22:00:36 2016	(r294685)
@@ -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, uint
 	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, uint
 			 * 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, uint
 		 * 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 p
 	/*
 	 * 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;
 	}
 
 	/*

Modified: stable/10/sys/boot/uboot/lib/copy.c
==============================================================================
--- stable/10/sys/boot/uboot/lib/copy.c	Sun Jan 24 21:18:54 2016	(r294684)
+++ stable/10/sys/boot/uboot/lib/copy.c	Sun Jan 24 22:00:36 2016	(r294685)
@@ -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, u
 		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, u
 		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);
 	}



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201601242200.u0OM0anN024060>