From owner-svn-src-all@FreeBSD.ORG Mon Feb 23 22:58:53 2015 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 0A839832; Mon, 23 Feb 2015 22:58:53 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id DEE0ED47; Mon, 23 Feb 2015 22:58:52 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.9/8.14.9) with ESMTP id t1NMwqPk096950; Mon, 23 Feb 2015 22:58:52 GMT (envelope-from grembo@FreeBSD.org) Received: (from grembo@localhost) by svn.freebsd.org (8.14.9/8.14.9/Submit) id t1NMwql8096949; Mon, 23 Feb 2015 22:58:52 GMT (envelope-from grembo@FreeBSD.org) Message-Id: <201502232258.t1NMwql8096949@svn.freebsd.org> X-Authentication-Warning: svn.freebsd.org: grembo set sender to grembo@FreeBSD.org using -f From: Michael Gmelin Date: Mon, 23 Feb 2015 22:58:52 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r279222 - head/sys/boot/i386/libi386 X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 23 Feb 2015 22:58:53 -0000 Author: grembo (ports committer) Date: Mon Feb 23 22:58:51 2015 New Revision: 279222 URL: https://svnweb.freebsd.org/changeset/base/279222 Log: Improve memory detection in biosmem.c - Add a quirk to allow ignoring e820 extended memory detection. - Improve memory detection through e801. - Add bootloader command "biosmem". See differential revision for more details. Reviewed by: jhb, adrian Approved by: adrian Differential Revision: https://reviews.freebsd.org/D1741 Modified: head/sys/boot/i386/libi386/biosmem.c Modified: head/sys/boot/i386/libi386/biosmem.c ============================================================================== --- head/sys/boot/i386/libi386/biosmem.c Mon Feb 23 22:50:43 2015 (r279221) +++ head/sys/boot/i386/libi386/biosmem.c Mon Feb 23 22:58:51 2015 (r279222) @@ -32,19 +32,63 @@ __FBSDID("$FreeBSD$"); */ #include #include +#include "bootstrap.h" #include "libi386.h" #include "btxv86.h" vm_offset_t memtop, memtop_copyin, high_heap_base; uint32_t bios_basemem, bios_extmem, high_heap_size; -static struct bios_smap smap; +static struct bios_smap_xattr smap; + +/* + * Used to track which method was used to set BIOS memory + * regions. + */ +static uint8_t b_bios_probed; +#define B_BASEMEM_E820 0x1 +#define B_BASEMEM_12 0x2 +#define B_EXTMEM_E820 0x4 +#define B_EXTMEM_E801 0x8 +#define B_EXTMEM_8800 0x10 /* * The minimum amount of memory to reserve in bios_extmem for the heap. */ #define HEAP_MIN (3 * 1024 * 1024) +/* + * Products in this list need quirks to detect + * 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 */ +struct bios_getmem_quirks { + 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} +}; + +static int +bios_getquirks(void) +{ + 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); + + return (0); +} + void bios_getmem(void) { @@ -56,7 +100,7 @@ bios_getmem(void) v86.ctl = V86_FLAGS; v86.addr = 0x15; /* int 0x15 function 0xe820*/ v86.eax = 0xe820; - v86.ecx = sizeof(struct bios_smap); + v86.ecx = sizeof(struct bios_smap_xattr); v86.edx = SMAP_SIG; v86.es = VTOPSEG(&smap); v86.edi = VTOPOFF(&smap); @@ -65,11 +109,16 @@ bios_getmem(void) break; /* look for a low-memory segment that's large enough */ if ((smap.type == SMAP_TYPE_MEMORY) && (smap.base == 0) && - (smap.length >= (512 * 1024))) + (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)) { + 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; } /* @@ -100,6 +149,7 @@ bios_getmem(void) v86int(); bios_basemem = (v86.eax & 0xffff) * 1024; + b_bios_probed |= B_BASEMEM_12; } /* Fall back through several compatibility functions for extended memory */ @@ -109,7 +159,30 @@ bios_getmem(void) v86.eax = 0xe801; v86int(); if (!(V86_CY(v86.efl))) { - bios_extmem = ((v86.ecx & 0xffff) + ((v86.edx & 0xffff) * 64)) * 1024; + /* + * 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) { @@ -118,6 +191,7 @@ bios_getmem(void) v86.eax = 0x8800; v86int(); bios_extmem = (v86.eax & 0xffff) * 1024; + b_bios_probed |= B_EXTMEM_8800; } /* Set memtop to actual top of memory */ @@ -132,4 +206,36 @@ bios_getmem(void) high_heap_size = HEAP_MIN; high_heap_base = memtop - HEAP_MIN; } -} +} + +static int +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_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); + if (b_bios_probed & B_BASEMEM_E820) + printf(" B_BASEMEM_E820"); + if (b_bios_probed & B_BASEMEM_12) + printf(" B_BASEMEM_12"); + if (b_bios_probed & B_EXTMEM_E820) + printf(" B_EXTMEM_E820"); + if (b_bios_probed & B_EXTMEM_E801) + printf(" B_EXTMEM_E801"); + if (b_bios_probed & B_EXTMEM_8800) + printf(" B_EXTMEM_8800"); + printf("\n"); + + return (CMD_OK); +} + +COMMAND_SET(biosmem, "biosmem", "show BIOS memory setup", command_biosmem);