The patch to CURRENT below is an extended version of a patch originally done by Adrian and accomplishes the following: * Add a quirks table based on BIOS vendor / maker / product (NULL matches any), making use of the new smbios_match function * pass in an smap+acpi entry size for e820; like what biossmap.c does; * don't blindly believe e820 if it doesn't give us enough memory to successfully load things, but ONLY if the machine is listed as BQ_DISTRUST_E820_EXTMEM in the quirks table (in this patch this is only the Acer C720 aka Peppy, since it was the reason to write this patch). There are probably other models out there with these issues, but without data it's probably best to add them one at a time. * don't blindly concat cx/dx with e801 - ensure that cx indicates there's no hole and there's a full 15mb of ram before concat'ing; * truncate how much RAM we probe for via e801 (which adrian doesn't entirely think is needed) * if we use e801, don't use the heap as-is; use the end of bios_extmem instead as if we didn't get anything from E820; * add a boot loader command "biosmem" which give details about how memory was detected The code has already been reviewed and more details can be found here: https://reviews.freebsd.org/D1741 It would be great, if a few more people could take a look at this and test it before it's committed to HEAD. Thanks, Michael Index: sys/boot/i386/libi386/biosmem.c =================================================================== diff --git a/head/sys/boot/i386/libi386/biosmem.c b/head/sys/boot/i386/libi386/biosmem.c --- a/head/sys/boot/i386/libi386/biosmem.c (revision 277957) +++ b/head/sys/boot/i386/libi386/biosmem.c (working copy) _at__at_ -32,6 +32,7 _at__at_ */ #include <stand.h> #include <machine/pc/bios.h> +#include "bootstrap.h" #include "libi386.h" #include "btxv86.h" _at__at_ -38,13 +39,56 _at__at_ 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) { _at__at_ -56,7 +100,7 _at__at_ 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); _at__at_ -65,11 +109,17 _at__at_ 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)) { + /* we need it to be at least 32MiB or -HEAD won't load */ + if ((smap.type == SMAP_TYPE_MEMORY) && (smap.base == 0x100000) && + (smap.length >= (32 * 1024 * 1024) || + !(bios_getquirks() & BQ_DISTRUST_E820_EXTMEM))) { bios_extmem = smap.length; + b_bios_probed |= B_EXTMEM_E820; } /* _at__at_ -100,6 +150,7 _at__at_ v86int(); bios_basemem = (v86.eax & 0xffff) * 1024; + b_bios_probed |= B_BASEMEM_12; } /* Fall back through several compatibility functions for extended memory */ _at__at_ -109,7 +160,29 _at__at_ 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) { _at__at_ -118,6 +191,7 _at__at_ v86.eax = 0x8800; v86int(); bios_extmem = (v86.eax & 0xffff) * 1024; + b_bios_probed |= B_EXTMEM_8800; } /* Set memtop to actual top of memory */ _at__at_ -132,4 +206,36 _at__at_ 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(smap, "biosmem", "show BIOS memory setup", command_biosmem); -- Michael GmelinReceived on Sat Feb 07 2015 - 17:03:22 UTC
This archive was generated by hypermail 2.4.0 : Wed May 19 2021 - 11:40:55 UTC