diff options
author | jhb <jhb@FreeBSD.org> | 2009-12-07 16:29:43 +0000 |
---|---|---|
committer | jhb <jhb@FreeBSD.org> | 2009-12-07 16:29:43 +0000 |
commit | e69f7d5c358161e41d6e4412ad06a5cee751f800 (patch) | |
tree | 2f7b156da9c3a741320b8b69399de41f67f16012 /sys/boot/i386 | |
parent | 537829a1a5c6b64cbe5ba59839e82df8aa9dbd22 (diff) | |
download | FreeBSD-src-e69f7d5c358161e41d6e4412ad06a5cee751f800.zip FreeBSD-src-e69f7d5c358161e41d6e4412ad06a5cee751f800.tar.gz |
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
Diffstat (limited to 'sys/boot/i386')
-rw-r--r-- | sys/boot/i386/libi386/biosmem.c | 39 | ||||
-rw-r--r-- | sys/boot/i386/libi386/libi386.h | 2 | ||||
-rw-r--r-- | sys/boot/i386/loader/main.c | 16 |
3 files changed, 49 insertions, 8 deletions
diff --git a/sys/boot/i386/libi386/biosmem.c b/sys/boot/i386/libi386/biosmem.c index e62c1dd..bae6813 100644 --- a/sys/boot/i386/libi386/biosmem.c +++ b/sys/boot/i386/libi386/biosmem.c @@ -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; + } } diff --git a/sys/boot/i386/libi386/libi386.h b/sys/boot/i386/libi386/libi386.h index b3d144e..ebf1b4c 100644 --- a/sys/boot/i386/libi386/libi386.h +++ b/sys/boot/i386/libi386/libi386.h @@ -99,6 +99,8 @@ 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 */ +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); diff --git a/sys/boot/i386/loader/main.c b/sys/boot/i386/loader/main.c index e40ea1c..75d5dbc 100644 --- a/sys/boot/i386/loader/main.c +++ b/sys/boot/i386/loader/main.c @@ -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); /* |