131921Sbrian/*- 231921Sbrian * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> 331921Sbrian * All rights reserved. 431921Sbrian * 531921Sbrian * Redistribution and use in source and binary forms, with or without 631921Sbrian * modification, are permitted provided that the following conditions 731921Sbrian * are met: 831921Sbrian * 1. Redistributions of source code must retain the above copyright 931921Sbrian * notice, this list of conditions and the following disclaimer. 1031921Sbrian * 2. Redistributions in binary form must reproduce the above copyright 1131921Sbrian * notice, this list of conditions and the following disclaimer in the 1231921Sbrian * documentation and/or other materials provided with the distribution. 1331921Sbrian * 1431921Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1531921Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1631921Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1731921Sbrian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1831921Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1931921Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2031921Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2131921Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2231921Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2331921Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2431921Sbrian * SUCH DAMAGE. 2531921Sbrian */ 2646686Sbrian 2730715Sbrian#include <sys/cdefs.h> 2830715Sbrian__FBSDID("$FreeBSD$"); 2931196Sbrian 3044279Sbrian/* 3144279Sbrian * Obtain memory configuration information from the BIOS 3244279Sbrian */ 3344279Sbrian#include <stand.h> 3444279Sbrian#include <machine/pc/bios.h> 3544279Sbrian#include "libi386.h" 3644279Sbrian#include "btxv86.h" 3746085Sbrian 3830715Sbrianvm_offset_t memtop, memtop_copyin, high_heap_base; 3931121Sbrianuint32_t bios_basemem, bios_extmem, high_heap_size; 4046686Sbrian 4137192Sbrianstatic struct bios_smap smap; 4234539Sbrian 4337192Sbrian/* 4431196Sbrian * The minimum amount of memory to reserve in bios_extmem for the heap. 4530715Sbrian */ 4630715Sbrian#define HEAP_MIN (3 * 1024 * 1024) 4730715Sbrian 4846686Sbrianvoid 4946686Sbrianbios_getmem(void) 5030715Sbrian{ 5130715Sbrian uint64_t size; 5230715Sbrian 5336453Sbrian /* Parse system memory map */ 5437010Sbrian v86.ebx = 0; 5530715Sbrian do { 5630715Sbrian v86.ctl = V86_FLAGS; 5730715Sbrian v86.addr = 0x15; /* int 0x15 function 0xe820*/ 5830715Sbrian v86.eax = 0xe820; 5930715Sbrian v86.ecx = sizeof(struct bios_smap); 6031343Sbrian v86.edx = SMAP_SIG; 6136285Sbrian v86.es = VTOPSEG(&smap); 6231343Sbrian v86.edi = VTOPOFF(&smap); 6330715Sbrian v86int(); 6431196Sbrian if ((V86_CY(v86.efl)) || (v86.eax != SMAP_SIG)) 6536285Sbrian break; 6636285Sbrian /* look for a low-memory segment that's large enough */ 6736285Sbrian if ((smap.type == SMAP_TYPE_MEMORY) && (smap.base == 0) && 6836285Sbrian (smap.length >= (512 * 1024))) 6931196Sbrian bios_basemem = smap.length; 7036285Sbrian /* look for the first segment in 'extended' memory */ 7136285Sbrian if ((smap.type == SMAP_TYPE_MEMORY) && (smap.base == 0x100000)) { 7236285Sbrian bios_extmem = smap.length; 7336285Sbrian } 7436285Sbrian 7536285Sbrian /* 7636285Sbrian * Look for the largest segment in 'extended' memory beyond 7736285Sbrian * 1MB but below 4GB. 7836285Sbrian */ 7936285Sbrian if ((smap.type == SMAP_TYPE_MEMORY) && (smap.base > 0x100000) && 8036285Sbrian (smap.base < 0x100000000ull)) { 8136285Sbrian size = smap.length; 8236285Sbrian 8336285Sbrian /* 8436285Sbrian * If this segment crosses the 4GB boundary, truncate it. 8536285Sbrian */ 8636285Sbrian if (smap.base + size > 0x100000000ull) 8736465Sbrian size = 0x100000000ull - smap.base; 8836465Sbrian 8936285Sbrian if (size > high_heap_size) { 9036285Sbrian high_heap_size = size; 9136465Sbrian high_heap_base = smap.base; 9236465Sbrian } 9336285Sbrian } 9436285Sbrian } while (v86.ebx != 0); 9536285Sbrian 9636285Sbrian /* Fall back to the old compatibility function for base memory */ 9736285Sbrian if (bios_basemem == 0) { 9836285Sbrian v86.ctl = 0; 9931196Sbrian v86.addr = 0x12; /* int 0x12 */ 10036285Sbrian v86int(); 10131196Sbrian 10236285Sbrian bios_basemem = (v86.eax & 0xffff) * 1024; 10336285Sbrian } 10436285Sbrian 10531196Sbrian /* Fall back through several compatibility functions for extended memory */ 10636285Sbrian if (bios_extmem == 0) { 10731196Sbrian v86.ctl = V86_FLAGS; 10831203Sbrian v86.addr = 0x15; /* int 0x15 function 0xe801*/ 10936285Sbrian v86.eax = 0xe801; 11036285Sbrian v86int(); 11131203Sbrian if (!(V86_CY(v86.efl))) { 11236285Sbrian bios_extmem = ((v86.ecx & 0xffff) + ((v86.edx & 0xffff) * 64)) * 1024; 11331203Sbrian } 11436285Sbrian } 11536285Sbrian if (bios_extmem == 0) { 11636285Sbrian v86.ctl = 0; 11736285Sbrian v86.addr = 0x15; /* int 0x15 function 0x88*/ 11836285Sbrian v86.eax = 0x8800; 11936285Sbrian v86int(); 12036285Sbrian bios_extmem = (v86.eax & 0xffff) * 1024; 12136285Sbrian } 12236285Sbrian 12336285Sbrian /* Set memtop to actual top of memory */ 12436285Sbrian memtop = memtop_copyin = 0x100000 + bios_extmem; 12536285Sbrian 12631203Sbrian /* 12744279Sbrian * If we have extended memory and did not find a suitable heap 12844279Sbrian * region in the SMAP, use the last 3MB of 'extended' memory as a 12944279Sbrian * high heap candidate. 13044279Sbrian */ 13144279Sbrian if (bios_extmem >= HEAP_MIN && high_heap_size < HEAP_MIN) { 13244279Sbrian high_heap_size = HEAP_MIN; 13344279Sbrian high_heap_base = memtop - HEAP_MIN; 13444279Sbrian } 13544279Sbrian} 13644279Sbrian