---- 整理自狄泰软件唐佐林老师课程
查看所有文章链接:(更新中)深入浅出操作系统 - 目录
文章目录
1. 讨论
- 怎么知道还剩多少空闲页框?一共有多少页框可用?
==> 如何获取系统物理内存的大小?
2. BIOS提供的内存相关中断(int 0x15)
- 基础功能(eax = 0xE801)
- 分别检测低15MB和高16MB~4GB的内存
- 最大支持4GB内存检测
- 高级功能(eax = 0xE820)
- 遍历主机上所有的内存
- 获取各个内存范围的详细信息
2.1 int 0x15基础功能
- 中断参数
eax = 0xE801 - 返回值:
- cf = 0 ==> 成功0,出错1
- ax、cx ==> 以1KB为单位,表示15MB以下的内存容量
- bx、dx ==> 以64KB位单位,表示16MB以上的内存容量
- (少了1MB,下面的内容会讲到)
2.1.1 汇编小贴士
注:有进位就跳转到标签处。
- 进位标志位
- 判断运算过程是否进位/借位
- 运算不需要进位/借位时CF位的值为0,否则为1
2.1.2 int 0x15基础功能示例
2.1.3 编程实验:获取物理内存容量
【参看链接】:31-32 - 获取物理内存容量 / 31 / 00
因为要使用bios中断,故在16位code中添加GetMemSize
反编译不加:-b 32
2.1.4 问题
- 为什么0xE801获取的内存容量分两部分表示?
- 为什么0xE801获取的内存容量少了1MB?
- 一些历史原因
- 80286中的24根地址线最大寻址范围是16MB
- 当时的ISA设备使用15MB以上的地址作为缓冲区
- 操作系统无法使用15MB~16MB的物理内存
- 80386之后的处理器为了兼容,多余16MB的内存容量单独返回
- 为了兼容性,在使用int 0x15后,ax寄存器最多表示15MB的内存容量,即:最大值为0x3C00,这样,对于80286时代的各种程序就可以完全兼容,正常执行。
2.1.5 修正物理内存容量
【参看链接】:31-32 - 获取物理内存容量 / 31 / 01
2.1.6 小推论
- eax = 0xE801 所返回的是可实际使用的内存容量
- 处理器对内存地址空间做了分段处理(这里的分段不是保护模式下的分段,而是处理器对内存地址空间的分段)
- 问题
- 是否能够获取处理器对内存地址进行分段的详细信息?
2.2 int 0x15进阶版功能
- 高级功能(eax = 0xE820)
- 遍历主机上所有的内存
- 获取各个内存范围的详细信息
- 中断参数
eax = 0xE820(固定值)
edx = 0x534D4150(固定值)
ebx ==> 初始参数必须为0,终止标志
ecx ==> ARDS结构体大小(20字节)
es:di ==> ARDS结构体数组(每个元素占用20字节)
2.2.1 地址范围描述结构(Address Range Descriptor Structure)
2.2.2 int 0x15进阶功能示例
伪代码:
2.2.3 编程实验:获取ARDS记录
【参看链接】:31-32 - 获取物理内存容量 / 32 / 00
2.2.4 问题
- ARDS记录中并没有包含物理内存容量的信息,那么记录这些记录有什么意义?
2.2.5 ARDS结构体中的Type成员
- type = 1:AddressRangeMemory
这段内存可以被操作系统使用 - type = 2:AddressRangeReserved
内存使用中或被保留,操作系统不可使用 - type = 其它值:未定义
保留,可当作AddressRangeMemory处理
2.2.6 根据ARDS记录来计算物理内存
- 在32位系统中:
- ARDS结构体中的 BaseAddrHigh 和 LengthHigh 均为 0(32位系统中只需要关心32位的BaseAddrLow)
- 物理内存容量需要通过属性为1的内存段计算
- 计算方式为:max { BaseAddrLow + LengthLow }
- BaseAddrLow + LengthLow 是一段内存的地址上限
(当一片内存可被操作系统使用,且地址上限最大时,这个地址上限就是物理内存的大小)
- BaseAddrLow + LengthLow 是一段内存的地址上限
- 伪代码
【参看链接】:31-32 - 获取物理内存容量 / 32 / 01
这里借用上述实验的图片,计算出 属性为 1 的内存段大小等于0x01ff0000并不等于32MB,算上属性为3的长度0x10000,0x01ff0000+0x00010000=0x02000000=32MB(暂时不清楚为啥属性3的要加上)。
- 实验中使用的策略:
- 通过0xE801计算物理内存的大小
- 通过0xE820获取各个ARDS并填入结构体数组
- 根据ARDS结构体数组计算物理内存的大小
- 选择通过0xE801和0xE820计算得到的较大内存容量作为最终结果
- Linux中获取物理内存容量的策略
3. 小结
- int 0x15可用于获取物理内存容量
- 0xE801子功能修正后可得到物理内存容量
- 0xE820子功能通过ARDS得到更详细的内存信息
- 需要多次使用0xE820子功能才能获得物理内存容量
- 操作系统依赖于BIOS中断获取硬件信息