这篇文章记录操作系统启动引导过程
80386开始,cpu有三种工作方式:实模式,保护模式和虚拟8086模式。实模式是早起intel cpu(80286及之前)的工作模式,20根地址线,可访问内存为1MB。没有内存保护和多任务等概念。当前系统都不在工作实模式下,但是开机时还是需要通过实模式加载和引导到保护模式的(因为开机启动时执行的BIOS指令是16位模式,工作在实模式下)。
- cpu引脚中有一个是RESET,每次加电,处理器都会执行一个硬件初始化,将内部所有寄存器内容初始化到一个预置状态。对于Intel 8086,设置cs:ip为0xffff:0000,其他寄存器全为0,根据下面的实模式内存布局图可以看到该内存区域为BIOS入口地址(在Intel 8086中,BIOS ROM占据着整个内存空间顶端的64KB,物理地址范围是0xf0000~0xfffff), BIOS ROM中在物理地址0xffff0的地方,一般是一个跳转指令,比如
jmp 0xf000:0xe05b
,在这里,BIOS将执行一些工作,例如硬件的诊断、检测、和初始化,让硬件处于一个正常的默认的工作状态,最后要做的一件事情是从外存储设备读取数据进行加载,具体内容:从设置的系统引导设备顺序一一检查每个盘第一个扇区(512字节)的最后两个字节是否是0x55aa,如果是,则认定是一个启动区,否则继续检查下一个引导设备的第一个扇区,直到找到这样一个扇区为止。找到这样一个扇区后,中断程序将对应的512个字节数据拷贝到地址为0x7c00处(不纠结这个为啥0x7c00,历史就这么约定的),然后将对应的cs:ip 设置为 0x0000:7c00,注意在执行主引导记录程序时cs是0x0000,不是0x07c0,因此再编写汇编时,段起始地址是0。
实模式下内存布局
起始地址 | 结束地址 | 大小 | 用途 |
---|---|---|---|
FFFF0 | FFFFF | 16B | BIOS入口地址,此地址也属于BIOS区域 |
F0000 | FFFEF | 64KB-16B | BIOS区域 |
C8000 | EFFFF | 160KB | 映射硬件适配器的ROM或内存映射式I/O |
C0000 | C7FFF | 32KB | 显示器适配BIOS |
B8000 | BFFFF | 32KB | 用于文本模式显示适配器 |
B0000 | B7FFF | 32KB | 用于黑白显示器适配器 |
A0000 | AFFFF | 64KB | 用于彩色显示器适配器 |
9FC00 | 9FFFF | 1KB | EBDA,扩展BIOS区域 |
07E00 | 9FBFF | 约608KB | 可用区域 |
07C00 | 07DFF | 512B | MBR被BIOS加载到此处 |
00500 | 07BFF | 约30KB | 可用区域 |
00400 | 004FF | 256B | BIOS Data Area (BIOS数据区) |
00000 | 003FF | 1KB | interrupt Vector Table(中断向量表) |
- 步骤1中设置cs:ip后,接下来cpu就应该从0x7c00处执行代码,此部分代码数据就是我们在镜像中对应的前512个字节数据,这512个字节我们称之为MBR扇区,一般在MBR中实现操作系统代码的加载(完成操作系统代码从镜像文件到操作系统的拷贝)。在我们最开始的时候,我们只是在第一个扇区中执行了打印字符串功能(BIOS提供的中断程序能力)。
- 在MBR扇区中,执行数据拷贝,将镜像文件中的操作系统数据拷贝到内存中,然后再设置cs:ip,跳转到对应的操作系统代码起始点,此时进入操作系统代码执行
- 汇编语言中,关于标号不得不说的事情 在写主引导区程序时,关于标号,我常常会陷入迷惑中,不知道标号代表的是该指令对应的段地址,还是偏移地址,该偏移地址又是指啥 首先可以确定的是,肯定不是段地址,段地址对应了一个很大的范围,不能精确定位到某条指令; 其次该指令确实是代表的偏移地址,但是该偏移地址是多少就要分两种情况了:
- 假如在程序头部声明了org 标号,指明了程序被装在到内存中的地址,那么标号代表的地址就是该指令的地址-第一个指令的地址+org表示的其实地址
- 如果程序没有声明org标号,那么标号代表的地址就是该指令的地址-第一个指令的地址
- 由4引发的对$,$$符号的思考