diff options
author | Toomas Soome <tsoome@me.com> | 2017-09-12 11:10:15 +0300 |
---|---|---|
committer | Dan McDonald <danmcd@joyent.com> | 2017-09-19 14:32:14 -0400 |
commit | 1ed324dd33fca02192d31bad13a72f6531ad4918 (patch) | |
tree | 9cd5f2051c3ec025906db90f6d160337aab02d59 | |
parent | 0827cc77d5fbb0420473ad22f969348c3e6f7401 (diff) | |
download | illumos-joyent-1ed324dd33fca02192d31bad13a72f6531ad4918.tar.gz |
8651 loader: biosmem allocate heap just below 4GB
Reviewed by: Robert Mustacchi <rm@joyent.com>
Reviewed by: Igor Kozhukhov <igor@dilos.org>
Reviewed by: C Fraire <cfraire@me.com>
Reviewed by: Ken Mays <maybird1776@yahoo.com>
Approved by: Dan McDonald <danmcd@joyent.com>
-rw-r--r-- | usr/src/boot/sys/boot/i386/libi386/biosmem.c | 273 |
1 files changed, 144 insertions, 129 deletions
diff --git a/usr/src/boot/sys/boot/i386/libi386/biosmem.c b/usr/src/boot/sys/boot/i386/libi386/biosmem.c index 38160da601..ad59d61bf9 100644 --- a/usr/src/boot/sys/boot/i386/libi386/biosmem.c +++ b/usr/src/boot/sys/boot/i386/libi386/biosmem.c @@ -1,4 +1,4 @@ -/*- +/* * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> * All rights reserved. * @@ -32,7 +32,6 @@ #include <stand.h> #include <machine/pc/bios.h> #include "bootstrap.h" -#include "smbios.h" #include "libi386.h" #include "btxv86.h" #include "smbios.h" @@ -63,150 +62,166 @@ static uint8_t b_bios_probed; * memory correctly. You need both maker and product as * reported by smbios. */ -#define BQ_DISTRUST_E820_EXTMEM 0x1 /* e820 might not return useful - extended memory */ +/* e820 might not return useful extended memory */ +#define BQ_DISTRUST_E820_EXTMEM 0x1 struct bios_getmem_quirks { - const char* bios_vendor; - const char* maker; - const char* product; - int quirk; + const char *bios_vendor; + const char *maker; + const char *product; + int quirk; }; static struct bios_getmem_quirks quirks[] = { - {"coreboot", "Acer", "Peppy", BQ_DISTRUST_E820_EXTMEM}, - {NULL, NULL, NULL, 0} + {"coreboot", "Acer", "Peppy", BQ_DISTRUST_E820_EXTMEM}, + {NULL, NULL, NULL, 0} }; static int bios_getquirks(void) { - int i; + int i; - for (i=0; quirks[i].quirk != 0; ++i) - if (smbios_match(quirks[i].bios_vendor, quirks[i].maker, - quirks[i].product)) - return (quirks[i].quirk); + for (i = 0; quirks[i].quirk != 0; ++i) { + if (smbios_match(quirks[i].bios_vendor, quirks[i].maker, + quirks[i].product)) + return (quirks[i].quirk); + } - return (0); + return (0); } void bios_getmem(void) { - uint64_t size; - - /* Parse system memory map */ - v86.ebx = 0; - do { - v86.ctl = V86_FLAGS; - v86.addr = 0x15; /* int 0x15 function 0xe820*/ - v86.eax = 0xe820; - v86.ecx = sizeof(struct bios_smap_xattr); - v86.edx = SMAP_SIG; - v86.es = VTOPSEG(&smap); - v86.edi = VTOPOFF(&smap); - v86int(); - if ((V86_CY(v86.efl)) || (v86.eax != SMAP_SIG)) - break; - /* look for a low-memory segment that's large enough */ - if ((smap.type == SMAP_TYPE_MEMORY) && (smap.base == 0) && - (smap.length >= (512 * 1024))) { - bios_basemem = smap.length; - b_bios_probed |= B_BASEMEM_E820; - } + uint64_t size; + + /* Parse system memory map */ + v86.ebx = 0; + do { + v86.ctl = V86_FLAGS; + v86.addr = 0x15; /* int 0x15 function 0xe820 */ + v86.eax = 0xe820; + v86.ecx = sizeof (struct bios_smap_xattr); + v86.edx = SMAP_SIG; + v86.es = VTOPSEG(&smap); + v86.edi = VTOPOFF(&smap); + v86int(); + if ((V86_CY(v86.efl)) || (v86.eax != SMAP_SIG)) + break; + /* look for a low-memory segment that's large enough */ + if ((smap.type == SMAP_TYPE_MEMORY) && (smap.base == 0) && + (smap.length >= (512 * 1024))) { + bios_basemem = smap.length; + b_bios_probed |= B_BASEMEM_E820; + } + + /* look for the first segment in 'extended' memory */ + if ((smap.type == SMAP_TYPE_MEMORY) && + (smap.base == 0x100000) && + !(bios_getquirks() & BQ_DISTRUST_E820_EXTMEM)) { + bios_extmem = smap.length; + b_bios_probed |= B_EXTMEM_E820; + } + + /* + * Look for the highest 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; + + /* + * To make maximum space for the kernel and the modules, + * set heap to use highest HEAP_MIN bytes below 4GB. + */ + if (high_heap_base < smap.base && size >= HEAP_MIN) { + high_heap_base = smap.base + size - HEAP_MIN; + high_heap_size = HEAP_MIN; + } + } + } while (v86.ebx != 0); + + /* Fall back to the old compatibility function for base memory */ + if (bios_basemem == 0) { + v86.ctl = 0; + v86.addr = 0x12; /* int 0x12 */ + v86int(); - /* look for the first segment in 'extended' memory */ - if ((smap.type == SMAP_TYPE_MEMORY) && (smap.base == 0x100000) && - !(bios_getquirks() & BQ_DISTRUST_E820_EXTMEM)) { - bios_extmem = smap.length; - b_bios_probed |= B_EXTMEM_E820; + bios_basemem = (v86.eax & 0xffff) * 1024; + b_bios_probed |= B_BASEMEM_12; } /* - * Look for the largest segment in 'extended' memory beyond - * 1MB but below 4GB. + * Fall back through several compatibility functions for extended + * memory. */ - 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; - } + if (bios_extmem == 0) { + v86.ctl = V86_FLAGS; + v86.addr = 0x15; /* int 0x15 function 0xe801 */ + v86.eax = 0xe801; + v86int(); + if (!(V86_CY(v86.efl))) { + /* + * Clear high_heap; it may end up overlapping + * with the segment we're determining here. + * Let the default "steal stuff from top of + * bios_extmem" code below pick up on it. + */ + high_heap_size = 0; + high_heap_base = 0; + + /* + * %cx is the number of 1KiB blocks between 1..16MiB. + * It can only be up to 0x3c00; if it's smaller then + * there's a PC AT memory hole so we can't treat + * it as contiguous. + */ + bios_extmem = (v86.ecx & 0xffff) * 1024; + if (bios_extmem == (1024 * 0x3c00)) + bios_extmem += (v86.edx & 0xffff) * 64 * 1024; + + /* truncate bios_extmem */ + if (bios_extmem > 0x3ff00000) + bios_extmem = 0x3ff00000; + + b_bios_probed |= B_EXTMEM_E801; + } } - } while (v86.ebx != 0); - - /* Fall back to the old compatibility function for base memory */ - if (bios_basemem == 0) { - v86.ctl = 0; - v86.addr = 0x12; /* int 0x12 */ - v86int(); - - bios_basemem = (v86.eax & 0xffff) * 1024; - b_bios_probed |= B_BASEMEM_12; - } - - /* Fall back through several compatibility functions for extended memory */ - if (bios_extmem == 0) { - v86.ctl = V86_FLAGS; - v86.addr = 0x15; /* int 0x15 function 0xe801*/ - v86.eax = 0xe801; - v86int(); - if (!(V86_CY(v86.efl))) { - /* - * Clear high_heap; it may end up overlapping - * with the segment we're determining here. - * Let the default "steal stuff from top of - * bios_extmem" code below pick up on it. - */ - high_heap_size = 0; - high_heap_base = 0; - - /* - * %cx is the number of 1KiB blocks between 1..16MiB. - * It can only be up to 0x3c00; if it's smaller then - * there's a PC AT memory hole so we can't treat - * it as contiguous. - */ - bios_extmem = (v86.ecx & 0xffff) * 1024; - if (bios_extmem == (1024 * 0x3c00)) - bios_extmem += (v86.edx & 0xffff) * 64 * 1024; - - /* truncate bios_extmem */ - if (bios_extmem > 0x3ff00000) - bios_extmem = 0x3ff00000; - - b_bios_probed |= B_EXTMEM_E801; + if (bios_extmem == 0) { + v86.ctl = 0; + v86.addr = 0x15; /* int 0x15 function 0x88 */ + v86.eax = 0x8800; + v86int(); + bios_extmem = (v86.eax & 0xffff) * 1024; + b_bios_probed |= B_EXTMEM_8800; + } + + /* Set memtop to actual top of memory */ + if (high_heap_size != 0) { + memtop = memtop_copyin = high_heap_base; + } else { + 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 HEAP_MIN 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; + memtop = memtop_copyin = high_heap_base; } - } - if (bios_extmem == 0) { - v86.ctl = 0; - v86.addr = 0x15; /* int 0x15 function 0x88*/ - v86.eax = 0x8800; - v86int(); - bios_extmem = (v86.eax & 0xffff) * 1024; - b_bios_probed |= B_EXTMEM_8800; - } - - /* 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; - } } #ifndef BOOT2 @@ -215,16 +230,16 @@ command_biosmem(int argc, char *argv[]) { int bq = bios_getquirks(); - printf("bios_basemem: 0x%llx\n", (unsigned long long) bios_basemem); - printf("bios_extmem: 0x%llx\n", (unsigned long long) bios_extmem); - printf("memtop: 0x%llx\n", (unsigned long long) memtop); - printf("high_heap_base: 0x%llx\n", (unsigned long long) high_heap_base); - printf("high_heap_size: 0x%llx\n", (unsigned long long) high_heap_size); + printf("bios_basemem: 0x%llx\n", (unsigned long long)bios_basemem); + printf("bios_extmem: 0x%llx\n", (unsigned long long)bios_extmem); + printf("memtop: 0x%llx\n", (unsigned long long)memtop); + printf("high_heap_base: 0x%llx\n", (unsigned long long)high_heap_base); + printf("high_heap_size: 0x%llx\n", (unsigned long long)high_heap_size); printf("bios_quirks: 0x%02x", bq); if (bq & BQ_DISTRUST_E820_EXTMEM) printf(" BQ_DISTRUST_E820_EXTMEM"); printf("\n"); - printf("b_bios_probed: 0x%02x", (int) b_bios_probed); + printf("b_bios_probed: 0x%02x", (int)b_bios_probed); if (b_bios_probed & B_BASEMEM_E820) printf(" B_BASEMEM_E820"); if (b_bios_probed & B_BASEMEM_12) |