Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 4 Dec 2009 17:34:23 -0500
From:      John Baldwin <jhb@freebsd.org>
To:        Hiroki Sato <hrs@freebsd.org>
Cc:        freebsd-stable@freebsd.org
Subject:   Re: loader(8) readin failed on 7.2R and later including 8.0R
Message-ID:  <200912041734.24016.jhb@freebsd.org>
In-Reply-To: <200912041035.59173.jhb@freebsd.org>
References:  <200912020948.05698.jhb@freebsd.org> <20091204.062008.155444535.hrs@allbsd.org> <200912041035.59173.jhb@freebsd.org>

next in thread | previous in thread | raw e-mail | index | archive | help
--Boundary-00=_w5YGLS62F3/9EXj
Content-Type: Text/Plain;
  charset="iso-8859-15"
Content-Transfer-Encoding: 7bit

On Friday 04 December 2009 10:35:59 am John Baldwin wrote:
> On Thursday 03 December 2009 4:20:08 pm Hiroki Sato wrote:
> > John Baldwin <jhb@freebsd.org> wrote
> >   in <200912030803.29797.jhb@freebsd.org>:
> > 
> > jh> On Thursday 03 December 2009 5:29:13 am Hiroki Sato wrote:
> > jh> > John Baldwin <jhb@freebsd.org> wrote
> > jh> >   in <200912020948.05698.jhb@freebsd.org>:
> > jh> >
> > jh> > jh> On Tuesday 01 December 2009 12:13:39 pm Hiroki Sato wrote:
> > jh> > jh> >  While the "load" command seemed to finish, the box got stuck just
> > jh> > jh> >  after entering "boot" command.
> > jh> > jh> >
> > jh> > jh> >  Curious to say, I have got this symptom only on a specific box in
> > jh> > jh> >  more than ten different boxes I upgraded so far; it is based on an
> > jh> > jh> >  old motherboard Supermicro P4DPE[*].
> > jh> > jh> >
> > jh> > jh> >  [*]
> > jh> http://www.supermicro.com/products/motherboard/Xeon/E7500/P4DPE.cfm
> > jh> > jh> >
> > jh> > jh> >  Any workaround?  Booting from release CDROMs (7.2R and 8.0R) also
> > jh> > jh> >  fail.  On the box "7.1R" or "7.1R's loader + 7.2R kernel" worked
> > jh> > jh> >  fine.  It is possible something in changes of loader(8) between 7.1R
> > jh> > jh> >  and 7.2R is the cause, but I am still not sure what it is...
> > jh> > jh>
> > jh> > jh> It may be related to the loader switching to using memory > 1MB for its
> > jh> > jh> malloc().  Maybe try building the loader with
> > jh> 'LOADER_NO_GPT_SUPPORT=yes' in
> > jh> > jh> /etc/src.conf?
> > jh> >
> > jh> >  Thanks, a recompiled loader with LOADER_NO_GPT_SUPPORT=yes' displayed
> > jh> >  "elf32_loadimage: could not read symbols - skipped!" for 8.0R kernel.
> > jh> >  This is the same as 7.1R's loader + 8.0R kernel case.
> > jh>
> > jh> Can you get the output of 'smap' from the loader?  Is the 8.0 kernel bigger
> > jh> than the 7.x kernel?  If so, can you try trimming the 8.0 kernel a bit to see
> > jh> if that changes things?
> > 
> >  Sure.  Output of smap on an 8.0R loader with LOADER_NO_GPT_SUPPORT=yes
> >  was:
> > 
> > | OK smap
> > | SMAP type=01 base=0000000000000000 len=000000000009f400
> > | SMAP type=02 base=000000000009f400 len=0000000000000c00
> > | SMAP type=02 base=00000000000dc000 len=0000000000024000
> > | SMAP type=01 base=0000000000100000 len=0000000000e00000
> 
> So this is the region that ends up getting used for malloc:
> 
> 	/* look for the first segment in 'extended' memory */
> 	if ((smap.type == SMAP_TYPE_MEMORY) && (smap.base == 0x100000)) {
> 	    bios_extmem = smap.length;
> 
> 	...
> 
>     /* Set memtop to actual top of memory */
>     memtop = memtop_copyin = 0x100000 + bios_extmem;
> 
> 
> and then later:
> 
> #if defined(LOADER_BZIP2_SUPPORT) || defined(LOADER_FIREWIRE_SUPPORT) || defined(LOADER_GPT_SUPPORT) || defined(LOADER_ZFS_SUPPORT)
>     heap_top = PTOV(memtop_copyin);
>     memtop_copyin -= 0x300000;
>     heap_bottom = PTOV(memtop_copyin);
> #else
> 
> So memtop_copyin would start off as 0xf00000 but would end up as 0xc00000,
> and since the kernel starts at 4MB, I think that only leaves about 8MB for
> the kernel.  Probably the loader needs to be more intelligent about using
> high memory for malloc by using the largest region > 1MB but < 4GB for
> malloc() instead of stealing memory from bios_extmem in the SMAP case.
> Try the attached patch which tries to make the loader use better smarts
> when picking a memory region for the heap (warning, I haven't tested it
> myself yet).

Use the updated patch (actually tested in qemu) instead.

-- 
John Baldwin

--Boundary-00=_w5YGLS62F3/9EXj
Content-Type: text/x-patch; charset="ISO-8859-1"; name="loader_heap.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
	filename="loader_heap.patch"

--- //depot/vendor/freebsd/src/sys/boot/i386/libi386/biosmem.c	2007/10/28 21:26:35
+++ //depot/user/jhb/boot/sys/boot/i386/libi386/biosmem.c	2009/12/04 22:20:17
@@ -35,14 +35,20 @@
 #include "libi386.h"
 #include "btxv86.h"
 
-vm_offset_t	memtop, memtop_copyin;
-u_int32_t	bios_basemem, bios_extmem;
+vm_offset_t	memtop, memtop_copyin, high_heap_base;
+uint32_t	bios_basemem, bios_extmem, high_heap_size;
 
 static struct bios_smap smap;
 
+/*
+ * The minimum amount of memory to reserve in bios_extmem for the heap.
+ */
+#define	HEAP_MIN	(3 * 1024 * 1024)
+
 void
 bios_getmem(void)
 {
+    uint64_t size;
 
     /* Parse system memory map */
     v86.ebx = 0;
@@ -65,6 +71,26 @@
 	if ((smap.type == SMAP_TYPE_MEMORY) && (smap.base == 0x100000)) {
 	    bios_extmem = smap.length;
 	}
+
+	/*
+	 * Look for the largest segment in 'extended' memory beyond
+	 * 1MB but below 4GB.
+	 */
+	if ((smap.type == SMAP_TYPE_MEMORY) && (smap.base > 0x100000) &&
+	    (smap.base < 0x100000000ull)) {
+	    size = smap.length;
+
+	    /*
+	     * If this segment crosses the 4GB boundary, truncate it.
+	     */
+	    if (smap.base + size > 0x100000000ull)
+		size = 0x100000000ull - smap.base;
+
+	    if (size > high_heap_size) {
+		high_heap_size = size;
+		high_heap_base = smap.base;
+	    }
+	}
     } while (v86.ebx != 0);
 
     /* Fall back to the old compatibility function for base memory */
@@ -97,5 +123,13 @@
     /* Set memtop to actual top of memory */
     memtop = memtop_copyin = 0x100000 + bios_extmem;
 
+    /*
+     * If we have extended memory and did not find a suitable heap
+     * region in the SMAP, use the last 3MB of 'extended' memory as a
+     * high heap candidate.
+     */
+    if (bios_extmem >= HEAP_MIN && high_heap_size < HEAP_MIN) {
+	high_heap_size = HEAP_MIN;
+	high_heap_base = memtop - HEAP_MIN;
+    }
 }    
-
--- //depot/vendor/freebsd/src/sys/boot/i386/libi386/libi386.h	2009/03/12 20:45:15
+++ //depot/user/jhb/boot/sys/boot/i386/libi386/libi386.h	2009/12/04 15:33:59
@@ -78,9 +78,9 @@
 int	bc_getdev(struct i386_devdesc *dev);	/* return dev_t for (dev) */
 int	bc_bios2unit(int biosdev);	/* xlate BIOS device -> bioscd unit */
 int	bc_unit2bios(int unit);		/* xlate bioscd unit -> BIOS device */
-u_int32_t	bd_getbigeom(int bunit);	/* return geometry in bootinfo format */
-int	bd_bios2unit(int biosdev);		/* xlate BIOS device -> biosdisk unit */
-int	bd_unit2bios(int unit);			/* xlate biosdisk unit -> BIOS device */
+uint32_t bd_getbigeom(int bunit);	/* return geometry in bootinfo format */
+int	bd_bios2unit(int biosdev);	/* xlate BIOS device -> biosdisk unit */
+int	bd_unit2bios(int unit);		/* xlate biosdisk unit -> BIOS device */
 int	bd_getdev(struct i386_devdesc *dev);	/* return dev_t for (dev) */
 
 ssize_t	i386_copyin(const void *src, vm_offset_t dest, const size_t len);
@@ -92,12 +92,15 @@
 void	bios_getsmap(void);
 
 void	bios_getmem(void);
-extern u_int32_t	bios_basemem;				/* base memory in bytes */
-extern u_int32_t	bios_extmem;				/* extended memory in bytes */
+extern uint32_t		bios_basemem;	/* base memory in bytes */
+extern uint32_t		bios_extmem;	/* extended memory in bytes */
 extern vm_offset_t	memtop;		/* last address of physical memory + 1 */
 extern vm_offset_t	memtop_copyin;	/* memtop less heap size for the cases */
-					/*  when heap is at the top of extended memory */
-					/*  for other cases - just the same as memtop */
+					/*  when heap is at the top of         */
+					/*  extended memory; for other cases   */
+					/*  just the same as memtop            */
+extern uint32_t		high_heap_size;	/* extended memory region available */
+extern vm_offset_t	high_heap_base;	/* for use as the heap */
 
 int biospci_find_devclass(uint32_t class, int index, uint32_t *locator);
 int biospci_write_config(uint32_t locator, int offset, int width, uint32_t val);
--- //depot/vendor/freebsd/src/sys/boot/i386/loader/main.c	2009/03/09 17:20:15
+++ //depot/user/jhb/boot/sys/boot/i386/loader/main.c	2009/12/04 22:09:08
@@ -102,14 +102,19 @@
      */
     bios_getmem();
 
-#if defined(LOADER_BZIP2_SUPPORT) || defined(LOADER_FIREWIRE_SUPPORT) || defined(LOADER_GPT_SUPPORT) || defined(LOADER_ZFS_SUPPORT)
-    heap_top = PTOV(memtop_copyin);
-    memtop_copyin -= 0x300000;
-    heap_bottom = PTOV(memtop_copyin);
-#else
-    heap_top = (void *)bios_basemem;
-    heap_bottom = (void *)end;
+#if defined(LOADER_BZIP2_SUPPORT) || defined(LOADER_FIREWIRE_SUPPORT) || \
+    defined(LOADER_GPT_SUPPORT) || defined(LOADER_ZFS_SUPPORT)
+    if (high_heap_size > 0) {
+	heap_top = PTOV(high_heap_base + high_heap_size);
+	heap_bottom = PTOV(high_heap_base);
+	if (high_heap_base < memtop_copyin)
+	    memtop_copyin = high_heap_base;
+    } else
 #endif
+    {
+	heap_top = (void *)PTOV(bios_basemem);
+	heap_bottom = (void *)end;
+    }
     setheap(heap_bottom, heap_top);
 

--Boundary-00=_w5YGLS62F3/9EXj--



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