https://pdos.csail.mit.edu/6.828/2016/ 。6.828的课程自带了一个简单的基于unix的操作系统。打算写几篇阅读这个操作系统源码的文章。这是第一篇,主要讲解启动时候的主要操作。
一 bootloader的汇编代码部分
我们知道,在计算机启动的时候,首先执行的代码是主板上的BIOS(Basic Input Output System).BIOS所做的主要是一些硬件自检的工作。在这些工作做完之后,它会从启动盘里读取第一扇区的512字节数据到内存中,这512字节实际上就是我们熟知的bootloader.在导入完之后,BIOS就会把CPU的控制权给bootloader.BIOS会把bootloader导入到地址0x7c00开始的地方,然后把PC指针设成此地址,以完成跳转。下面让我们看看bootloader的汇编部分代码:
.code16 # Assemble for 16−bit mode
.globl start
start:
cli # BIOS enabled interrupts; disable
# Zero data segment registers DS, ES, and SS.
xorw %ax,%ax # Set %ax to zero
movw %ax,%ds # −> Data Segment
movw %ax,%es # −> Extra Segment
movw %ax,%ss # −> Stack Segment
.code16的意思是此段代码是16位的代码。为了保证向后的兼容性,在刚启动的时候,执行的是16位的代码。32位的代码要等到32位被使能之后才可以执行。
BIOS在执行的时候会打开中断,但这是BIOS已经不在执行了,所以它的中断向量表之类的也就不在起作用了,bootloader此时应当关闭中断,在合适的时机再将中断打开。
下面几条语句的用意是清掉段寄存器。在xv6中,我们有虚拟地址,逻辑地址,线性地址和物理地址的概念。虚拟地址的概念相信熟悉分页机制的肯定都知道。在进程中,指令操作的往往都不是实际的物理地址,因为这样会带来很多问题:安全问题,共享问题等等。所以用分页机制来做下转换,程序操作的都是虚拟地址,而这些虚拟地址都是不变的,操作系统负责将虚拟地址映射到实际的物理地址上,同样的虚拟地址在不同的时刻可能对应不同的物理地址。
在x86指令架构中,虚拟地址通常是用逻辑地址来表示的,虚拟地址通常保存成这样的形式segment:offset,每条地址处在一个段中,segment是该段的基地址,各个地址相对于段基址的偏移被存在offset里面。程序中出现的实际上只有offset,硬件自动通过通过segment和offset算出线性地址,线性地址再经过页表等一系列处理得到实际的物理地址。
在刚进入bootloader的时候,硬件处于实模式,在此模式下,只能使用16位的寄存器,但是真正可寻址的范围是20位地址,也就是1M的地址空间,硬件通过把segment左移四位然后加上offset的方式来得到线性地址,因为这时分页模式还没有打开,所以得到的就是实际的物理地址。
实模式下物理地址计算方式:segment >> 4 + offset.
%ds, %es,%ss实际上存放的就是各个段的基地址(segment),其中ds代表数据段,es代表扩展段,ss代表堆栈段。在BIOS的时候可能会用到这些寄存器,在这里把寄存器清0.
seta20.1:
inb $0x64,%al # Wait for not busy
testb $0x2,%al
jnz seta20.1
movb $0xd1,%al # 0xd1 −> port 0x64
outb %al,$0x64
seta20.2:
inb $0x64,%al # Wait for not busy
testb $0x2,%al
jnz seta20.2
movb $0xdf,%al # 0xdf −> port 0x60
outb %al,$0x60
在上述计算物理地址的过程中,用到了两个16位的寄存器,那么两个寄存器的最大值都是0xffff,所以得到的物理地址的最大值应该是是0xffff0+0xffff = 0x10ffef,这个地址实际上是有21位的,但是在实模式下,8086/8088寻址地址实际上只有20位,这也就意味着最高位是无效的,得到的地址实际上是0xffef.
但是在intel更高架构的处理器上(如80286),地址线总数是多余20位的,所以这21位是有效的,这就导致了在8086和80286在实模式下行为不一致。为了使行为一致,IBM采用了这样一种方法:当键盘控制器的输入为低时,清掉A21这位,只有键盘控制器的输入为高时,这一位才有效。具体的情形可以参考这篇文章:http://www.techbulo.com/703.html
当然,在这里我们需要离开实模式了,所以我们要确保键盘控制器输出为高,以保证在80286以