iPXE
Data Structures | Macros | Functions | Variables
memmap.c File Reference

Memory mapping. More...

#include <stdint.h>
#include <errno.h>
#include <realmode.h>
#include <bios.h>
#include <memsizes.h>
#include <ipxe/io.h>

Go to the source code of this file.

Data Structures

struct  e820_entry
 An INT 15,e820 memory map entry. More...
 

Macros

#define SMAP   ( 0x534d4150 )
 Magic value for INT 15,e820 calls. More...
 
#define E820_TYPE_RAM   1
 Normal memory. More...
 
#define E820_TYPE_RESERVED   2
 Reserved and unavailable. More...
 
#define E820_TYPE_ACPI   3
 ACPI reclaim memory. More...
 
#define E820_TYPE_NVS   4
 ACPI NVS memory. More...
 
#define E820_ATTR_ENABLED   0x00000001UL
 
#define E820_ATTR_NONVOLATILE   0x00000002UL
 
#define E820_ATTR_UNKNOWN   0xfffffffcUL
 
#define E820_MIN_SIZE   20
 
#define e820buf   __use_data16 ( e820buf )
 
#define memmap_post   __use_data16 ( memmap_post )
 

Functions

 FILE_LICENCE (GPL2_OR_LATER_OR_UBDL)
 
struct e820_entry __attribute__ ((packed))
 
static struct e820_entry __bss16 (e820buf)
 Buffer for INT 15,e820 calls. More...
 
uint8_t __bss16 (memmap_post)
 We are running during POST; inhibit INT 15,e820 and INT 15,e801. More...
 
static unsigned int extmemsize_e801 (void)
 Get size of extended memory via INT 15,e801. More...
 
static unsigned int extmemsize_88 (void)
 Get size of extended memory via INT 15,88. More...
 
unsigned int extmemsize (void)
 Get size of extended memory. More...
 
static int meme820 (struct memory_map *memmap)
 Get e820 memory map. More...
 
void x86_get_memmap (struct memory_map *memmap)
 Get memory map. More...
 
 PROVIDE_IOAPI (x86, get_memmap, x86_get_memmap)
 

Variables

uint64_t start
 Start of region. More...
 
uint64_t len
 Length of region. More...
 
uint32_t type
 Type of region. More...
 
uint32_t attrs
 Extended attributes (optional) More...
 

Detailed Description

Memory mapping.

Definition in file memmap.c.

Macro Definition Documentation

◆ SMAP

#define SMAP   ( 0x534d4150 )

Magic value for INT 15,e820 calls.

Definition at line 41 of file memmap.c.

◆ E820_TYPE_RAM

#define E820_TYPE_RAM   1

Normal memory.

Definition at line 55 of file memmap.c.

◆ E820_TYPE_RESERVED

#define E820_TYPE_RESERVED   2

Reserved and unavailable.

Definition at line 56 of file memmap.c.

◆ E820_TYPE_ACPI

#define E820_TYPE_ACPI   3

ACPI reclaim memory.

Definition at line 57 of file memmap.c.

◆ E820_TYPE_NVS

#define E820_TYPE_NVS   4

ACPI NVS memory.

Definition at line 58 of file memmap.c.

◆ E820_ATTR_ENABLED

#define E820_ATTR_ENABLED   0x00000001UL

Definition at line 60 of file memmap.c.

◆ E820_ATTR_NONVOLATILE

#define E820_ATTR_NONVOLATILE   0x00000002UL

Definition at line 61 of file memmap.c.

◆ E820_ATTR_UNKNOWN

#define E820_ATTR_UNKNOWN   0xfffffffcUL

Definition at line 62 of file memmap.c.

◆ E820_MIN_SIZE

#define E820_MIN_SIZE   20

Definition at line 64 of file memmap.c.

◆ e820buf

#define e820buf   __use_data16 ( e820buf )

Definition at line 68 of file memmap.c.

◆ memmap_post

#define memmap_post   __use_data16 ( memmap_post )

Definition at line 72 of file memmap.c.

Function Documentation

◆ FILE_LICENCE()

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL  )

◆ __attribute__()

struct e820_entry __attribute__ ( (packed)  )

◆ __bss16() [1/2]

static struct e820_entry __bss16 ( e820buf  )
static

Buffer for INT 15,e820 calls.

◆ __bss16() [2/2]

uint8_t __bss16 ( memmap_post  )

We are running during POST; inhibit INT 15,e820 and INT 15,e801.

◆ extmemsize_e801()

static unsigned int extmemsize_e801 ( void  )
static

Get size of extended memory via INT 15,e801.

Return values
extmemExtended memory size, in kB, or 0

Definition at line 79 of file memmap.c.

79  {
80  uint16_t extmem_1m_to_16m_k, extmem_16m_plus_64k;
81  uint16_t confmem_1m_to_16m_k, confmem_16m_plus_64k;
82  unsigned int flags;
83  unsigned int extmem;
84 
85  /* Inhibit INT 15,e801 during POST */
86  if ( memmap_post ) {
87  DBG ( "INT 15,e801 not available during POST\n" );
88  return 0;
89  }
90 
91  __asm__ __volatile__ ( REAL_CODE ( "stc\n\t"
92  "int $0x15\n\t"
93  "pushfw\n\t"
94  "popw %w0\n\t" )
95  : "=R" ( flags ),
96  "=a" ( extmem_1m_to_16m_k ),
97  "=b" ( extmem_16m_plus_64k ),
98  "=c" ( confmem_1m_to_16m_k ),
99  "=d" ( confmem_16m_plus_64k )
100  : "a" ( 0xe801 ) );
101 
102  if ( flags & CF ) {
103  DBG ( "INT 15,e801 failed with CF set\n" );
104  return 0;
105  }
106 
107  if ( ! ( extmem_1m_to_16m_k | extmem_16m_plus_64k ) ) {
108  DBG ( "INT 15,e801 extmem=0, using confmem\n" );
109  extmem_1m_to_16m_k = confmem_1m_to_16m_k;
110  extmem_16m_plus_64k = confmem_16m_plus_64k;
111  }
112 
113  extmem = ( extmem_1m_to_16m_k + ( extmem_16m_plus_64k * 64 ) );
114  DBG ( "INT 15,e801 extended memory size %d+64*%d=%d kB "
115  "[100000,%llx)\n", extmem_1m_to_16m_k, extmem_16m_plus_64k,
116  extmem, ( 0x100000 + ( ( ( uint64_t ) extmem ) * 1024 ) ) );
117 
118  /* Sanity check. Some BIOSes report the entire 4GB address
119  * space as available, which cannot be correct (since that
120  * would leave no address space available for 32-bit PCI
121  * BARs).
122  */
123  if ( extmem == ( 0x400000 - 0x400 ) ) {
124  DBG ( "INT 15,e801 reported whole 4GB; assuming insane\n" );
125  return 0;
126  }
127 
128  return extmem;
129 }
unsigned short uint16_t
Definition: stdint.h:11
#define CF
Definition: registers.h:181
unsigned long long uint64_t
Definition: stdint.h:13
#define memmap_post
Definition: memmap.c:72
__asm__ __volatile__("\n1:\n\t" "movb -1(%3,%1), %%al\n\t" "stosb\n\t" "loop 1b\n\t" "xorl %%eax, %%eax\n\t" "mov %4, %1\n\t" "rep stosb\n\t" :"=&D"(discard_D), "=&c"(discard_c), "+m"(*value) :"r"(data), "g"(pad_len), "0"(value0), "1"(len) :"eax")
__asm__(".section \".rodata\", \"a\", " PROGBITS "\n\t" "\nprivate_key_data:\n\t" ".size private_key_data, ( . - private_key_data )\n\t" ".equ private_key_len, ( . - private_key_data )\n\t" ".previous\n\t")
#define DBG(...)
Print a debugging message.
Definition: compiler.h:498
#define REAL_CODE(asm_code_str)
Definition: libkir.h:226
uint8_t flags
Flags.
Definition: ena.h:18

References __asm__(), __volatile__(), CF, DBG, flags, memmap_post, and REAL_CODE.

Referenced by extmemsize().

◆ extmemsize_88()

static unsigned int extmemsize_88 ( void  )
static

Get size of extended memory via INT 15,88.

Return values
extmemExtended memory size, in kB

Definition at line 136 of file memmap.c.

136  {
137  uint16_t extmem;
138 
139  /* Ignore CF; it is not reliable for this call */
140  __asm__ __volatile__ ( REAL_CODE ( "int $0x15" )
141  : "=a" ( extmem ) : "a" ( 0x8800 ) );
142 
143  DBG ( "INT 15,88 extended memory size %d kB [100000, %x)\n",
144  extmem, ( 0x100000 + ( extmem * 1024 ) ) );
145  return extmem;
146 }
unsigned short uint16_t
Definition: stdint.h:11
__asm__ __volatile__("\n1:\n\t" "movb -1(%3,%1), %%al\n\t" "stosb\n\t" "loop 1b\n\t" "xorl %%eax, %%eax\n\t" "mov %4, %1\n\t" "rep stosb\n\t" :"=&D"(discard_D), "=&c"(discard_c), "+m"(*value) :"r"(data), "g"(pad_len), "0"(value0), "1"(len) :"eax")
__asm__(".section \".rodata\", \"a\", " PROGBITS "\n\t" "\nprivate_key_data:\n\t" ".size private_key_data, ( . - private_key_data )\n\t" ".equ private_key_len, ( . - private_key_data )\n\t" ".previous\n\t")
#define DBG(...)
Print a debugging message.
Definition: compiler.h:498
#define REAL_CODE(asm_code_str)
Definition: libkir.h:226

References __asm__(), __volatile__(), DBG, and REAL_CODE.

Referenced by extmemsize().

◆ extmemsize()

unsigned int extmemsize ( void  )

Get size of extended memory.

Return values
extmemExtended memory size, in kB

Note that this is only an approximation; for an accurate picture, use the E820 memory map obtained via get_memmap();

Definition at line 156 of file memmap.c.

156  {
157  unsigned int extmem_e801;
158  unsigned int extmem_88;
159 
160  /* Try INT 15,e801 first, then fall back to INT 15,88 */
161  extmem_88 = extmemsize_88();
162  extmem_e801 = extmemsize_e801();
163  return ( extmem_e801 ? extmem_e801 : extmem_88 );
164 }
static unsigned int extmemsize_88(void)
Get size of extended memory via INT 15,88.
Definition: memmap.c:136
static unsigned int extmemsize_e801(void)
Get size of extended memory via INT 15,e801.
Definition: memmap.c:79

References extmemsize_88(), and extmemsize_e801().

Referenced by nbi_process_segments(), and x86_get_memmap().

◆ meme820()

static int meme820 ( struct memory_map memmap)
static

Get e820 memory map.

Parameters
memmapMemory map to fill in
Return values
rcReturn status code

Definition at line 172 of file memmap.c.

172  {
173  struct memory_region *region = memmap->regions;
174  struct memory_region *prev_region = NULL;
175  uint32_t next = 0;
176  uint32_t smap;
177  uint32_t size;
178  unsigned int flags;
179  unsigned int discard_D;
180 
181  /* Inhibit INT 15,e820 during POST */
182  if ( memmap_post ) {
183  DBG ( "INT 15,e820 not available during POST\n" );
184  return -ENOTTY;
185  }
186 
187  /* Clear the E820 buffer. Do this once before starting,
188  * rather than on each call; some BIOSes rely on the contents
189  * being preserved between calls.
190  */
191  memset ( &e820buf, 0, sizeof ( e820buf ) );
192 
193  do {
194  /* Some BIOSes corrupt %esi for fun. Guard against
195  * this by telling gcc that all non-output registers
196  * may be corrupted.
197  */
198  __asm__ __volatile__ ( REAL_CODE ( "pushl %%ebp\n\t"
199  "stc\n\t"
200  "int $0x15\n\t"
201  "pushfw\n\t"
202  "popw %%dx\n\t"
203  "popl %%ebp\n\t" )
204  : "=a" ( smap ), "=b" ( next ),
205  "=c" ( size ), "=d" ( flags ),
206  "=D" ( discard_D )
207  : "a" ( 0xe820 ), "b" ( next ),
208  "D" ( __from_data16 ( &e820buf ) ),
209  "c" ( sizeof ( e820buf ) ),
210  "d" ( SMAP )
211  : "esi", "memory" );
212 
213  if ( smap != SMAP ) {
214  DBG ( "INT 15,e820 failed SMAP signature check\n" );
215  return -ENOTSUP;
216  }
217 
218  if ( size < E820_MIN_SIZE ) {
219  DBG ( "INT 15,e820 returned only %d bytes\n", size );
220  return -EINVAL;
221  }
222 
223  if ( flags & CF ) {
224  DBG ( "INT 15,e820 terminated on CF set\n" );
225  break;
226  }
227 
228  /* If first region is not RAM, assume map is invalid */
229  if ( ( memmap->count == 0 ) &&
230  ( e820buf.type != E820_TYPE_RAM ) ) {
231  DBG ( "INT 15,e820 failed, first entry not RAM\n" );
232  return -EINVAL;
233  }
234 
235  DBG ( "INT 15,e820 region [%llx,%llx) type %d",
236  e820buf.start, ( e820buf.start + e820buf.len ),
237  ( int ) e820buf.type );
238  if ( size > offsetof ( typeof ( e820buf ), attrs ) ) {
239  DBG ( " (%s", ( ( e820buf.attrs & E820_ATTR_ENABLED )
240  ? "enabled" : "disabled" ) );
241  if ( e820buf.attrs & E820_ATTR_NONVOLATILE )
242  DBG ( ", non-volatile" );
243  if ( e820buf.attrs & E820_ATTR_UNKNOWN )
244  DBG ( ", other [%08x]", e820buf.attrs );
245  DBG ( ")" );
246  }
247  DBG ( "\n" );
248 
249  /* Discard non-RAM regions */
250  if ( e820buf.type != E820_TYPE_RAM )
251  continue;
252 
253  /* Check extended attributes, if present */
254  if ( size > offsetof ( typeof ( e820buf ), attrs ) ) {
255  if ( ! ( e820buf.attrs & E820_ATTR_ENABLED ) )
256  continue;
257  if ( e820buf.attrs & E820_ATTR_NONVOLATILE )
258  continue;
259  }
260 
261  region->start = e820buf.start;
262  region->end = e820buf.start + e820buf.len;
263 
264  /* Check for adjacent regions and merge them */
265  if ( prev_region && ( region->start == prev_region->end ) ) {
266  prev_region->end = region->end;
267  } else {
268  prev_region = region;
269  region++;
270  memmap->count++;
271  }
272 
273  if ( memmap->count >= ( sizeof ( memmap->regions ) /
274  sizeof ( memmap->regions[0] ) ) ) {
275  DBG ( "INT 15,e820 too many regions returned\n" );
276  /* Not a fatal error; what we've got so far at
277  * least represents valid regions of memory,
278  * even if we couldn't get them all.
279  */
280  break;
281  }
282  } while ( next != 0 );
283 
284  /* Sanity checks. Some BIOSes report complete garbage via INT
285  * 15,e820 (especially at POST time), despite passing the
286  * signature checks. We currently check for a base memory
287  * region (starting at 0) and at least one high memory region
288  * (starting at 0x100000).
289  */
290  if ( memmap->count < 2 ) {
291  DBG ( "INT 15,e820 returned only %d regions; assuming "
292  "insane\n", memmap->count );
293  return -EINVAL;
294  }
295  if ( memmap->regions[0].start != 0 ) {
296  DBG ( "INT 15,e820 region 0 starts at %llx (expected 0); "
297  "assuming insane\n", memmap->regions[0].start );
298  return -EINVAL;
299  }
300  if ( memmap->regions[1].start != 0x100000 ) {
301  DBG ( "INT 15,e820 region 1 starts at %llx (expected 100000); "
302  "assuming insane\n", memmap->regions[0].start );
303  return -EINVAL;
304  }
305 
306  return 0;
307 }
#define EINVAL
Invalid argument.
Definition: errno.h:428
#define CF
Definition: registers.h:181
#define E820_ATTR_ENABLED
Definition: memmap.c:60
uint32_t next
Next descriptor address.
Definition: myson.h:18
unsigned int count
Number of used regions.
Definition: io.h:503
#define E820_ATTR_NONVOLATILE
Definition: memmap.c:61
#define offsetof(type, field)
Get offset of a field within a structure.
Definition: stddef.h:24
#define E820_ATTR_UNKNOWN
Definition: memmap.c:62
#define memmap_post
Definition: memmap.c:72
#define ENOTSUP
Operation not supported.
Definition: errno.h:589
struct memory_region regions[MAX_MEMORY_REGIONS]
Memory regions.
Definition: io.h:501
#define E820_TYPE_RAM
Normal memory.
Definition: memmap.c:55
uint32_t attrs
Extended attributes (optional)
Definition: memmap.c:32
__asm__ __volatile__("\n1:\n\t" "movb -1(%3,%1), %%al\n\t" "stosb\n\t" "loop 1b\n\t" "xorl %%eax, %%eax\n\t" "mov %4, %1\n\t" "rep stosb\n\t" :"=&D"(discard_D), "=&c"(discard_c), "+m"(*value) :"r"(data), "g"(pad_len), "0"(value0), "1"(len) :"eax")
A usable memory region.
Definition: io.h:488
void * discard_D
Definition: bigint.h:31
unsigned int uint32_t
Definition: stdint.h:12
__asm__(".section \".rodata\", \"a\", " PROGBITS "\n\t" "\nprivate_key_data:\n\t" ".size private_key_data, ( . - private_key_data )\n\t" ".equ private_key_len, ( . - private_key_data )\n\t" ".previous\n\t")
#define ENOTTY
Inappropriate I/O control operation.
Definition: errno.h:594
uint64_t start
Physical start address.
Definition: io.h:490
#define __from_data16(pointer)
Definition: libkir.h:22
uint8_t size
Entry size (in 32-bit words)
Definition: ena.h:16
typeof(acpi_finder=acpi_find)
ACPI table finder.
Definition: acpi.c:45
#define DBG(...)
Print a debugging message.
Definition: compiler.h:498
#define e820buf
Definition: memmap.c:68
uint64_t end
Physical end address.
Definition: io.h:492
#define REAL_CODE(asm_code_str)
Definition: libkir.h:226
#define SMAP
Magic value for INT 15,e820 calls.
Definition: memmap.c:41
#define NULL
NULL pointer (VOID *)
Definition: Base.h:321
#define E820_MIN_SIZE
Definition: memmap.c:64
void * memset(void *dest, int character, size_t len) __nonnull
uint8_t flags
Flags.
Definition: ena.h:18

References __asm__(), __from_data16, __volatile__(), attrs, CF, memory_map::count, DBG, discard_D, E820_ATTR_ENABLED, E820_ATTR_NONVOLATILE, E820_ATTR_UNKNOWN, E820_MIN_SIZE, E820_TYPE_RAM, e820buf, EINVAL, memory_region::end, ENOTSUP, ENOTTY, flags, memmap_post, memset(), next, NULL, offsetof, REAL_CODE, memory_map::regions, size, SMAP, memory_region::start, and typeof().

Referenced by x86_get_memmap().

◆ x86_get_memmap()

void x86_get_memmap ( struct memory_map memmap)

Get memory map.

Parameters
memmapMemory map to fill in

Definition at line 314 of file memmap.c.

314  {
315  unsigned int basemem, extmem;
316  int rc;
317 
318  DBG ( "Fetching system memory map\n" );
319 
320  /* Clear memory map */
321  memset ( memmap, 0, sizeof ( *memmap ) );
322 
323  /* Get base and extended memory sizes */
324  basemem = basememsize();
325  DBG ( "FBMS base memory size %d kB [0,%x)\n",
326  basemem, ( basemem * 1024 ) );
327  extmem = extmemsize();
328 
329  /* Try INT 15,e820 first */
330  if ( ( rc = meme820 ( memmap ) ) == 0 ) {
331  DBG ( "Obtained system memory map via INT 15,e820\n" );
332  return;
333  }
334 
335  /* Fall back to constructing a map from basemem and extmem sizes */
336  DBG ( "INT 15,e820 failed; constructing map\n" );
337  memmap->regions[0].end = ( basemem * 1024 );
338  memmap->regions[1].start = 0x100000;
339  memmap->regions[1].end = 0x100000 + ( extmem * 1024 );
340  memmap->count = 2;
341 }
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
unsigned int count
Number of used regions.
Definition: io.h:503
static unsigned int basememsize(void)
Get size of base memory from BIOS free base memory counter.
Definition: memsizes.h:13
struct memory_region regions[MAX_MEMORY_REGIONS]
Memory regions.
Definition: io.h:501
unsigned int extmemsize(void)
Get size of extended memory.
Definition: memmap.c:156
uint64_t start
Physical start address.
Definition: io.h:490
#define DBG(...)
Print a debugging message.
Definition: compiler.h:498
uint64_t end
Physical end address.
Definition: io.h:492
static int meme820(struct memory_map *memmap)
Get e820 memory map.
Definition: memmap.c:172
void * memset(void *dest, int character, size_t len) __nonnull

References basememsize(), memory_map::count, DBG, memory_region::end, extmemsize(), meme820(), memset(), rc, memory_map::regions, and memory_region::start.

◆ PROVIDE_IOAPI()

PROVIDE_IOAPI ( x86  ,
get_memmap  ,
x86_get_memmap   
)

Variable Documentation

◆ start

uint64_t start

Start of region.

Definition at line 26 of file memmap.c.

◆ len

uint64_t len

Length of region.

Definition at line 28 of file memmap.c.

◆ type

uint32_t type

Type of region.

Definition at line 30 of file memmap.c.

◆ attrs

uint32_t attrs