Linux通过BIOS的中断向量0x15来探测物理内存布局,有三种常见的方式,0xe820、0x801、0x88三种,默认Linux会同时使用这三者来进行探测。
void detect_memory(void) {
detect_memory_e820();
detect_memory_e801();
detect_memory_88();
}
e820探测
/*
* The E820 memory region entry of the boot protocol ABI:
*/
struct boot_e820_entry {
__u64 addr;
__u64 size;
__u32 type;
} __attribute__((packed));
// 最多128个
struct boot_e820_entry e820_table[E820_MAX_ENTRIES_ZEROPAGE]; /* 0x2d0 */
static void detect_memory_e820(void)
{
int count = 0;
struct biosregs ireg, oreg;
struct boot_e820_entry *desc = boot_params.e820_table;
static struct boot_e820_entry buf; /* static so it is zeroed */
initregs(&ireg);
ireg.ax = 0xe820;
ireg.cx = sizeof(buf);
ireg.edx = SMAP;
ireg.di = (size_t)&buf;
/*
* Note: at least one BIOS is known which assumes that the
* buffer pointed to by one e820 call is the same one as
* the previous call, and only changes modified fields. Therefore,
* we use a temporary buffer and copy the results entry by entry.
*
* This routine deliberately does not try to account for
* ACPI 3+ extended attributes. This is because there are
* BIOSes in the field which report zero for the valid bit for
* all ranges, and we don't currently make any use of the
* other attribute bits. Revisit this if we see the extended
* attribute bits deployed in a meaningful way in the future.
*/
do {
intcall(0x15, &ireg, &oreg);
ireg.ebx = oreg.ebx; /* for next iteration... */
/* BIOSes which terminate the chain with CF = 1 as opposed
to %ebx = 0 don't always report the SMAP signature on
the final, failing, probe. */
if (oreg.eflags & X86_EFLAGS_CF)
break;
/* Some BIOSes stop returning SMAP in the middle of
the search loop. We don't know exactly how the BIOS
screwed up the map at that point, we might have a
partial map, the full map, or complete garbage, so
just return failure. */
// 校验魔术字
if (oreg.eax != SMAP) {
count = 0;
break;
}
*desc++ = buf;
count++;
} while (ireg.ebx && count < ARRAY_SIZE(boot_params.e820_table));
// 记录E820探测到的内存块数目
boot_params.e820_entries = count;
}
e820探测到的内存信息:
root@tianqian:~/code/rust-for-linux# dmesg |grep "e820"
[ 0.000000] BIOS-e820: [mem 0x0000000000000000-0x000000000009fbff] usable
[ 0.000000] BIOS-e820: [mem 0x000000000009fc00-0x000000000009ffff] reserved
[ 0.000000] BIOS-e820: [mem 0x00000000000f0000-0x00000000000fffff] reserved
[ 0.000000] BIOS-e820: [mem 0x0000000000100000-0x000000009fffffff] usable
[ 0.000000] BIOS-e820: [mem 0x00000000a0000000-0x00000000a111ffff] reserved
[ 0.000000] BIOS-e820: [mem 0x00000000a1120000-0x00000000bffcefff] usable
[ 0.000000] BIOS-e820: [mem 0x00000000bffcf000-0x00000000bfffffff] reserved
[ 0.000000] BIOS-e820: [mem 0x00000000fffbc000-0x00000000ffffffff] reserved
[ 0.000000] BIOS-e820: [mem 0x0000000100000000-0x0000001f3fffffff] usable
[ 0.000000] BIOS-e820: [mem 0x0000001f40000000-0x000000203fffffff] reserved
[ 0.000608] e820: update [mem 0x00000000-0x00000fff] usable ==> reserved
[ 0.000611] e820: remove [mem 0x000a0000-0x000fffff] usable
[ 0.916047] e820: reserve RAM buffer [mem 0x0009fc00-0x0009ffff]
[ 0.916049] e820: reserve RAM buffer [mem 0xbffcf000-0xbfffffff]
root@tianqian:~/code/rust-for-linux#
只有内存类型为usable的才能被操作系统所使用。