计算机启动流程分析--以JOS为例(从BIOS到刚进入boot loader)

xiaoxiao2021-02-28  88

    最近的OS课程(借鉴自MIT6.828)学习了PC boot的过程,自己也动手完成了6.828的lab1,对启动流程有了一定认识。

    环境:jos,QEMU为lab的实验环境。

    CPU加电后,先进入预先写好的BIOS程序执行,首先执行:

[f000:fff0] 0xffff0: ljmp $0xf000,$0xe05b

    f000:fff0是这条语句的地址,必须注意:BIOS下,处于i8086模式,即系统的实际内存只有1MB,lab中的注释描述如下:

+------------------+ <- 0xFFFFFFFF (4GB) | 32-bit | | memory mapped | | devices | | | /\/\/\/\/\/\/\/\/\/\ /\/\/\/\/\/\/\/\/\/\ | | | Unused | | | +------------------+ <- depends on amount of RAM | | | | | Extended Memory | | | | | +------------------+ <- 0x00100000 (1MB) | BIOS ROM | +------------------+ <- 0x000F0000 (960KB) | 16-bit devices, | | expansion ROMs | +------------------+ <- 0x000C0000 (768KB) | VGA Display | +------------------+ <- 0x000A0000 (640KB) | | | Low Memory | | | +------------------+ <- 0x00000000

    可以注意到1MB以上的地址是Extended Memory。在i8086模式下,采用实模式寻址,方法是:

PA = 16 * CS + IP

     其中,CS是段寄存器,IP是指令寄存器(我们可能会对它在386模式下的拓展:EIP更熟悉)。

     这样的寻址模式是因为:需要支持20位地址空间(即1MB),仅有一个16位的寄存器是不够的,因此需要段寄存器配合。然而,现代操作系统已经忽略了“段(Segement)”的概念

    因此,我们得到实际的物理地址0xffff0,注意到这个地址接近1MB的边界,因此第一条BIOS语句会跳转到属于BIOS ROM的一个低的地址去。

    接下来的过程不再描述(主要是因为后来发现QEMU对每种不同的Arch都设计了不同的BIOS,而且BIOS代码太长)。我们需要关注的是,在某个时刻,BIOS会加载磁盘的引导块,找到boot loader所在的boot.S文件,然后把它加载到物理内存0x7c00处,然后将计算机控制权交给它。

    boot loader 的第一行是:

.globl start start: .code16 # Assemble for 16-bit mode cli # Disable interrupts cld # String operations increment # Set up the important data segment registers (DS, ES, SS). xorw %ax,%ax # Segment number zero movw %ax,%ds # -> Data Segment movw %ax,%es # -> Extra Segment movw %ax,%ss # -> Stack Segment

    第一条指令是0x7c00处的cli指令,作用是关闭中断(BIOS把它打开了)。

    然后是一些寄存器的初始化操作,接下来是:

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这段就是经典的设置A20的代码,关于A20,它是一个多年的历史遗留问题:回忆之前的i8086物理内存示意图,只有1MB大小的内存,在之后的升级过程中不断被拓展,为了保证“兼容性”,设计了A20,以下内容翻译自Wiki:

    原来的PC机中的8088只有20个地址线,有效1MB。最大地址FFFF,更高的位会被截断。当286(有24条地址线)需要与8088完全兼容(程序会假设只有20位地址)。IBM发明了一种开关来启用/禁用0x100000地址位。由于8042键盘控制器恰好有一个备用引脚,用于控制禁止该地址位的与门。该信号被称为A20,如果它为零,所有地址的最高4位被清除。

       显然是有些旧的程序会假设超过1MB的地址会“绕回”0地址处,我们的程序需要关闭这个功能,因此A20被设置。

        接下来是非常有技巧性的一段代码:

lgdt gdtdesc movl %cr0,
转载请注明原文地址: https://www.6miu.com/read-2614714.html

最新回复(0)