mirror of
https://github.com/ipxe/ipxe
synced 2026-01-22 03:32:59 +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:
|
int15:
|
||||||
/* See if we want to intercept this call */
|
/* See if we want to intercept this call */
|
||||||
pushfw
|
pushfw
|
||||||
|
cmpb $0, %cs:int15_intercept_flag
|
||||||
|
je 3f
|
||||||
cmpw $0xe820, %ax
|
cmpw $0xe820, %ax
|
||||||
jne 1f
|
jne 1f
|
||||||
cmpl $SMAP, %edx
|
cmpl $SMAP, %edx
|
||||||
@@ -587,3 +589,9 @@ int15:
|
|||||||
int15_vector:
|
int15_vector:
|
||||||
.long 0
|
.long 0
|
||||||
.size int15_vector, . - int15_vector
|
.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 <fakee820.h>
|
||||||
#include <ipxe/init.h>
|
#include <ipxe/init.h>
|
||||||
#include <ipxe/io.h>
|
#include <ipxe/io.h>
|
||||||
|
#include <ipxe/memmap.h>
|
||||||
#include <ipxe/hidemem.h>
|
#include <ipxe/hidemem.h>
|
||||||
|
|
||||||
/** Set to true if you want to test a fake E820 map */
|
/** 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 );
|
extern struct segoff __text16 ( int15_vector );
|
||||||
#define int15_vector __use_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 */
|
/* The linker defines these symbols for us */
|
||||||
extern char _textdata[];
|
extern char _textdata[];
|
||||||
extern char _etextdata[];
|
extern char _etextdata[];
|
||||||
@@ -131,6 +136,17 @@ void hide_textdata ( void ) {
|
|||||||
virt_to_phys ( _etextdata ) );
|
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
|
* Hide Etherboot
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -26,10 +26,12 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <assert.h>
|
||||||
#include <realmode.h>
|
#include <realmode.h>
|
||||||
#include <bios.h>
|
#include <bios.h>
|
||||||
#include <memsizes.h>
|
#include <memsizes.h>
|
||||||
#include <ipxe/io.h>
|
#include <ipxe/io.h>
|
||||||
|
#include <ipxe/memmap.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @file
|
* @file
|
||||||
@@ -152,7 +154,7 @@ static unsigned int extmemsize_88 ( void ) {
|
|||||||
* @ret extmem Extended memory size, in kB
|
* @ret extmem Extended memory size, in kB
|
||||||
*
|
*
|
||||||
* Note that this is only an approximation; for an accurate picture,
|
* 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 extmemsize ( void ) {
|
||||||
unsigned int extmem_e801;
|
unsigned int extmem_e801;
|
||||||
@@ -167,12 +169,13 @@ unsigned int extmemsize ( void ) {
|
|||||||
/**
|
/**
|
||||||
* Get e820 memory map
|
* 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
|
* @ret rc Return status code
|
||||||
*/
|
*/
|
||||||
static int meme820 ( struct memory_map *memmap ) {
|
static int meme820 ( struct memmap_region *region ) {
|
||||||
struct memory_region *region = memmap->regions;
|
unsigned int count = 0;
|
||||||
struct memory_region *prev_region = NULL;
|
uint64_t start = 0;
|
||||||
|
uint64_t len = 0;
|
||||||
uint32_t next = 0;
|
uint32_t next = 0;
|
||||||
uint32_t smap;
|
uint32_t smap;
|
||||||
uint32_t size;
|
uint32_t size;
|
||||||
@@ -226,13 +229,6 @@ static int meme820 ( struct memory_map *memmap ) {
|
|||||||
break;
|
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",
|
DBG ( "INT 15,e820 region [%llx,%llx) type %d",
|
||||||
e820buf.start, ( e820buf.start + e820buf.len ),
|
e820buf.start, ( e820buf.start + e820buf.len ),
|
||||||
( int ) e820buf.type );
|
( int ) e820buf.type );
|
||||||
@@ -259,27 +255,36 @@ static int meme820 ( struct memory_map *memmap ) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
region->start = e820buf.start;
|
|
||||||
region->end = e820buf.start + e820buf.len;
|
|
||||||
|
|
||||||
/* Check for adjacent regions and merge them */
|
/* Check for adjacent regions and merge them */
|
||||||
if ( prev_region && ( region->start == prev_region->end ) ) {
|
if ( e820buf.start == ( start + len ) ) {
|
||||||
prev_region->end = region->end;
|
len += e820buf.len;
|
||||||
} else {
|
} else {
|
||||||
prev_region = region;
|
start = e820buf.start;
|
||||||
region++;
|
len = e820buf.len;
|
||||||
memmap->count++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( memmap->count >= ( sizeof ( memmap->regions ) /
|
/* Sanity check: first region (base memory) should
|
||||||
sizeof ( memmap->regions[0] ) ) ) {
|
* start at address zero.
|
||||||
DBG ( "INT 15,e820 too many regions returned\n" );
|
*/
|
||||||
/* Not a fatal error; what we've got so far at
|
if ( ( count == 0 ) && ( start != 0 ) ) {
|
||||||
* least represents valid regions of memory,
|
DBG ( "INT 15,e820 region 0 starts at %llx (expected "
|
||||||
* even if we couldn't get them all.
|
"0); assuming insane\n", start );
|
||||||
*/
|
return -EINVAL;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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 );
|
} while ( next != 0 );
|
||||||
|
|
||||||
/* Sanity checks. Some BIOSes report complete garbage via INT
|
/* 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
|
* region (starting at 0) and at least one high memory region
|
||||||
* (starting at 0x100000).
|
* (starting at 0x100000).
|
||||||
*/
|
*/
|
||||||
if ( memmap->count < 2 ) {
|
if ( count < 2 ) {
|
||||||
DBG ( "INT 15,e820 returned only %d regions; assuming "
|
DBG ( "INT 15,e820 returned only %d regions; assuming "
|
||||||
"insane\n", memmap->count );
|
"insane\n", 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 );
|
|
||||||
return -EINVAL;
|
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 ) {
|
static void int15_describe ( uint64_t addr, int hide,
|
||||||
unsigned int basemem, extmem;
|
struct memmap_region *region ) {
|
||||||
|
unsigned int basemem;
|
||||||
|
unsigned int extmem;
|
||||||
|
uint64_t inaccessible;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
DBG ( "Fetching system memory map\n" );
|
/* Initialise region */
|
||||||
|
memmap_init ( addr, region );
|
||||||
|
|
||||||
/* Clear memory map */
|
/* Mark addresses above 4GB as inaccessible: we have no way to
|
||||||
memset ( memmap, 0, sizeof ( *memmap ) );
|
* 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 */
|
||||||
basemem = basememsize();
|
int15_intercept ( hide );
|
||||||
DBG ( "FBMS base memory size %d kB [0,%x)\n",
|
|
||||||
basemem, ( basemem * 1024 ) );
|
/* Try INT 15,e820 first, falling back to constructing a map
|
||||||
extmem = extmemsize();
|
* from basemem and extmem sizes
|
||||||
|
*/
|
||||||
/* Try INT 15,e820 first */
|
if ( ( rc = meme820 ( region ) ) == 0 ) {
|
||||||
if ( ( rc = meme820 ( memmap ) ) == 0 ) {
|
|
||||||
DBG ( "Obtained system memory map via INT 15,e820\n" );
|
DBG ( "Obtained system memory map via INT 15,e820\n" );
|
||||||
return;
|
} else {
|
||||||
|
basemem = basememsize();
|
||||||
|
DBG ( "FBMS base memory size %d kB [0,%x)\n",
|
||||||
|
basemem, ( basemem * 1024 ) );
|
||||||
|
extmem = extmemsize();
|
||||||
|
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 */
|
/* Restore INT 15 interception */
|
||||||
DBG ( "INT 15,e820 failed; constructing map\n" );
|
int15_intercept ( 1 );
|
||||||
memmap->regions[0].end = ( basemem * 1024 );
|
|
||||||
memmap->regions[1].start = 0x100000;
|
|
||||||
memmap->regions[1].end = 0x100000 + ( extmem * 1024 );
|
|
||||||
memmap->count = 2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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 CONSOLE_PCBIOS
|
||||||
#define NAP_PCBIOS
|
#define NAP_PCBIOS
|
||||||
#define UMALLOC_MEMTOP
|
#define UMALLOC_MEMTOP
|
||||||
#define MEMMAP_NULL
|
#define MEMMAP_INT15
|
||||||
#define SMBIOS_PCBIOS
|
#define SMBIOS_PCBIOS
|
||||||
#define SANBOOT_PCBIOS
|
#define SANBOOT_PCBIOS
|
||||||
#define ENTROPY_RTC
|
#define ENTROPY_RTC
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <ipxe/io.h>
|
||||||
#include <ipxe/memmap.h>
|
#include <ipxe/memmap.h>
|
||||||
|
|
||||||
/** @file
|
/** @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_describe );
|
||||||
PROVIDE_MEMMAP_INLINE ( null, memmap_sync );
|
PROVIDE_MEMMAP_INLINE ( null, memmap_sync );
|
||||||
|
|||||||
Reference in New Issue
Block a user