123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226 |
- #include "stdint.h"
- #include "stddef.h"
- #include "realmode.h"
- #include "init.h"
- #include "memsizes.h"
-
- #define CF ( 1 << 0 )
-
- #ifndef MEMSIZES_DEBUG
- #define MEMSIZES_DEBUG 0
- #endif
-
- /* by Eric Biederman */
-
- struct meminfo meminfo;
-
- /**************************************************************************
- BASEMEMSIZE - Get size of the conventional (base) memory
- **************************************************************************/
- static unsigned short basememsize ( void ) {
- uint16_t int12_basememsize, fbms_basememsize;
-
- /* There are two methods for retrieving the base memory size:
- * INT 12 and the BIOS FBMS counter at 40:13. We read both
- * and use the smaller value, to be paranoid.
- */
-
- REAL_EXEC ( rm_basememsize,
- "int $0x12\n\t",
- 1,
- OUT_CONSTRAINTS ( "=a" ( int12_basememsize ) ),
- IN_CONSTRAINTS (),
- CLOBBER ( "ebx", "ecx", "edx", "ebp", "esi", "edi" ) );
-
- get_real ( fbms_basememsize, 0x40, 0x13 );
-
- return ( int12_basememsize < fbms_basememsize ?
- int12_basememsize : fbms_basememsize );
- }
-
- /**************************************************************************
- MEMSIZE - Determine size of extended memory, in kB
- **************************************************************************/
- static unsigned int memsize ( void ) {
- uint16_t extmem_1m_to_16m_k, extmem_16m_plus_64k;
- uint16_t confmem_1m_to_16m_k, confmem_16m_plus_64k;
- uint16_t flags;
- int memsize;
-
- /* Try INT 15,e801 first
- *
- * Some buggy BIOSes don't clear/set carry on pass/error of
- * e801h memory size call or merely pass cx,dx through without
- * changing them, so we set carry and zero cx,dx before call.
- */
- REAL_EXEC ( rm_mem_e801,
- "stc\n\t"
- "int $0x15\n\t"
- "pushfw\n\t" /* flags -> %di */
- "popw %%di\n\t",
- 5,
- OUT_CONSTRAINTS ( "=a" ( extmem_1m_to_16m_k ),
- "=b" ( extmem_16m_plus_64k ),
- "=c" ( confmem_1m_to_16m_k ),
- "=d" ( confmem_16m_plus_64k ),
- "=D" ( flags ) ),
- IN_CONSTRAINTS ( "a" ( 0xe801 ),
- "c" ( 0 ),
- "d" ( 0 ) ),
- CLOBBER ( "ebp", "esi" ) );
-
- if ( ! ( flags & CF ) ) {
- /* INT 15,e801 succeeded */
- if ( confmem_1m_to_16m_k || confmem_16m_plus_64k ) {
- /* Use confmem (cx,dx) values */
- memsize = confmem_1m_to_16m_k +
- ( confmem_16m_plus_64k << 6 );
- } else {
- /* Use extmem (ax,bx) values */
- memsize = extmem_1m_to_16m_k +
- ( extmem_16m_plus_64k << 6 );
- }
- } else {
- /* INT 15,e801 failed; fall back to INT 15,88
- *
- * CF is apparently unreliable and should be ignored.
- */
- REAL_EXEC ( rm_mem_88,
- "int $0x15\n\t",
- 1,
- OUT_CONSTRAINTS ( "=a" ( extmem_1m_to_16m_k ) ),
- IN_CONSTRAINTS ( "a" ( 0x88 << 8 ) ),
- CLOBBER ( "ebx", "ecx", "edx",
- "ebp", "esi", "edi" ) );
- memsize = extmem_1m_to_16m_k;
- }
-
- return memsize;
- }
-
- /**************************************************************************
- MEME820 - Retrieve the E820 BIOS memory map
- **************************************************************************/
- #define SMAP ( 0x534d4150 ) /* "SMAP" */
- static int meme820 ( struct e820entry *buf, int count ) {
- int index;
- uint16_t basemem_entry;
- uint32_t smap, next;
- uint16_t flags;
- uint32_t discard_c, discard_d;
-
- index = 0;
- next = 0;
- do {
- basemem_entry = BASEMEM_PARAMETER_INIT ( buf[index] );
- REAL_EXEC ( rm_mem_e820,
- "int $0x15\n\t"
- "pushfw\n\t" /* flags -> %di */
- "popw %%di\n\t",
- 5,
- OUT_CONSTRAINTS ( "=a" ( smap ),
- "=b" ( next ),
- "=c" ( discard_c ),
- "=d" ( discard_d ),
- "=D" ( flags ) ),
- IN_CONSTRAINTS ( "a" ( 0xe820 ),
- "b" ( next ),
- "c" ( sizeof (struct e820entry) ),
- "d" ( SMAP ),
- "D" ( basemem_entry ) ),
- CLOBBER ( "ebp", "esi" ) );
- BASEMEM_PARAMETER_DONE ( buf[index] );
- if ( smap != SMAP ) return 0;
- if ( flags & CF ) break;
- index++;
- } while ( ( index < count ) && ( next != 0 ) );
-
- return index;
- }
-
- /**************************************************************************
- GET_MEMSIZES - Retrieve the system memory map via any available means
- **************************************************************************/
- void get_memsizes ( void ) {
- /* Ensure we don't stomp bios data structutres.
- * the interrupt table: 0x000 - 0x3ff
- * the bios data area: 0x400 - 0x502
- * Dos variables: 0x502 - 0x5ff
- */
- static const unsigned min_addr = 0x600;
- unsigned i;
- unsigned basemem;
-
- /* Retrieve memory information from the BIOS */
- meminfo.basememsize = basememsize();
- basemem = meminfo.basememsize << 10;
- meminfo.memsize = memsize();
- #ifndef IGNORE_E820_MAP
- meminfo.map_count = meme820 ( meminfo.map, E820MAX );
- #else
- meminfo.map_count = 0;
- #endif
-
- /* If we don't have an e820 memory map fake it */
- if ( meminfo.map_count == 0 ) {
- meminfo.map_count = 2;
- meminfo.map[0].addr = 0;
- meminfo.map[0].size = meminfo.basememsize << 10;
- meminfo.map[0].type = E820_RAM;
- meminfo.map[1].addr = 1024*1024;
- meminfo.map[1].size = meminfo.memsize << 10;
- meminfo.map[1].type = E820_RAM;
- }
-
- /* Scrub the e820 map */
- for ( i = 0; i < meminfo.map_count; i++ ) {
- if ( meminfo.map[i].type != E820_RAM ) {
- continue;
- }
-
- /* Reserve the bios data structures */
- if ( meminfo.map[i].addr < min_addr ) {
- unsigned long delta;
- delta = min_addr - meminfo.map[i].addr;
- if ( delta > meminfo.map[i].size ) {
- delta = meminfo.map[i].size;
- }
- meminfo.map[i].addr = min_addr;
- meminfo.map[i].size -= delta;
- }
-
- /* Ensure the returned e820 map is in sync with the
- * actual memory state
- */
- if ( ( meminfo.map[i].addr < 0xa0000 ) &&
- (( meminfo.map[i].addr+meminfo.map[i].size ) > basemem )){
- if ( meminfo.map[i].addr <= basemem ) {
- meminfo.map[i].size = basemem
- - meminfo.map[i].addr;
- } else {
- meminfo.map[i].addr = basemem;
- meminfo.map[i].size = 0;
- }
- }
- }
-
- #if MEMSIZES_DEBUG
- printf ( "basememsize %d\n", meminfo.basememsize );
- printf ( "memsize %d\n", meminfo.memsize );
- printf ( "Memory regions(%d):\n", meminfo.map_count );
- for ( i = 0; i < meminfo.map_count; i++ ) {
- unsigned long long r_start, r_end;
- r_start = meminfo.map[i].addr;
- r_end = r_start + meminfo.map[i].size;
- printf ( "[%X%X, %X%X) type %d\n",
- ( unsigned long ) ( r_start >> 32 ),
- ( unsigned long ) r_start,
- ( unsigned long ) ( r_end >> 32 ),
- ( unsigned long ) r_end,
- meminfo.map[i].type );
- }
- #endif
-
- }
-
- INIT_FN ( INIT_MEMSIZES, get_memsizes, NULL, NULL );
|