Detecting Memory (x86): Difference between revisions

m
Bot: Replace deprecated source tag with syntaxhighlight
[unchecked revision][unchecked revision]
No edit summary
m (Bot: Replace deprecated source tag with syntaxhighlight)
Line 31:
 
Usage:
<sourcesyntaxhighlight lang="asm">
; Clear carry flag
clc
Line 42:
 
; AX = amount of continuous memory in KB starting from 0.
</syntaxhighlight>
</source>
 
Note: this function is supposed to be always present, and may not modify the carry flag. If an emulator doesn't support it, the carry flag will be set, indicating error.
Line 151:
 
Linux Usage:
<sourcesyntaxhighlight lang="asm">
XOR CX, CX
XOR DX, DX
Line 168:
; AX = number of contiguous Kb, 1M to 16M
; BX = contiguous 64Kb pages above 16M
</syntaxhighlight>
</source>
 
====BIOS Function: INT 0x15, AX = 0xDA88====
Line 182:
 
Usage:
<sourcesyntaxhighlight lang="asm">
CLC ; CF bug workaround
MOV AH, 0x88
Line 190:
JE SHORT .ERR
; AX = number of contiguous KB above 1M
</syntaxhighlight>
</source>
 
====BIOS Function: INT 0x15, AH = 0x8A====
Line 355:
Alternatively, you can modify the multiboot header, specifically the multiboot_mmap_entry struct, to the following to get the correct values:
 
<sourcesyntaxhighlight lang="c">
struct multiboot_mmap_entry
{
Line 371:
} __attribute__((packed));
typedef struct multiboot_mmap_entry multiboot_memory_map_t;
</syntaxhighlight>
</source>
 
Each multiboot mmap entry is stored as the following:
Line 413:
== What about on UEFI? ==
On UEFI, you have 'BootServices->GetMemoryMap'. This function is similar to E820 and is the only solution on new UEFI machines. Basically, to use, first you call it once to get the size of the memory map. Then you allocate a buffer of that size, and then call again to get the map itself. Watch out, by allocating memory you could increase the size of the memory map. Considering that a new allocation can split a free memory area into two, you should add space for 2 additional memory descriptors. It returns an array of EFI_MEMORY_DESCRIPTORs. They have the following format (taken from GNU EFI):
<sourcesyntaxhighlight lang="c">
typedef struct {
UINT32 Type; // EFI_MEMORY_TYPE, Field size is 32 bits followed by 32 bit pad
Line 422:
UINT64 Attribute; // Field size is 64 bits
} EFI_MEMORY_DESCRIPTOR;
</syntaxhighlight>
</source>
To traverse them, you can use the NEXT_MEMORY_DESCRITOR macro.
 
Memory types are different to the E820 codes. For converting, see [https://github.com/tianocore/edk2/blob/70d5086c3274b1a5b099d642d546581070374e6e/OvmfPkg/Csm/LegacyBiosDxe/LegacyBootSupport.c#L1601 CSM E820 compatibility].
<sourcesyntaxhighlight lang="c">
typedef enum {
EfiReservedMemoryType,
Line 445:
EfiMaxMemoryType
} EFI_MEMORY_TYPE;
</syntaxhighlight>
</source>
 
==Code Examples==
Line 479:
===Getting an E820 Memory Map===
 
<sourcesyntaxhighlight lang="asm">
; use the INT 0x15, eax= 0xE820 BIOS function to get a memory map
; note: initially di is 0, be sure to set it to a value so that the BIOS code will not be overwritten.
Line 531:
stc ; "function unsupported" error exit
ret
</syntaxhighlight>
</source>
 
Sample in C (assuming we are in a bootloader environment, real mode, DS and CS = 0000):
Line 741:
* it's better to assume that memory holes are present (and risk skipping some RAM) than to assume that memory holes aren't present (and risk crashing). This means assuming that the area from 0x00F00000 to 0x00FFFFFF can't be used and not probing this area at all (it's possible that some sort of ISA device is in this area, and that any write to this area can cause problems).
 
<sourcesyntaxhighlight lang="asm">
;Probe to see if there's RAM at a certain address
;
Line 798:
pop eax
ret
</syntaxhighlight>
</source>
 
Further Notes: