从头开始编写操作系统(4) 第3章:引导加载器
来源:互联网 发布:新网互联域名证书生成 编辑:程序博客网 时间:2024/06/06 04:48
译自:http://www.brokenthorn.com/Resources/OSDev3.html
第3章:引导加载器
by Mike, 2008, 2009
本系列文章旨在向您展示并说明如何从头开发一个操作系统。
介绍
欢迎!这正是您等待的一篇教程,在这一章包括的主题有:
- 引导步骤——它是怎么工作的
- 引导加载器理论
- 开发一个简单的引导加载器
- 使用NASM汇编器汇编引导加载器
- 使用VFD(虚拟磁盘驱动器)软件:创建一个软盘映像
- 使用PartCopy:将引导加载器复制到软盘映像
- 使用Bochs——基本设置和应用:测试引导加载器
准备好了吗?
引导过程
当电源按钮按下时
当我们按下电源按钮是到底发生了什么?当这个按钮被按下后,连接到这个按钮的线缆会向主板发送一个电信号,主板简单的把这个信号转发给电源(PSU)。
这个信号只包含1比特信息。如果是0,表示没电(计算机关闭,主板不活动)。如果是1(活动信号),意味着系统已经加电。
为了更好的理解,记住计算机的基础是二值逻辑。8“比特”仅仅表示8条可以导电的“线缆”,0代表线上没有电流,而1表示线上有电流。这些与逻辑门,一起构成了数字逻辑点了的基础,而在此之上构建的整个计算机。
当PSU收到这个活动信号,它开始向系统的其余部分供电。当所有设备都得到正确数量的供电时,就可以确定PSU会持续向它们供电而不发生大的问题。
PSU会发送一个“供电正常(power_good)”的信号到主板的基本输入输出系统 (BIOS)。
BIOS POST
到那个BIOS接收到“power_good”信号,BIOS开始一个称为POST(Power On Self Test 加电自检)的初始化过程。POST通过测试确保供电正确,设备已安装 (如:键盘、鼠标、USB、串口等),并确保内存状态良好 (通过检测内存损伤)。
POST向BIOS交出控制权。POST将BIOS加载到内存的末尾(可能是0xFFFFF0)并且在内存的第一个字节处放置一个跳转指令。
处理器指令指针 (CS:IP)被设置为0,然后处理器得到控制权。
什么意思呢?处理器会在地址0x0处开始执行指令。这里,它是一条POST程序放置的跳转指令,这条指令跳转到0xFFFFF0 处(或者其他BIOS被加载到的地址),然后处理器开始执行BIOS。
BIOS得到控制权……
BIOS
基本输入输出系统(BIOS)会做一些工作。它创建一个中断向量表(IVT), 并提供基本的中断服务。BIOS然后会做一些检查以确保没有硬件问题。BIOS也提供一个设置的功能。
BIOS需要找到一个操作系统。根据您在BIOS设置中指定的引导顺序,BIOS执行0x19号中断来找出一个可引导设备。
如果没有找到可引导设备 (INT 0x19 返回了),BIOS会尝试引导顺序列表中的下一个设备。如果再没有可供尝试的设备,BIOS会打印一个类似于“操作系统未找到”的信息,并停止系统的运行。
中断与中断向量表 (IVT)
一个中断是可以被许多不同的程序调用的子程序。这些中断被保存在从地址0x0开始的被称为中断向量表的空间中。比如,一个常见的中断INT 0x21被用于DOS系统。
注意:这儿没有DOS!“只有”BIOS设置的中断才有效,没有其他的!使用其他的中断会导致系统执行不存在的程序,这将导致你的系统崩溃。
注意:如果切换处理器模式,IVT会变得无效。这意味着,任何的中断(无论软硬件,包括BIOS)全都无效。对于32位操作系统,我们不得不这样做。
BIOS 0x19中断
INT 0x19——引导程序加载器
通过“热重启”重启系统,不会清空内存,也不会恢复中断向量表。
该中断由BIOS执行。它读入磁盘的第一个扇区(扇区(Sector) 1,磁头(Head) 0, 磁道(Track) 0)。
扇区Sectors
扇区即一个512字节的组,扇区1表示磁盘最前面的512字节数据。
磁头Heads
磁头(或“面”)表示磁盘的一面。磁头0是正面,磁头1是背面. 多数磁盘值由一个面,因此只有一个磁头。
磁道Tracks
为了理解磁道,看下面的图:
图中的磁盘代表硬盘或软盘,我们看到的是磁头0(正面),并且每扇区512字节。磁道是扇区的集合。
注意:记住1扇区是512字节,软盘的1磁道又18扇区,这一点在加载文件时很重要。
如果磁盘可引导,则引导扇会被加载到0x7C00, INT 0x19 会跳转到哪里,将控制权交给一点加载器。
注意:引导加载器会被加载扫0x7C00,这很重要!
注意:有些系统在按下“热重启”按钮,会在地址0x0040:0072处放置一个0x1234 再跳转到0xFFFF:0。冷重启则会用0x0代替。
现在,我们的1337 引导加载器得到控制权!
引导加载器理论
关于引导加载器我们已经看了不少。现在,把其中重要的部分放在一起。
引导加载器是……
- ……与主引导记录(Master Boot Record (MBR))在一起。
- ……在磁盘的第一个扇区。
- ……大小是一个扇区 (512字节)。
- ……已经被BIOS的INT 0x19加载到地址0x7C00处。
如你所想,我们不能在512字节里做很多事情。我们要做什么呢?
在汇编语言中我们很容易超过512字节。尽管代码看起来不错,可是只有一部分在内存中,比如,想想下面的例子:
mov ax, 4ch
inc bx ; 512 byte
mov [var],bx ; 514 byte
在汇编语言中,从上往下执行。但,要记得当向内存加载文件时,以扇区为单位。 每扇区512字节,因此只能复制几个512字节到内存中。
如果只有第一个扇区被加载到内存,我们仅仅复制到第512字节 (inc bx 那一行)。这样最后的mov指令仍在磁盘上,不在内存中!
那当处理器执行完inc bx 之后会做什么呢?处理器会继续执行第514字节。但是我们的代码不在内存中,它会跨过文件的末尾!结果呢?崩溃。
但是,再加载第二(或更多)扇区到指定地址并执行是可能的。这样文件中剩余的数据就会加载到内存中,会工作的很好。
这种方法是可行的,但难以使用。常见的方法是将引导加载器控制在512字节,用来搜索、加载和执行第二段引导加载器。这个我们会在后面看到。
硬件异常Hardware Exceptions
硬件异常与软件异常相似不过它由处理器而不是软件执行。
有时,我们必须避免所有异常的产生。比如,在我们切换处理器状态后,整个中断向量表失效,此时,任何的软硬件中断都会使我们的系统崩溃。我们在后面详细说明。
CLI 和STI 指令
您可以使用STI和CLI指令允许或禁止所有的中断,大部分系统不允许应用程序执行这两条指令,因为这可能会带来大问题(尽管系统可以模拟它们)。
cli ; 禁止中断
; do something...
sti ; 允许中断——我们前面禁止了!
双重错误(Double Fault)的硬件异常
如果处理器在处理异常的时候发现了问题(如,非法指令,除0,等),处理器会执行双重错误处理程序,即0x8中断。
我们在后面会看到一个双重错误。如果处理器在双重错误之后还不能恢复,它会执行一个三重错误(Triple Fault)。
三重错误Triple Fault
前面我们见到过这个条目吗?CPU的三重错误意味着系统重启。
在早期阶段,比如在引导加载过程中,你代码中的错误,会产生一个三重错误。这表明你的代码有问题。
开发一个简单的引导加载器
总算到了我们等的了!
让我们在看看我们的列表:
- 与主引导记录(Master Boot Record (MBR))在一起。
- 在磁盘的第一个扇区。
- 大小是一个扇区 (512字节)。
- 已经被BIOS的INT 0x19加载到地址0x7C00处。
打开任意的文本编辑器(我使用Visual Studio 2005),但Notepad(记事本)就足够了。
这里是引导加载器 (Boot1.asm)...
;*********************************************
; Boot1.asm
; - ASimple Bootloader
;
; OperatingSystems Development Tutorial
;*********************************************
org 0x7c00 ; 我们已经被BIOS加载到 0x7C00
bits 16 ; 我们在16位实模式
Start:
cli ; 禁止中断
hlt ; 系统停机
times 510 - ($-$$) db 0 ;我们得有512字节,将剩余的部分清零
dw 0xAA55 ;引导标志
这些并没有什么令人兴奋的,下面我们一行行分析:
org 0x7c00
记住:BIOS把我们加载到0x7C00,上面的代码告诉NASM 确保相对地址为0x7C00。这表示,第一条指令在0x7C00处
bits 16
还记得第2章吗?在那一章里,我解释了x86系列向后兼容老DOS系统。因为老DOS系统是16位的,所有的x86兼容机引导时为16位模式,也就是:
- 我们受限在1 MB内存。
- 我们受限在16为寄存器。
我们会在后面将计算机切换到32位模式。
times 510 - ($-$$) db 0
我希望这里有文档可以参考。在NASM中,美元符($)表示当前行的地址。$$表示第一条指令的地址(0x7C00)。所以,$-$$ 返回当前行到起点共有多少字节 (这里就是程序的大小)。
dw 0xAA55
这需要一些解释。
BIOS INT 0x19会搜索可引导磁盘。那它怎么知道一个磁盘是否可以引导呢?因为引导标志。如果511字节是0xAA且512字节是0x55,INT 0x19会加载它,并执行引导加载器。
因为引导表示必须是引导扇的最后两个字节。我们使用times 关键字填充到第510个字节,而不是第512个字节。
使用NASM汇编
NASM是命令行汇编器,因此必须通过命令行或批处理脚本执行。汇编Boot1.asm 这么做:
nasm -f bin Boot1.asm -o Boot1.bin
-f选项用于告诉NASM生成哪种类型的文件,这里是二进制文件。
-o 选项由于给出输出文件名,这里是Boot1.bin
汇编之后你会得到一个名为"Boot1.bin"512字节的文件。
注意:因为一些原因Windows文件浏览器会显示文件的大小为1 KB,但查看文件属性时你会发现它确实是512字节。
使用VFD (虚拟软盘驱动器)
我们使用VFD来创建我们的操作系统要保存的虚拟软盘。下面解释如何使用它。
- 打开 vfdwin.exe.
- 在Driver标签下,点击Start按钮,以启动驱动器。
- 点击Drive0或Drive1标签。
- 点击Open
你会看到这个:
确保Media Type(媒体类型)是st和ard3.5" 1.44 MB floppy(标准的3.5" 1.44 MB 软盘),并且类型是RAM。同样的,确保Write Protect(写保护)打开(不选中)。点击 "Create".
到“我的电脑”(在“您”的计算机上)您会见到一个新的软盘驱动器。
在驱动器图标上右击->属性,格式化软盘。在VFD 标签处会有一个格式化选项。
PartCopy——复制引导加载器
好,现在我们有了自己的引导加载器,怎么把它复制到硬盘中呢?你可能知道,Windows不允许我们将文件直接复制到磁盘的第一个扇区上,所以我们用一个命令来完成。
在第1章中我们见到了debug命令,如果你决定使用那个命令,请跳过这一节。
PartCopy是一个命令行出现,它使用下面的语法:
partcopy file first_byte last_byte drive
PartCopy不仅仅用于复制文件,它可以将制定的字节复制到扇区或从扇区复制出来,感谢它的语法(见上面),这是一个安全的方法。
因为你可以模拟软驱,你可以使用驱动器号(如A:)来代表驱动器。
要复制引导驱动器,这么做:
partcopy Boot1.bin 0 200 -f0
f0代表0号软驱。你可以使用f0或f1等,这要根据你的软盘在那个驱动器里。Boot1.bin是我们要复制的文件。从第一个字节(0x0)复制到最后一个字节 (0x200,十进制的512)。注意partcopy只接受16进制的数据。
警告:如果使用不小心,可能会导致磁盘数据损坏。上面的命令值适用于软盘,不要在硬盘上尝试。
Bochs: 测试引导加载器
Bochs是一个32位PC仿真器,我们使用它来调试和测试。
Bochs使用配置文件来描述要仿真的硬件。如下例,是我使用的配置文件:
# ROM 和 VGA BIOSimages ---------------------------------------------
romimage: file=BIOS-bochs-latest, address=0xf0000
vgaromimage: VGABIOS-lgpl-latest
# boot from floppy using our disk image-------------------------------
floppya: 1_44=a:, status=inserted # Boot from drive A
# logging 和reporting -----------------------------------------------
log: OSDev.log # All errors and info logs will output to OSDev.log
error: action=report
info: action=report
配置文件使用#注释。它试图从一个在驱动器A中的软盘引导。
ROM BIOS和VGA BIOS映像文件是和Bochs一起的,所以别为它担心。
定位BIOS ROM
配置文件中的大部分都很简单。有一行需要再看看:
romimage: file=BIOS-bochs-latest, address=0xf0000
这行告诉Bochs把BIOS放到内存的什么位置。要知道BIOS的大小是可变的,BIOS必须放在1MB的末尾,即BIOS的最后一个字节必须在0xFFFFF。
因此你可能需要改变BIOS的位置。这可以通过获得BIOS映像的大小(它在Bochs文件夹下的BIOS-bochs-latest)。这个大小以字节为单位。
这样从0xFFFFF减去BIOS文件的大小(以字节为单位)。这就是新的BIOS地址,更新这一行的address,把BIOS移到一个新位置。
你可能不需要这一步。如果你被告知“BIOS必须在0xFFFFF结束”时,你就要这么做了。
如何使用Bochs
使用Bochs:
- 执行bochs.exe
- 选择option 2 (Read options form);按回车。
- 输入配置文件名 (我们上面创建的那个); 回车。
- 你会返回到主菜单。选option 5:Begin Simulation(开始仿真),回车。
一个新的窗口会打开,你会看到:
如果Bochs退出并重启了
……你有了一个三重错误的经历。返回到代码,找找哪里出了错。如果你需要帮助,联系我吧。
如果窗口出现,但什么也没发生
恭喜!这是我们的cli和hlt指令使系统停止了,我们的引导加载器在执行了。
构建步骤——总结
和我们在前一章里提到的构建步骤相比较,一旦你跟着做了,你会发现这很简单。
从此往后,我们将步骤详细重复这个构建步骤。
下次见
- 从头开始编写操作系统(4) 第3章:引导加载器
- 从头开始编写操作系统(5) 第4章:引导加载器2
- 从头开始编写操作系统(7) 第6章:引导加载器4
- 从头开始编写操作系统(6) 第5章:引导加载器3
- 从头开始编写操作系统(3) 第2章:基本理论
- 从头开始编写操作系统(1) 第0章:序章
- 从头开始编写操作系统(2) 第1章:介绍
- 从头开始编写操作系统(8) 第7章:系统结构
- 从头开始编写操作系统(9) 第8章:保护模式
- 从头开始编写操作系统(10) 第9章:开启A20
- 从头开始编写操作系统(11) 第10章:为内核做准备1
- 从头开始编写操作系统
- 【从头开始写操作系统系列】实现一个 GDT(3)
- 【从头开始写操作系统系列】实现一个-GDT(1)
- 【从头开始写操作系统系列】实现一个-GDT(2)
- 操作系统编写之引导扇区
- 开始学习编写操作系统
- 操作系统实践(1)——从引导开始
- Master Note- How to diagnose Database Performance - FAQ [ID 402983.1]
- C# 实现保留两位小数的方法
- 关于jquery插件
- mate 虚拟机
- C/S(client/server )客户服务器模式 B/S(browser/server)浏览器服务器模式
- 从头开始编写操作系统(4) 第3章:引导加载器
- 一道经典IBM面试题 自解
- C#中写Excell
- Word/WPS中页码从指定的页面开始插入方法
- matlab中的数据类型和显示精度
- Android开发环境搭建全程演示(jdk+eclip+android sdk)
- IO 输入与输出(3) -- 节点流之五ByteArrayInputStream和ByteArrayOutputStream类
- 2011 3月微博
- Acm 母函数