操作系统为了初始化它自己,一个最重要的信息就是其宿主系统的可用内存所对应的内存
图。一般情况下,最基本的方法(也是唯一的方法)就是通过BIOS中断INT 0x15,eax
= 0xe820实现.大多数BIOS在其探测内存被执行之前是不能使用任何RAM的,之后探测
每个内存模板的大小,最后使用探测到的RAM来配置芯片集,在这个阶段,内存并不能运
行任何程序.
下面介绍BIOS 函数:INT 0x15, EAX = 0xe820
目前为止,探测一个PC机内存的最好方法是通过调用INT 0x15,eax = 0xe820来实现。
这个功能在2002年以后被所有PC机所使用,这是唯一能够探测超过4G大小内存的方案,
当然,这个方法也可以被认为是内存的最终检测方法.实际上,这个函数返回一个非排序
列表,这个列表包含了那些没有使用的项,并且可能返回存在覆盖的区域.在linux中每
个列表项被存放在ES:EDI指定的内存区域中。每个项均有一定的格式:即2个8字节字段,
一个2字节字段.我们会发现,在linux中,对于内存探测的实现由函数detect_memory_e820
来实现的,在这个函数中,使用了一个do...while()循环来实现,并将所探测的内容写
入boot_params.e820_map数组中,下面是具体的实现:
do {
size = sizeof(struct e820entry);
asm ("int $0x15; setc %0"
: "=d" (err), "+b" (next), "=a" (id), "+c" (size),
"=m" (*desc)
: "D" (desc), "d" (SMAP), "a" (0xe820)
);
count++;
desc++;
}while(next && count < ARRAY_SIZE(boot_params.e820_map));
下面是e820entry结构体,其结构体中的内容对应着上面提到的列表内容.
struct e820entry {
__u64 addr;
__u64 size;
__u32 type;
}__attribute__((packed));
addr字段存放的基始地址、size字段存放的是探测区域的大小(如果值为0,那么就将忽略此项)、
type是区域类型.
对于区域类型有以下几种:
类型1:可用RAM
类型2:保存的RAM,即不可用
类型3:ACPI 可回收内存
类型4:ACPI NVS内存区
类型5:包含有坏内存区的区域
当第一次调用这个函数时,将ES:EDI指向列表对应的目的缓冲区,清空EBX,设置EDX
的值为0x534d4150,设置EAX的值为0xe820,设置ecx为24,之后就调用中断INT 0x15。
如果此中断运行成功,那么eax的值将会被设置为0x534d4150,进位标志被清空,EBX被
设置为非0值,这个值将会被保存,使用于下一个函数调用.CL保存的是保存在ES:EDI位
置的字节长度.为了给函数的后续调用,EDI的值将会以列表项长度增加.同时,重置eax的
值为0xe820,ecx为24(ecx的值实际上就是sizeof(struct entryf)),ebx也许会
被设置为0。如果ebx的值被设置为0,那么将会结束函数的运行,否则将会继续进行探测。
阅读(1449) | 评论(0) | 转发(0) |