利用BIOS中断获取内存容量

机器启动后有2种方式探测物理内存:直接探测、通过BIOS中断探测。
这里我们关注如何通过BIOS的0x15中断探测物理内存。

由于BIOS中断需要在实模式下调用,所以我们在bootloader中探测物理内存比较合适。

BIOS的0x15中断有3个子功能:e820h、e801h、88h。这三个子功能区别是:

  • e820h返回内存布局,信息量大
  • e801h返回内存容量
  • 88h最简单,功能也最弱

e820h子功能

这是功能最强大的子功能,使用也最复杂。

地址范围描述符

系统内存分为很多内存块,这些内存块加起来才构成系统的总内存。而这些内存块有不同的类型:有的OS可以使用、有的OS不能使用。

每次调用这个中断都会得到一块内存的描述,要通过多次调用才能得到系统所有内存块的描述。

e820将物理内存探测的结果以地址范围描述符的格式放在内存中。地址范围描述符共计20字节,格式是:

字节范围 描述
0~7 内存块基地址
8~15 这块内存的大小
16~20 这块内存的类型

我们将在内存中开辟一个数组来存放所有地址范围描述符。
在c语言中可以这样定义:

struct {
    uint64_t addr;
    uint64_t size;
    uint32_t type;
};

e820h的调用参数

显然在保护模式下用int $0x15来调用15h中断。

但在这之前我们要将参数放置在寄存器中:

  • eax:子功能编号,这里我们填入0xe820
  • edx:534D4150h(ascii字符”SMAP”),签名,约定填”SMAP”
  • ebx:每调用一次int $0x15,ebx会加1。当ebx为0表示所有内存块检测完毕。(重要!看后面的案例会明白如何使用)
  • ecx:存放地址范围描述符的内存大小,至少要设置为20。
  • es:di:告诉BIOS要把地址描述符写到这个地址。

中断的返回值如下:

  • CF标志位:若中断执行失败,则置为1。
  • eax:值是534D4150h(“SMAP”)
  • es:di:中断不改变该值,值与参数传入的值一致
  • ebx:下一个中断描述符的计数值(见后面的案例)
  • ecx:返回BIOS写到cs:di处的地址描述符的大小(应该就是20吧?)
  • ah:若发生错误,表示错误码

案例:实现内存探测

定义数据存放结构,约定探测结果存放于0x8000处

约定在bootloader中将内存探测结果放到0x8000地址处。
数据存放的格式在c中定义了:

struct e820map {
    int nr_map;  // 表示数组元素个数,该字段是为了方便后续OS,不是BIOS访问的
    struct {
        uint64_t addr;
        uint64_t size;
        uint32_t type;
    } map[E820MAX];
};
调用中断,并判断是否发生错误、是否探测完所有内存块

通过int $0x15调用中断。如果发生错误,CF位为1。那么可以尝试使用其它子功能进行探测,或者就直接关机(连内存容量都没探测肯定无法启动OS了)

根据ebx判断是否完成所有内存块的探测,如果没有则继续int $0x15探测下一个内存块,如此反复直到所有内存块探测完毕。

Created
  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值