diff options
| author | Simon Rettberg | 2026-01-28 12:53:53 +0100 |
|---|---|---|
| committer | Simon Rettberg | 2026-01-28 12:53:53 +0100 |
| commit | 8e82785c584dc13e20f9229decb95bd17bbe9cd1 (patch) | |
| tree | a8b359e59196be5b2e3862bed189107f4bc9975f /src/include/ipxe/memmap.h | |
| parent | Merge branch 'master' into openslx (diff) | |
| parent | [prefix] Make unlzma.S compatible with 386 class CPUs (diff) | |
| download | ipxe-openslx.tar.gz ipxe-openslx.tar.xz ipxe-openslx.zip | |
Merge branch 'master' into openslxopenslx
Diffstat (limited to 'src/include/ipxe/memmap.h')
| -rw-r--r-- | src/include/ipxe/memmap.h | 236 |
1 files changed, 236 insertions, 0 deletions
diff --git a/src/include/ipxe/memmap.h b/src/include/ipxe/memmap.h new file mode 100644 index 000000000..4a768f867 --- /dev/null +++ b/src/include/ipxe/memmap.h @@ -0,0 +1,236 @@ +#ifndef _IPXE_MEMMAP_H +#define _IPXE_MEMMAP_H + +/** @file + * + * System memory map + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); +FILE_SECBOOT ( PERMITTED ); + +#include <stddef.h> +#include <stdint.h> +#include <ipxe/api.h> +#include <ipxe/tables.h> +#include <config/ioapi.h> + +/** + * Calculate static inline memory map API function name + * + * @v _prefix Subsystem prefix + * @v _api_func API function + * @ret _subsys_func Subsystem API function + */ +#define MEMMAP_INLINE( _subsys, _api_func ) \ + SINGLE_API_INLINE ( MEMMAP_PREFIX_ ## _subsys, _api_func ) + +/** + * Provide a memory map API implementation + * + * @v _prefix Subsystem prefix + * @v _api_func API function + * @v _func Implementing function + */ +#define PROVIDE_MEMMAP( _subsys, _api_func, _func ) \ + PROVIDE_SINGLE_API ( MEMMAP_PREFIX_ ## _subsys, _api_func, _func ) + +/** + * Provide a static inline memory map API implementation + * + * @v _prefix Subsystem prefix + * @v _api_func API function + */ +#define PROVIDE_MEMMAP_INLINE( _subsys, _api_func ) \ + PROVIDE_SINGLE_API_INLINE ( MEMMAP_PREFIX_ ## _subsys, _api_func ) + +/** A memory region descriptor */ +struct memmap_region { + /** Minimum address in region */ + uint64_t min; + /** Maximum address in region */ + uint64_t max; + /** Region flags */ + unsigned int flags; + /** Region name (for debug messages) */ + const char *name; +}; + +#define MEMMAP_FL_MEMORY 0x0001 /**< Contains memory */ +#define MEMMAP_FL_RESERVED 0x0002 /**< Is reserved */ +#define MEMMAP_FL_USED 0x0004 /**< Is in use by iPXE */ +#define MEMMAP_FL_INACCESSIBLE 0x0008 /**< Outside of addressable range */ + +/** + * Initialise memory region descriptor + * + * @v min Minimum address + * @v region Region descriptor to fill in + */ +static inline __attribute__ (( always_inline )) void +memmap_init ( uint64_t min, struct memmap_region *region ) { + + region->min = min; + region->max = ~( ( uint64_t ) 0 ); + region->flags = 0; + region->name = NULL; +} + +/** + * Check if memory region is usable + * + * @v region Region descriptor + * @ret is_usable Memory region is usable + */ +static inline __attribute__ (( always_inline )) int +memmap_is_usable ( const struct memmap_region *region ) { + + return ( region->flags == MEMMAP_FL_MEMORY ); +} + +/** + * Get remaining size of memory region (from the described address upwards) + * + * @v region Region descriptor + * @ret size Size of memory region + */ +static inline __attribute__ (( always_inline )) uint64_t +memmap_size ( const struct memmap_region *region ) { + + /* Calculate size, assuming overflow is known to be impossible */ + return ( region->max - region->min + 1 ); +} + +/** An in-use memory region */ +struct used_region { + /** Region name */ + const char *name; + /** Start address */ + physaddr_t start; + /** Length of region */ + size_t size; +}; + +/** In-use memory region table */ +#define USED_REGIONS __table ( struct used_region, "used_regions" ) + +/** Declare an in-use memory region */ +#define __used_region __table_entry ( USED_REGIONS, 01 ) + +/* Include all architecture-independent ACPI API headers */ +#include <ipxe/null_memmap.h> +#include <ipxe/fdtmem.h> + +/* Include all architecture-dependent ACPI API headers */ +#include <bits/memmap.h> + +/** + * Describe memory region from system memory map + * + * @v min Minimum address + * @v hide Hide in-use regions from the memory map + * @v region Region descriptor to fill in + */ +void memmap_describe ( uint64_t min, int hide, struct memmap_region *region ); + +/** + * Synchronise in-use regions with the externally visible system memory map + * + * In environments such as x86 BIOS, we need to patch the global + * system memory map to hide our in-use regions, since there is no + * other way to communicate this information to external code. + */ +void memmap_sync ( void ); + +/** + * Update an in-use memory region + * + * @v used In-use memory region + * @v start Start address + * @v size Length of region + */ +static inline __attribute__ (( always_inline )) void +memmap_use ( struct used_region *used, physaddr_t start, size_t size ) { + + /* Record region */ + used->start = start; + used->size = size; + + /* Synchronise externally visible memory map */ + memmap_sync(); +} + +/** + * Iterate over memory regions from a given starting address + * + * @v region Region descriptor + * @v start Starting address + * @v hide Hide in-use regions from the memory map + */ +#define for_each_memmap_from( region, start, hide ) \ + for ( (region)->min = (start), (region)->max = 0 ; \ + ( ( ( (region)->max + 1 ) != 0 ) && \ + ( memmap_describe ( (region)->min, (hide), \ + (region) ), 1 ) ) ; \ + (region)->min = ( (region)->max + 1 ) ) + +/** + * Iterate over memory regions + * + * @v region Region descriptor + * @v hide Hide in-use regions from the memory map + */ +#define for_each_memmap( region, hide ) \ + for_each_memmap_from ( (region), 0, (hide) ) + +#define DBG_MEMMAP_IF( level, region ) do { \ + const char *name = (region)->name; \ + unsigned int flags = (region)->flags; \ + \ + DBG_IF ( level, "MEMMAP (%s%s%s%s) [%#08llx,%#08llx]%s%s\n", \ + ( ( flags & MEMMAP_FL_MEMORY ) ? "M" : "-" ), \ + ( ( flags & MEMMAP_FL_RESERVED ) ? "R" : "-" ), \ + ( ( flags & MEMMAP_FL_USED ) ? "U" : "-" ), \ + ( ( flags & MEMMAP_FL_INACCESSIBLE ) ? "X" : "-" ), \ + ( ( unsigned long long ) (region)->min ), \ + ( ( unsigned long long ) (region)->max ), \ + ( name ? " " : "" ), ( name ? name : "" ) ); \ + } while ( 0 ) + +#define DBGC_MEMMAP_IF( level, id, ... ) do { \ + DBG_AC_IF ( level, id ); \ + DBG_MEMMAP_IF ( level, __VA_ARGS__ ); \ + DBG_DC_IF ( level ); \ + } while ( 0 ) + +#define DBGC_MEMMAP( ... ) DBGC_MEMMAP_IF ( LOG, ##__VA_ARGS__ ) +#define DBGC2_MEMMAP( ... ) DBGC_MEMMAP_IF ( EXTRA, ##__VA_ARGS__ ) +#define DBGCP_MEMMAP( ... ) DBGC_MEMMAP_IF ( PROFILE, ##__VA_ARGS__ ) + +/** + * Dump system memory map (for debugging) + * + * @v hide Hide in-use regions from the memory map + */ +static inline void memmap_dump_all ( int hide ) { + struct memmap_region region; + + /* Do nothing unless debugging is enabled */ + if ( ! DBG_LOG ) + return; + + /* Describe all memory regions */ + DBGC ( &memmap_describe, "MEMMAP with in-use regions %s:\n", + ( hide ? "hidden" : "ignored" ) ); + for_each_memmap ( ®ion, hide ) + DBGC_MEMMAP ( &memmap_describe, ®ion ); +} + +extern void memmap_update ( struct memmap_region *region, uint64_t start, + uint64_t size, unsigned int flags, + const char *name ); +extern void memmap_update_used ( struct memmap_region *region ); +extern size_t memmap_largest ( physaddr_t *start ); + +#endif /* _IPXE_MEMMAP_H */ |
