Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 7 Dec 2009 16:29:43 +0000 (UTC)
From:      John Baldwin <jhb@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r200219 - in head/sys/boot/i386: libi386 loader
Message-ID:  <200912071629.nB7GThqX059293@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: jhb
Date: Mon Dec  7 16:29:43 2009
New Revision: 200219
URL: http://svn.freebsd.org/changeset/base/200219

Log:
  Improve the algorithm the loader uses to choose a memory range for its
  heap when using a range above 1MB.
  
  Previously the loader would always use the last 3MB in the first memory
  range above 1MB for the heap.  However, this memory range is also where the
  kernel and any modules are loaded.  If this memory range is "small", then
  using the high 3MB for the heap may not leave enough room for the kernel
  and modules.
  
  Now the loader will use any range below 4GB for the heap, and the logic to
  choose the "high" heap region has moved into biosmem.c.  It sets two
  variables that the loader can use for a high heap if it desires.  When a
  high heap is enabled (BZIP2, FireWire, GPT, or ZFS), then the following
  memory ranges are preferred for the heap in order from best to worst:
  - The largest memory region in the SMAP with a start address greater than
    1MB.  The memory region must be at least 3MB in length.  This leaves the
    region starting at 1MB purely for use by the kernel and modules.
  - The last 3MB of the memory region starting at 1MB if it is at least 3MB
    in size.  This matches the current behavior except that the current loader
    would break horribly if the first region was not at least 3MB in size.
  - The memory range from the end of the loader up to the 640k window.  This
    is the range the loader uses when none of the high-heap-requesting options
    are enabled.
  
  Tested by:	hrs
  MFC after:	1 week

Modified:
  head/sys/boot/i386/libi386/biosmem.c
  head/sys/boot/i386/libi386/libi386.h
  head/sys/boot/i386/loader/main.c

Modified: head/sys/boot/i386/libi386/biosmem.c
==============================================================================
--- head/sys/boot/i386/libi386/biosmem.c	Mon Dec  7 16:23:25 2009	(r200218)
+++ head/sys/boot/i386/libi386/biosmem.c	Mon Dec  7 16:29:43 2009	(r200219)
@@ -35,14 +35,20 @@ __FBSDID("$FreeBSD$");
 #include "libi386.h"
 #include "btxv86.h"
 
-vm_offset_t	memtop, memtop_copyin;
-uint32_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 @@ bios_getmem(void)
 	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,4 +123,13 @@ bios_getmem(void)
     /* 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;
+    }
 }    

Modified: head/sys/boot/i386/libi386/libi386.h
==============================================================================
--- head/sys/boot/i386/libi386/libi386.h	Mon Dec  7 16:23:25 2009	(r200218)
+++ head/sys/boot/i386/libi386/libi386.h	Mon Dec  7 16:29:43 2009	(r200219)
@@ -99,6 +99,8 @@ extern vm_offset_t	memtop_copyin;	/* mem
 					/*  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);

Modified: head/sys/boot/i386/loader/main.c
==============================================================================
--- head/sys/boot/i386/loader/main.c	Mon Dec  7 16:23:25 2009	(r200218)
+++ head/sys/boot/i386/loader/main.c	Mon Dec  7 16:29:43 2009	(r200219)
@@ -104,13 +104,17 @@ main(void)
 
 #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 (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);
 
     /* 



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