Linux0.11——第一回 最开始的两行代码

按下开机键后究竟发生了什么

  • 官方教科书说法:

BIOS 按照“启动顺序”,把控制权转交给排在第一位的存储设备:硬盘。然后在硬盘里寻找主引导记录的分区,这个分区告诉电脑操作系统在哪里,并把操作系统被加载到内存中,然后你就能看到经典的启动界面了,这个开机过程也就完成了。

我们需要明确3点:

  1. 内存是存储数据的地方,给出一个地址信号,内存可以返回该地址所对应的数据。
  2. CPU 的工作方式就是不断从内存中取出指令,并执行。
  3. CPU 从内存的哪个地址取出指令,是由一个寄存器中的值决定的,这个值会不断进行 +1 操作,或者由某条跳转指令指定其值是多少。

内存映射

CPU 地址总线的宽度决定了可访问的内存空间的大小。比如 16 位的 CPU 地址总线宽度为 20 位,地址范围是 1M。32 位的 CPU 地址总线宽度为 32 位,地址范围是 4G。你可以算算我们现在的 64 位机的地址范围。

可是,可访问的内存空间这么大,并不等于说全都给内存使用,也就是说寻址的对象不只有内存,还有一些外设也要通过地址总线的方式去访问,那怎么去访问这些外设呢?就是在地址范围中划出一片片的区域,这块给显存使用,那块给硬盘控制器使用,等等 。

实模式下的内存分布

Linux0.11——第一回 最开始的两行代码_第1张图片

怎么就从BIOS里的程序开始执行了

好了,现在我们知道 BIOS 里的信息被映射到了内存 0xC0000 - 0xFFFFF 位置,其中最为关键的系统 BIOS 被映射到了 0xF0000 - 0xFFFFF 位置。

通俗点简单点说就是,按下开机键,一定有硬件的办法使得PC寄存器设置成BIOS入口地址处的值0xFFFF0,显然只有16字节肯定不是BIOS程序的全部内容,一定是一个跳转指令。

jmp far f000:e05b

地址 0xfe05b 处开始,便是 BIOS 真正发挥作用的代码了,这块代码会检测一些外设信息,并初始化好硬件,建立中断向量表并填写中断例程。

0x7C00是啥

为什么非要是 0x7c00 呢?找到一个比较浪漫的说法,具体是不是也不清楚

07在ASCII码中是bell的意思,这里代指Bell Labs(贝尔实验室),后面的C0你可以理解成C语言(1973年第四版的Unix用C语言重写了),也可理解为 Clear Zero,Current Zero…… 这也许就是……反正浪漫就完事儿了!

最开始的两行代码

Linux0.11——第一回 最开始的两行代码_第2张图片
对于我们理解操作系统而言,此时的 BIOS 仅仅就是个代码搬运工,把 512 字节的二进制数据从硬盘搬运到了内存中而已。所以作为操作系统的开发人员,仅仅需要把操作系统最开始的那段代码,编译并存储在硬盘的 0 盘 0 道 1 扇区即可。之后 BIOS 会帮我们把它放到内存里,并且跳过去执行。

而 Linux-0.11 的最开始的代码,就是这个用汇编语言写的 bootsect.s,位于 boot 文件夹下。
通过编译,这个 bootsect.s 会被编译成二进制文件,存放在启动区的第一扇区。
Linux0.11——第一回 最开始的两行代码_第3张图片

mov ax,0x07c0
mov ds,ax

这里有两个疑问:

  1. 为什么要这么麻烦,直接mov ds 0x07c0不行吗,原因是CPU设计时没有设计直接把立即数传入到ds寄存器的线路
  2. 为什么这里要有这个0x07c0,后面的地址都是要加上基址0x7c00(历史原因),也有一部分原因说是为了解决重定位问题。

Linux0.11——第一回 最开始的两行代码_第4张图片
Linux0.11——第一回 最开始的两行代码_第5张图片
重定位难题
段地址和偏移地址

总结

  1. 按下开机键,CPU 将 PC 寄存器的值强制初始化为 0xffff0,这个位置是 BIOS 程序的入口地址(一跳)
  2. 该入口地址处是一个跳转指令,跳转到 0xfe05b 位置,开始执行(二跳)
  3. 执行了一些硬件检测工作后,最后一步将启动区内容加载到内存 0x7c00,并跳转到这里(三跳)
  4. 启动区代码主要是加载操作系统内核,并跳转到加载处(四跳)

BIOS负责加载了启动区,而启动区又负责加载真正的操作系统内核。

你可能感兴趣的:(Linux学习,linux)