BIOS关于获取内存信息的调用

OS开机获取当前计算机的内存信息是一件很重要的事情,因为分页机制要用到它。来看看Linux是怎么做的吧 。

读了0.11内核的人应该注意到了,linus使用int 0x15 ah = 0x88中断调用获取扩展内存的大小,代码极其简洁:

mov  ah, 0x88
int  0x15
mov  [2], ax

 

这个方法真得很简单,而且不用担心BIOS不支持(该调用从286时代就存在了!)但它有个致命缺陷:ax的单位是KB,而只有16位的ax所能表示的扩展内存上限仅有2^(16+10) = 64M!

这在当时也许是足够了(偶99年买的电脑才32M!!!),不过放在今天大概没人愿意接受。不幸的是当时PC机的BIOS确实也只能支持到这一步(他们都认为64M足够了- -)。

那么我们来看看新时代的内存信息获取方法吧。

时间再向后一点,到1994年。新的BIOS开始支持一种新的中断调用,那就是int 0x15 ax = 0xe801。

该方法终于能够支持64M以上的扩展内存了,2.33.4.4的代码如下:

meme801:
  stc                # fix to work around buggy
  xorw %cx, %cx      # BIOSes which dont clear/set
 
xorw %dx, %dx      # carry on pass/error of
                    
# e801h memory size call
                     # or merely pass cx,dx though
                     # without changing them.
  movw $0xe801, %ax
 
int  $0x15
 
jc   mem88

 
cmpw $0x0, %cx     # Kludge to handle BIOSes
 
jne  e801usecxdx   # which report their extended
  cmpw $0x0, %dx     # memory in AX/BX rather than
 
jne  e801usecxdx   # CX/DX.  The spec I have read
 
movw %ax, %cx      # seems to indicate AX/BX
 
movw %bx, %dx      # are more reasonable anyway...

e801usecxdx:
  andl $0xffff, %edx  # clear sign extend
 
shll $6, %edx       # and go from 64k to 1k chunks
 
movl %edx, (0x1e0)  # store extended memory size
 
andl $0xffff, %ecx  # clear sign extend
 
addl %ecx, (0x1e0)  # and add lower memory into
                     
# total size.

 

比起前一种方法长了许多= =。

这个调用有些奇怪,有些BIOS使用ax/bx存放内存信息,而有些却使用cx/dx XD,通过判断哪些寄存器被置零可以知道到底该用ax/bx还是cx/dx。由于bx(dx)的单位是64K,故该方法最大可以获得2^(16+16) = 4G内存!这和IA32的内存上限值是一致的,因此这个方法就基本够用了。但是不幸的是,即使在今天,许多BIOS还是不支持该调用。

更新的BIOS提供了更好的方法,那就是著名的int 0x15 ax = 0xe820中断调用。

在于前辈的书上提到的就是这种方法。它最全面,除了能获得内存大小之外还可以获得内存分布!我上一篇文章所提及得内存分布在这个调用中都能找得到!

现在我们有这么多选择,到底用什么比较好呢?来看看linux是怎么选的。

其实很简单,3种方法都用!2.4.33.4内核中使用全部的三种方法!它首先尝试int 0x15 ax = 0xe820,如果失败(通常是BIOS版本太低)则尝试int 0x15 ax = 0xe801。如果还失败(原因同前),则只好尝试int 0x15 ah = 0x88(这时候你就只能使用64MB的小内存了 = =)。

由于2.4.33.4中关于int 0x15 ax = 0xe820的代码太长,而且难懂,我就不贴了,讨论这个问题的大有人在,请打开google自行查询。。。

-------------------------------------------------------

追加1: int 0x15 ah = 0x88的使用简介

中断服务:0x15
AH:0x88
输入:无
输出:AX = 扩展内存大小(单位KB,最大64MB)

追加2:int 0x15 ax = 0xe801的使用简介

中断服务:0x15
AX:  0xE801
输入: 无
输出: AX = 低于16M的扩展内存大小(单位1KB,最大0x3c00 = 15MB),或为0
      BX = 大于16M的扩展内存大小(单位64KB,最大4GB),或为0
      CX = 低于16M的扩展内存大小(单位1KB,最大0x3c00 = 15MB),或为0
      DX = 大于16M的扩展内存大小(单位64KB,最大4GB),或为0
返回:CF置位表示出错
其他:在一些BIOS上使用CX/DX替代AX/BX表示内存大小,这时候AX/BX被置0。

 

追加3: 有兴趣的人可以参考这个页面:

            http://www.huihoo.com/gnu_linux/own_os/booting-memory_check_6.htm

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页