• 实模式下1M内存
  • 比特,字,字节单位
  • BIOS 是怎么启动的
  • 找到 BIOD 的入口地址
  • 找到 jmp指令
  • 小小总结

如果你亲自动手重载过系统你就听过 BIOS 这个名词。BIOS 全称叫 Base Input & Output System ,也就是基本输入输出系统。

实模式下1M内存

在很久以前,Intel 8086 有 20 条地址线,因为 220=1048576=1MB,所以,这 20 条地址线可以访问 1MB 的内存。如果用 16 进制来表示就是 0x00000 ~ 0xFFFFF

这里先大概预览一下实模式下的内存布局表

sysbios 内存 bios内存容量总数_sysbios 内存

比特,字,字节单位

计算机由几亿万个位(bit)组成,每个字节存储的都是 0,1 二进制.一般 8 个位组成一个字节(byte),当然不同机器不一样。

每个字节类似一个存储单元,但是这样的一个存储单元有点小,所以有些机器把多个字节连接在一起,组成一个更大的内存单位,称为【字】。一个字一般由 2 个 或者 4 个字节组成。所以呢,每个字包含了更多的位,每个字可以容纳的无符号整数范围是 0 ~ 4294967295 (232-1),可以容纳的有符号整数范围是 -2147483648 (-231) ~ 2147483647 (231-1)。

  • 1字节(Byte) = 8位(bit)
  • 1 千字节(KB) = 1024字节(B)
  • 1 兆字节(MB) = 1024K (1024KB)

内存地址 0 ~ 0x9FFFF 的空间范围是 640KB,这个范围的地址对应到 DRAM(动态随机访问内存,断电即丢失),也就是我们插在主板的内存条,但是,内存条的内存不等于全部的物理内存。

sysbios 内存 bios内存容量总数_sysbios 内存_02

上表中的 0xF0000 ~ 0xFFFF,这 64KB 内存就是 ROM (只读存储),这里存放的是 BIOS 的代码 (其实这里存储的只是跳转指令)。

我们先来看下面这张图,0xF0000 ~ 0xFFFF 这段地址可以分为 0xF0000 ~ 0xFFFEF + 0xFFFF0 ~ 0xFFFFF,其中 0xFFFF0 ~ 0xFFFFF 这段 16 字节,是 BIOS 的入口地址,此处的内容是 跳转指令 jmp f000: e05b 。其中 BIOS 的作用是 检测、初始化硬件 和 建立中断向量表,这里的建立操作对硬件来说就是 IO 操作。

sysbios 内存 bios内存容量总数_实模式_03

从上图可以清楚看出 ROM 只有 64KB,所以能够实现所有的 IO 操作非常有限,这也正是在实模式下为什么计算机只能运行硬件 IO 的基本操作。这应该也是 BIOS 为什么叫基本输入输出系统的原因吧。

回到一开始的问题,为什么在 CPU 眼里主板插上的内存条的内存不是“全部内存”呢?

这其实是由[地址总线]的宽度决定的,因为地址总线的宽度决定了可以访问的内存空间大小,就比如我们以前用的 32 位的电脑,其实它的地址范围就是 4GB (232=4294967296),所以你电脑如果还是 32位 的,那就算买的内存条大于 4GB 也不会有什么本质的作用。

注意,刚刚说的是寻址范围为 4GB,但是并没有说它一定会寻址到哪里,所以寻址范围不一定是物理地址。这是怎么回事呢?

因为在计算机中,除了主板上的内存条外,还有其他设备也需要通过地址总线来访问,就比如显存,硬盘控制器等。试想,如果把所有的地址总线都拿来给主板上的内存条用,那么其他设备怎么办呢?是吧。所以说,地址总线需要将一部分内存预留出来,剩下的内存才是指向 DRAM(物理内存)。

sysbios 内存 bios内存容量总数_寻址_04

所以不要还以为电脑中内存条越大越好,还得看你电脑中地址总线的宽度,如果你电脑的地址总线的寻址范围只有 8G,那你买个 16G 的内存条有什么用呢?

BIOS 是怎么启动的

找到 BIOD 的入口地址

BIOS 是计算机上第一个运行的软件,那么既然是第一个软件,那它肯定不能自己加载自己了,所以 BIOS 是由硬件加载的。这个硬件也就是我们前面提到的 只读存储器 ROM。因为是只读的,所以里面的内容是不可以更改的,也可以说 BIOS 的工作是一成不变的。当然你如果要刷机情况除外。

sysbios 内存 bios内存容量总数_实模式_05

从上图可以很清楚看出 BIOS 写在 ROM,然后 ROM 被映射到整个 1M (实模式)的顶部,也就是之前说的 64KB 那里。然后 BIOS 的入口地址是 0xFFFF0

好了,现在找到 BIOS 的入口了,那么 CPU 如何执行它呢?也就是说 CPU 的 cs:ip寄存器怎么将一串数字组织成 0xFFFF0 呢?

找到 jmp指令

这里先注释一点,CPU 给一串字符串给地址总线,地址总线将这一字符串映射成地址,CPU 才能访问该地址。

CPU 的访问内存需要涉及到内存分段机制,就是CPU 需要用 段基地址 + 偏移地址 才能找到物理地址。这里注意,在实模式下,段地址需要乘于 16,也就是向左移 4 位才能与偏移地址相加。

计算机在开机之后,CPU 的cs: ip寄存器被强制初始化为 0xF000: 0xFFF0,也就是 cs 寄存器的值是 0xF000,ip 寄存器的值是 0xFFF0,也就是段基地址是 0xF000,段内偏移地址是 0xFFF0,这个地址组合出来就是 0xFFFF0。

这里简单介绍下上面是怎么计算出来的。0xF000 转成二进制是 1111 0000 0000 0000 ,然后左移 4 位之后变成 1111 0000 0000 0000 0000 0000 ,再加上 0xFFF0(1111 1111 1111 0000) 等于 1111 1111 1111 1111 0000(FFFF0)。

0xF000 处存储的还是跳转指令 jmp f000: e05b,也就是下一条要执行的指令。也就是说跳转到下一条要执行的指令。这就是 BIOS 代码开始的地方。接下来 BIOS 就可以开始工作了。

小小总结

  • 主板内存条的内存不一定是实际的物理内存,这和地址总线的宽度有关,因为地址总线的宽度决定寻址的范围。而且不仅仅是主板上的内存条需要访问地址总线,其他设备也需要访问,所以地址总线需要预留出一部分地址空间出来给其他设备访问。因此我们买的 4GB 的内存条,在电脑看到的可能只有 3.8GB。
  • BIOS 的起始地址是 0xFFFF0,CPU 通过地址总线映射到这个地址,然后 CPU 访问该地址并执行它,这个访问过程需要用到内存分段机制,即 段基地址+偏移地址=物理地址。

参考《操作系统真象还原》《王爽的汇编语言》