2007-07-11 12:18:50 -07:00
/* -*- linux-c -*- ------------------------------------------------------- *
*
* Copyright ( C ) 1991 , 1992 Linus Torvalds
* Copyright 2007 rPath , Inc . - All Rights Reserved
*
* This file is part of the Linux kernel , and is made available under
* the terms of the GNU General Public License version 2.
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*
* Memory detection code
*/
# include "boot.h"
# define SMAP 0x534d4150 /* ASCII "SMAP" */
static int detect_memory_e820 ( void )
{
2007-09-26 14:11:43 -07:00
int count = 0 ;
2007-07-11 12:18:50 -07:00
u32 next = 0 ;
u32 size , id ;
u8 err ;
struct e820entry * desc = boot_params . e820_map ;
do {
size = sizeof ( struct e820entry ) ;
2007-09-27 17:17:12 -07:00
/* Important: %edx is clobbered by some BIOSes,
so it must be either used for the error output
or explicitly marked clobbered . */
2007-07-11 12:18:50 -07:00
asm ( " int $0x15; setc %0 "
2007-09-27 17:17:12 -07:00
: " =d " ( err ) , " +b " ( next ) , " =a " ( id ) , " +c " ( size ) ,
2007-07-11 12:18:50 -07:00
" =m " ( * desc )
2007-09-27 17:17:12 -07:00
: " D " ( desc ) , " d " ( SMAP ) , " a " ( 0xe820 ) ) ;
2007-07-11 12:18:50 -07:00
2008-02-13 11:16:46 -08:00
/* BIOSes which terminate the chain with CF = 1 as opposed
to % ebx = 0 don ' t always report the SMAP signature on
the final , failing , probe . */
if ( err )
break ;
2007-09-26 14:11:43 -07:00
/* Some BIOSes stop returning SMAP in the middle of
the search loop . We don ' t know exactly how the BIOS
screwed up the map at that point , we might have a
partial map , the full map , or complete garbage , so
just return failure . */
if ( id ! = SMAP ) {
count = 0 ;
2007-07-11 12:18:50 -07:00
break ;
2007-09-26 14:11:43 -07:00
}
2007-07-11 12:18:50 -07:00
2007-09-26 14:11:43 -07:00
count + + ;
2007-07-11 12:18:50 -07:00
desc + + ;
2008-05-14 08:15:34 -07:00
} while ( next & & count < ARRAY_SIZE ( boot_params . e820_map ) ) ;
2007-07-11 12:18:50 -07:00
2007-09-26 14:11:43 -07:00
return boot_params . e820_entries = count ;
2007-07-11 12:18:50 -07:00
}
static int detect_memory_e801 ( void )
{
u16 ax , bx , cx , dx ;
u8 err ;
bx = cx = dx = 0 ;
ax = 0xe801 ;
asm ( " stc; int $0x15; setc %0 "
: " =m " ( err ) , " +a " ( ax ) , " +b " ( bx ) , " +c " ( cx ) , " +d " ( dx ) ) ;
if ( err )
return - 1 ;
/* Do we really need to do this? */
if ( cx | | dx ) {
ax = cx ;
bx = dx ;
}
if ( ax > 15 * 1024 )
return - 1 ; /* Bogus! */
/* This ignores memory above 16MB if we have a memory hole
there . If someone actually finds a machine with a memory
hole at 16 MB and no support for 0E820 h they should probably
generate a fake e820 map . */
boot_params . alt_mem_k = ( ax = = 15 * 1024 ) ? ( dx < < 6 ) + ax : ax ;
return 0 ;
}
static int detect_memory_88 ( void )
{
u16 ax ;
u8 err ;
ax = 0x8800 ;
asm ( " stc; int $0x15; setc %0 " : " =bcdm " ( err ) , " +a " ( ax ) ) ;
boot_params . screen_info . ext_mem_k = ax ;
return - err ;
}
int detect_memory ( void )
{
2007-09-26 14:11:43 -07:00
int err = - 1 ;
2007-07-11 12:18:50 -07:00
if ( detect_memory_e820 ( ) > 0 )
2007-09-26 14:11:43 -07:00
err = 0 ;
2007-07-11 12:18:50 -07:00
if ( ! detect_memory_e801 ( ) )
2007-09-26 14:11:43 -07:00
err = 0 ;
if ( ! detect_memory_88 ( ) )
err = 0 ;
2007-07-11 12:18:50 -07:00
2007-09-26 14:11:43 -07:00
return err ;
2007-07-11 12:18:50 -07:00
}