Changeset View
Changeset View
Standalone View
Standalone View
sys/boot/i386/libi386/biosmem.c
Show All 26 Lines | |||||
#include <sys/cdefs.h> | #include <sys/cdefs.h> | ||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
/* | /* | ||||
* Obtain memory configuration information from the BIOS | * Obtain memory configuration information from the BIOS | ||||
*/ | */ | ||||
#include <stand.h> | #include <stand.h> | ||||
#include <machine/pc/bios.h> | #include <machine/pc/bios.h> | ||||
#include "bootstrap.h" | |||||
#include "libi386.h" | #include "libi386.h" | ||||
#include "btxv86.h" | #include "btxv86.h" | ||||
vm_offset_t memtop, memtop_copyin, high_heap_base; | vm_offset_t memtop, memtop_copyin, high_heap_base; | ||||
uint32_t bios_basemem, bios_extmem, high_heap_size; | 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. | * The minimum amount of memory to reserve in bios_extmem for the heap. | ||||
*/ | */ | ||||
#define HEAP_MIN (3 * 1024 * 1024) | #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 | void | ||||
bios_getmem(void) | bios_getmem(void) | ||||
{ | { | ||||
uint64_t size; | uint64_t size; | ||||
/* Parse system memory map */ | /* Parse system memory map */ | ||||
v86.ebx = 0; | v86.ebx = 0; | ||||
do { | do { | ||||
v86.ctl = V86_FLAGS; | v86.ctl = V86_FLAGS; | ||||
v86.addr = 0x15; /* int 0x15 function 0xe820*/ | v86.addr = 0x15; /* int 0x15 function 0xe820*/ | ||||
v86.eax = 0xe820; | v86.eax = 0xe820; | ||||
v86.ecx = sizeof(struct bios_smap); | v86.ecx = sizeof(struct bios_smap_xattr); | ||||
v86.edx = SMAP_SIG; | v86.edx = SMAP_SIG; | ||||
v86.es = VTOPSEG(&smap); | v86.es = VTOPSEG(&smap); | ||||
v86.edi = VTOPOFF(&smap); | v86.edi = VTOPOFF(&smap); | ||||
v86int(); | v86int(); | ||||
if ((V86_CY(v86.efl)) || (v86.eax != SMAP_SIG)) | if ((V86_CY(v86.efl)) || (v86.eax != SMAP_SIG)) | ||||
break; | break; | ||||
/* look for a low-memory segment that's large enough */ | /* look for a low-memory segment that's large enough */ | ||||
if ((smap.type == SMAP_TYPE_MEMORY) && (smap.base == 0) && | if ((smap.type == SMAP_TYPE_MEMORY) && (smap.base == 0) && | ||||
(smap.length >= (512 * 1024))) | (smap.length >= (512 * 1024))) { | ||||
bios_basemem = smap.length; | bios_basemem = smap.length; | ||||
b_bios_probed |= B_BASEMEM_E820; | |||||
} | |||||
/* look for the first segment in 'extended' memory */ | /* 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; | bios_extmem = smap.length; | ||||
jhb: I think you don't need the 32MB check now if you have the quirk check.
If you do, please… | |||||
b_bios_probed |= B_EXTMEM_E820; | |||||
} | } | ||||
/* | /* | ||||
* Look for the largest segment in 'extended' memory beyond | * Look for the largest segment in 'extended' memory beyond | ||||
* 1MB but below 4GB. | * 1MB but below 4GB. | ||||
Not Done Inline ActionsI kept the check in here, the idea is that we might want to be a bit bolder in the quirks table in the future (let's say: all coreboot machines), but only use the fallback code, in case the numbers returned aren't good. Does this make sense to you or do you think that's not a realistic scenario anyway? grembo: I kept the check in here, the idea is that we might want to be a bit bolder in the quirks table… | |||||
*/ | */ | ||||
if ((smap.type == SMAP_TYPE_MEMORY) && (smap.base > 0x100000) && | if ((smap.type == SMAP_TYPE_MEMORY) && (smap.base > 0x100000) && | ||||
(smap.base < 0x100000000ull)) { | (smap.base < 0x100000000ull)) { | ||||
size = smap.length; | size = smap.length; | ||||
/* | /* | ||||
* If this segment crosses the 4GB boundary, truncate it. | * If this segment crosses the 4GB boundary, truncate it. | ||||
*/ | */ | ||||
Show All 9 Lines | if ((smap.type == SMAP_TYPE_MEMORY) && (smap.base > 0x100000) && | ||||
/* Fall back to the old compatibility function for base memory */ | /* Fall back to the old compatibility function for base memory */ | ||||
if (bios_basemem == 0) { | if (bios_basemem == 0) { | ||||
v86.ctl = 0; | v86.ctl = 0; | ||||
v86.addr = 0x12; /* int 0x12 */ | v86.addr = 0x12; /* int 0x12 */ | ||||
v86int(); | v86int(); | ||||
bios_basemem = (v86.eax & 0xffff) * 1024; | bios_basemem = (v86.eax & 0xffff) * 1024; | ||||
b_bios_probed |= B_BASEMEM_12; | |||||
} | } | ||||
/* Fall back through several compatibility functions for extended memory */ | /* Fall back through several compatibility functions for extended memory */ | ||||
if (bios_extmem == 0) { | if (bios_extmem == 0) { | ||||
v86.ctl = V86_FLAGS; | v86.ctl = V86_FLAGS; | ||||
v86.addr = 0x15; /* int 0x15 function 0xe801*/ | v86.addr = 0x15; /* int 0x15 function 0xe801*/ | ||||
v86.eax = 0xe801; | v86.eax = 0xe801; | ||||
v86int(); | v86int(); | ||||
if (!(V86_CY(v86.efl))) { | 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; | |||||
Not Done Inline ActionsPlease add a blank line here before the comment. jhb: Please add a blank line here before the comment. | |||||
/* | |||||
Not Done Inline ActionsPlease use '%cx' for register names. jhb: Please use '%cx' for register names. | |||||
* %cx is the number of 1KiB blocks between 1..16MiB. | |||||
Not Done Inline ActionsI hope I got this right (%cx) grembo: I hope I got this right (%cx) | |||||
* 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) { | if (bios_extmem == 0) { | ||||
v86.ctl = 0; | v86.ctl = 0; | ||||
v86.addr = 0x15; /* int 0x15 function 0x88*/ | v86.addr = 0x15; /* int 0x15 function 0x88*/ | ||||
v86.eax = 0x8800; | v86.eax = 0x8800; | ||||
v86int(); | v86int(); | ||||
bios_extmem = (v86.eax & 0xffff) * 1024; | bios_extmem = (v86.eax & 0xffff) * 1024; | ||||
b_bios_probed |= B_EXTMEM_8800; | |||||
} | } | ||||
/* Set memtop to actual top of memory */ | /* Set memtop to actual top of memory */ | ||||
memtop = memtop_copyin = 0x100000 + bios_extmem; | memtop = memtop_copyin = 0x100000 + bios_extmem; | ||||
/* | /* | ||||
* If we have extended memory and did not find a suitable heap | * 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 | * region in the SMAP, use the last 3MB of 'extended' memory as a | ||||
* high heap candidate. | * high heap candidate. | ||||
*/ | */ | ||||
if (bios_extmem >= HEAP_MIN && high_heap_size < HEAP_MIN) { | if (bios_extmem >= HEAP_MIN && high_heap_size < HEAP_MIN) { | ||||
high_heap_size = HEAP_MIN; | high_heap_size = HEAP_MIN; | ||||
high_heap_base = memtop - 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); | |||||
Not Done Inline ActionsWhy "smap"? This should probably be 'biosmem' instead. I think it is just used to name the internal structure stored in the linker set, but it would be more consistent to have the name here match the command name (or at least be relevant). jhb: Why "smap"? This should probably be 'biosmem' instead. I think it is just used to name the… |
I think you don't need the 32MB check now if you have the quirk check.
If you do, please reformat the comment. It should be a block comment instead of two line comments, but also fix the punctuation / capitalization while you are there and add a blank before the comment block. (I'd probably just drop the 32MB check though.)