MIT6.828-LAB1 : PC启动

Lab1 1. 先熟悉PC的物理地址空间

image-20210620120250345

这里其实有很多可以说的,不过先简单描述一下吧。从0x00000000到0x00100000这1mb的地址空间时机器处于16位的实模式。也就是说这个时候机器的汇编都是16位汇编。这是为了兼容之前的8086处理器。在这1mb里面。有我们常见的bios,这里要做的就是进行一些开机前的检查,随后把内核读取进来,就算开机完成了

2. 追踪ROM BIOS

这里要求我们利用断点跟随一下bios的过程,看一下bios干了什么

这里的调试要利用到两个终端,一个执行make qemu-gdb 另一个执行make gdb

image-20210620123141845

你会看到gdb会停在这个界面。这里的停在的地址是oxfff0这是通过

oxfooo << 4 + oxfff0 得到的 $cs = oxf000 $pc = 0xfff0

这样计算地址的方法是还是因为当前在是模式。所以寻址方式是 $cs << 4 + $pc

接下来就到了bios的执行时间。它大概会做下面的事情

首先bios会初始化一些中断向量表,然后会初始化一些重要设备比如vga等等,然后开机提示信息就回现实(如windows常见的loading图)在初始化PCI总线和一些重要设备之后,它搜索可引导设备,如软盘,硬盘驱动器或CD-ROM。 最终,当它找到可启动磁盘时,BIOS将引导加载程序从磁盘读取。随后转移到引导启动程序上去

3. The Boot Loader

于PC来说,软盘,硬盘都可以被划分为一个个大小为512字节的区域,叫做扇区。一个扇区是一次磁盘操作的最小粒度。每一次读取或者写入操作都必须是一个或多个扇区。如果一个磁盘是可以被用来启动操作系统的,就把这个磁盘的第一个扇区叫做启动扇区。当BIOS找到一个可以启动的软盘或硬盘后,它就会把这512字节的启动扇区加载到内存地址0x7c00~0x7dff这个区域内。

 对于6.828,我们将采用传统的硬盘启动机制,这就意味着我们的boot loader程序的大小必须小于512字节。整个boot loader是由一个汇编文件,boot/boot.S,以及一个C语言文件,boot/main.c组成。Boot loader必须完成两个主要的功能。

首先,boot loader要把处理器从实模式转换为32bit的保护模式,因为只有在这种模式下软件可以访问超过1MB空间的内容。

然后,boot loader可以通过使用x86特定的IO指令,直接访问IDE磁盘设备寄存器,从磁盘中读取内核。

对于boot loader来说,有一个文件很重要,obj/boot/boot.asm。这个文件是我们真实运行的boot loader程序的反汇编版本。所以我们可以把它和它的源代码即boot.S以及main.c比较一下。

好下面就去0x7c00这个地址看一下这个启动扇区都做了什么

我们依次来分析一下boot.S的汇编代码

 /boot/boot.S:

1 .globl start 2 start: 3 .code16 # Assemble for 16-bit mode 4 cli # Disable interrupts

  这几条指令就是boot.S最开始的几句,其中cli是boot.S,也是boot loader的第一条指令。这条指令用于把所有的中断都关闭。因为在BIOS运行期间有可能打开了中断。此时CPU工作在实模式下。

5 cld # String operations increment

  这条指令用于指定之后发生的串处理操作的指针移动方向。在这里现在对它大致了解就够了。

6 # Set up the important data segment registers (DS, ES, SS). 7 xorw %ax,%ax # Segment number zero 8 movw %ax,%ds # -> Data Segment 9 movw %ax,%es # -> Extra Segment 10 movw %ax,%ss # -> Stack Segment

  这几条命令主要是在把三个段寄存器,ds,es,ss全部清零,因为经历了BIOS,操作系统不能保证这三个寄存器中存放的是什么数。所以这也是为后面进入保护模式做准备。

11 # Enable A20: 12 # For backwards compatibility with the earliest PCs, physical 13 # address line 20 is tied low, so that addresses higher than 14 # 1MB wrap around to zero by default. This code undoes this. 15 seta20.1: 16 inb $0x64,%al # Wait for not busy 17 testb $0x2,%al 18 jnz seta20.1 19 movb $0xd1,%al # 0xd1 -> port 0x64 20 outb %al,$0x64 21 seta20.2: 22 inb $0x64,%al # Wait for not busy 23 testb $0x2,%al 24 jnz seta20.2 25 movb $0xdf,%al # 0xdf -> port 0x60 26 outb %al,$0x60

这部分指令就是在准备把CPU的工作模式从实模式转换为保护模式。我们可以看到其中的指令包括inb,outb这样的IO端口命令。所以这些指令都是在对外部设备进行操作。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zyxszw.html