mirror of
https://github.com/ipxe/ipxe
synced 2026-01-21 18:30:56 +03:00
[bios] Update to use the generic system memory map API
Provide an implementation of the system memory map API based on the assorted BIOS INT 15 calls, and a temporary implementation of the legacy get_memmap() function using the new API. Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
14
src/arch/x86/include/bits/memmap.h
Normal file
14
src/arch/x86/include/bits/memmap.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#ifndef _BITS_MEMMAP_H
|
||||
#define _BITS_MEMMAP_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* x86-specific system memory map API implementations
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <ipxe/int15.h>
|
||||
|
||||
#endif /* _BITS_MEMMAP_H */
|
||||
20
src/arch/x86/include/ipxe/int15.h
Normal file
20
src/arch/x86/include/ipxe/int15.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#ifndef _IPXE_INT15_H
|
||||
#define _IPXE_INT15_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* INT15-based memory map
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#ifdef MEMMAP_INT15
|
||||
#define MEMMAP_PREFIX_int15
|
||||
#else
|
||||
#define MEMMAP_PREFIX_int15 __int15_
|
||||
#endif
|
||||
|
||||
extern void int15_intercept ( int intercept );
|
||||
|
||||
#endif /* _IPXE_INT15_H */
|
||||
@@ -564,6 +564,8 @@ int15_88:
|
||||
int15:
|
||||
/* See if we want to intercept this call */
|
||||
pushfw
|
||||
cmpb $0, %cs:int15_intercept_flag
|
||||
je 3f
|
||||
cmpw $0xe820, %ax
|
||||
jne 1f
|
||||
cmpl $SMAP, %edx
|
||||
@@ -587,3 +589,9 @@ int15:
|
||||
int15_vector:
|
||||
.long 0
|
||||
.size int15_vector, . - int15_vector
|
||||
|
||||
.section ".text16.data", "aw", @progbits
|
||||
.globl int15_intercept_flag
|
||||
int15_intercept_flag:
|
||||
.byte 1
|
||||
.size int15_intercept_flag, . - int15_intercept_flag
|
||||
|
||||
@@ -30,6 +30,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
#include <fakee820.h>
|
||||
#include <ipxe/init.h>
|
||||
#include <ipxe/io.h>
|
||||
#include <ipxe/memmap.h>
|
||||
#include <ipxe/hidemem.h>
|
||||
|
||||
/** Set to true if you want to test a fake E820 map */
|
||||
@@ -73,6 +74,10 @@ extern void int15();
|
||||
extern struct segoff __text16 ( int15_vector );
|
||||
#define int15_vector __use_text16 ( int15_vector )
|
||||
|
||||
/** INT 15 interception flag */
|
||||
extern uint8_t __text16 ( int15_intercept_flag );
|
||||
#define int15_intercept_flag __use_text16 ( int15_intercept_flag )
|
||||
|
||||
/* The linker defines these symbols for us */
|
||||
extern char _textdata[];
|
||||
extern char _etextdata[];
|
||||
@@ -131,6 +136,17 @@ void hide_textdata ( void ) {
|
||||
virt_to_phys ( _etextdata ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Set INT 15 interception flag
|
||||
*
|
||||
* @v intercept Intercept INT 15 calls to modify memory map
|
||||
*/
|
||||
void int15_intercept ( int intercept ) {
|
||||
|
||||
/* Set flag for INT 15 handler */
|
||||
int15_intercept_flag = intercept;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide Etherboot
|
||||
*
|
||||
|
||||
@@ -26,10 +26,12 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <realmode.h>
|
||||
#include <bios.h>
|
||||
#include <memsizes.h>
|
||||
#include <ipxe/io.h>
|
||||
#include <ipxe/memmap.h>
|
||||
|
||||
/**
|
||||
* @file
|
||||
@@ -152,7 +154,7 @@ static unsigned int extmemsize_88 ( void ) {
|
||||
* @ret extmem Extended memory size, in kB
|
||||
*
|
||||
* Note that this is only an approximation; for an accurate picture,
|
||||
* use the E820 memory map obtained via get_memmap();
|
||||
* use the E820 memory map obtained via memmap_describe();
|
||||
*/
|
||||
unsigned int extmemsize ( void ) {
|
||||
unsigned int extmem_e801;
|
||||
@@ -167,12 +169,13 @@ unsigned int extmemsize ( void ) {
|
||||
/**
|
||||
* Get e820 memory map
|
||||
*
|
||||
* @v memmap Memory map to fill in
|
||||
* @v region Memory region of interest to be updated
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int meme820 ( struct memory_map *memmap ) {
|
||||
struct memory_region *region = memmap->regions;
|
||||
struct memory_region *prev_region = NULL;
|
||||
static int meme820 ( struct memmap_region *region ) {
|
||||
unsigned int count = 0;
|
||||
uint64_t start = 0;
|
||||
uint64_t len = 0;
|
||||
uint32_t next = 0;
|
||||
uint32_t smap;
|
||||
uint32_t size;
|
||||
@@ -226,13 +229,6 @@ static int meme820 ( struct memory_map *memmap ) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* If first region is not RAM, assume map is invalid */
|
||||
if ( ( memmap->count == 0 ) &&
|
||||
( e820buf.type != E820_TYPE_RAM ) ) {
|
||||
DBG ( "INT 15,e820 failed, first entry not RAM\n" );
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
DBG ( "INT 15,e820 region [%llx,%llx) type %d",
|
||||
e820buf.start, ( e820buf.start + e820buf.len ),
|
||||
( int ) e820buf.type );
|
||||
@@ -259,27 +255,36 @@ static int meme820 ( struct memory_map *memmap ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
region->start = e820buf.start;
|
||||
region->end = e820buf.start + e820buf.len;
|
||||
|
||||
/* Check for adjacent regions and merge them */
|
||||
if ( prev_region && ( region->start == prev_region->end ) ) {
|
||||
prev_region->end = region->end;
|
||||
if ( e820buf.start == ( start + len ) ) {
|
||||
len += e820buf.len;
|
||||
} else {
|
||||
prev_region = region;
|
||||
region++;
|
||||
memmap->count++;
|
||||
start = e820buf.start;
|
||||
len = e820buf.len;
|
||||
}
|
||||
|
||||
if ( memmap->count >= ( sizeof ( memmap->regions ) /
|
||||
sizeof ( memmap->regions[0] ) ) ) {
|
||||
DBG ( "INT 15,e820 too many regions returned\n" );
|
||||
/* Not a fatal error; what we've got so far at
|
||||
* least represents valid regions of memory,
|
||||
* even if we couldn't get them all.
|
||||
/* Sanity check: first region (base memory) should
|
||||
* start at address zero.
|
||||
*/
|
||||
break;
|
||||
if ( ( count == 0 ) && ( start != 0 ) ) {
|
||||
DBG ( "INT 15,e820 region 0 starts at %llx (expected "
|
||||
"0); assuming insane\n", start );
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Sanity check: second region (extended memory)
|
||||
* should start at address 0x100000.
|
||||
*/
|
||||
if ( ( count == 1 ) && ( start != 0x100000 ) ) {
|
||||
DBG ( "INT 15,e820 region 1 starts at %llx (expected "
|
||||
"100000); assuming insane\n", start );
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Update region of interest */
|
||||
memmap_update ( region, start, len, MEMMAP_FL_MEMORY, "e820" );
|
||||
count++;
|
||||
|
||||
} while ( next != 0 );
|
||||
|
||||
/* Sanity checks. Some BIOSes report complete garbage via INT
|
||||
@@ -288,19 +293,9 @@ static int meme820 ( struct memory_map *memmap ) {
|
||||
* region (starting at 0) and at least one high memory region
|
||||
* (starting at 0x100000).
|
||||
*/
|
||||
if ( memmap->count < 2 ) {
|
||||
if ( count < 2 ) {
|
||||
DBG ( "INT 15,e820 returned only %d regions; assuming "
|
||||
"insane\n", memmap->count );
|
||||
return -EINVAL;
|
||||
}
|
||||
if ( memmap->regions[0].start != 0 ) {
|
||||
DBG ( "INT 15,e820 region 0 starts at %llx (expected 0); "
|
||||
"assuming insane\n", memmap->regions[0].start );
|
||||
return -EINVAL;
|
||||
}
|
||||
if ( memmap->regions[1].start != 0x100000 ) {
|
||||
DBG ( "INT 15,e820 region 1 starts at %llx (expected 100000); "
|
||||
"assuming insane\n", memmap->regions[0].start );
|
||||
"insane\n", count );
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -308,37 +303,52 @@ static int meme820 ( struct memory_map *memmap ) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get memory map
|
||||
* Describe memory region from system memory map
|
||||
*
|
||||
* @v memmap Memory map to fill in
|
||||
* @v addr Address within region
|
||||
* @v hide Hide in-use regions from the memory map
|
||||
* @v region Region descriptor to fill in
|
||||
*/
|
||||
void x86_get_memmap ( struct memory_map *memmap ) {
|
||||
unsigned int basemem, extmem;
|
||||
static void int15_describe ( uint64_t addr, int hide,
|
||||
struct memmap_region *region ) {
|
||||
unsigned int basemem;
|
||||
unsigned int extmem;
|
||||
uint64_t inaccessible;
|
||||
int rc;
|
||||
|
||||
DBG ( "Fetching system memory map\n" );
|
||||
/* Initialise region */
|
||||
memmap_init ( addr, region );
|
||||
|
||||
/* Clear memory map */
|
||||
memset ( memmap, 0, sizeof ( *memmap ) );
|
||||
/* Mark addresses above 4GB as inaccessible: we have no way to
|
||||
* access them either in a 32-bit build or in a 64-bit build
|
||||
* (since the 64-bit build identity-maps only the 32-bit
|
||||
* address space).
|
||||
*/
|
||||
inaccessible = ( 1ULL << 32 );
|
||||
memmap_update ( region, inaccessible, -inaccessible,
|
||||
MEMMAP_FL_INACCESSIBLE, NULL );
|
||||
|
||||
/* Get base and extended memory sizes */
|
||||
/* Enable/disable INT 15 interception as applicable */
|
||||
int15_intercept ( hide );
|
||||
|
||||
/* Try INT 15,e820 first, falling back to constructing a map
|
||||
* from basemem and extmem sizes
|
||||
*/
|
||||
if ( ( rc = meme820 ( region ) ) == 0 ) {
|
||||
DBG ( "Obtained system memory map via INT 15,e820\n" );
|
||||
} else {
|
||||
basemem = basememsize();
|
||||
DBG ( "FBMS base memory size %d kB [0,%x)\n",
|
||||
basemem, ( basemem * 1024 ) );
|
||||
extmem = extmemsize();
|
||||
|
||||
/* Try INT 15,e820 first */
|
||||
if ( ( rc = meme820 ( memmap ) ) == 0 ) {
|
||||
DBG ( "Obtained system memory map via INT 15,e820\n" );
|
||||
return;
|
||||
memmap_update ( region, 0, ( basemem * 1024 ),
|
||||
MEMMAP_FL_MEMORY, "basemem" );
|
||||
memmap_update ( region, 0x100000, ( extmem * 1024 ),
|
||||
MEMMAP_FL_MEMORY, "extmem" );
|
||||
}
|
||||
|
||||
/* Fall back to constructing a map from basemem and extmem sizes */
|
||||
DBG ( "INT 15,e820 failed; constructing map\n" );
|
||||
memmap->regions[0].end = ( basemem * 1024 );
|
||||
memmap->regions[1].start = 0x100000;
|
||||
memmap->regions[1].end = 0x100000 + ( extmem * 1024 );
|
||||
memmap->count = 2;
|
||||
/* Restore INT 15 interception */
|
||||
int15_intercept ( 1 );
|
||||
}
|
||||
|
||||
PROVIDE_IOAPI ( x86, get_memmap, x86_get_memmap );
|
||||
PROVIDE_MEMMAP ( int15, memmap_describe, int15_describe );
|
||||
|
||||
@@ -17,7 +17,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
#define CONSOLE_PCBIOS
|
||||
#define NAP_PCBIOS
|
||||
#define UMALLOC_MEMTOP
|
||||
#define MEMMAP_NULL
|
||||
#define MEMMAP_INT15
|
||||
#define SMBIOS_PCBIOS
|
||||
#define SANBOOT_PCBIOS
|
||||
#define ENTROPY_RTC
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <assert.h>
|
||||
#include <ipxe/io.h>
|
||||
#include <ipxe/memmap.h>
|
||||
|
||||
/** @file
|
||||
@@ -110,5 +111,29 @@ void memmap_update_used ( struct memmap_region *region ) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get legacy system memory map
|
||||
*
|
||||
* @v memmap Legacy memory map to fill in
|
||||
*/
|
||||
void get_memmap ( struct memory_map *memmap ) {
|
||||
struct memmap_region region;
|
||||
struct memory_region *usable;
|
||||
|
||||
/* Clear legacy memory map */
|
||||
memmap->count = 0;
|
||||
|
||||
/* Populate legacy memory map */
|
||||
for_each_memmap ( ®ion, 1 ) {
|
||||
if ( memmap_is_usable ( ®ion ) ) {
|
||||
usable = &memmap->regions[memmap->count++];
|
||||
usable->start = region.addr;
|
||||
usable->end = ( region.last + 1 );
|
||||
if ( memmap->count == MAX_MEMORY_REGIONS )
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PROVIDE_MEMMAP_INLINE ( null, memmap_describe );
|
||||
PROVIDE_MEMMAP_INLINE ( null, memmap_sync );
|
||||
|
||||
Reference in New Issue
Block a user