质量最好的国产手办:从头开始编写操作系统(4) 第3章:引导加载器 - xiaoxiaoyaya的专栏 - C...

来源:百度文库 编辑:九乡新闻网 时间:2024/07/07 14:07:05
  从头开始编写操作系统(4) 第3章:引导加载器 收藏
译自: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 ;              - A Simple Bootloader ; ;       Operating Systems 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 和ard 3.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 BIOS images ---------------------------------------------   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 指令使系统停止了,我们的引导加载器在执行了。 构建步骤——总结 和我们在前一章里提到的构建步骤相比较,一旦你跟着做了,你会发现这很简单。 从此往后,我们将步骤详细重复这个构建步骤。 下次见  本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/xiaoxiaoyaya/archive/2011/04/13/6321590.aspx
从头开始编写操作系统(4) 第3章:引导加载器 - xiaoxiaoyaya的专栏 - C... 从头开始编写操作系统(5) 第4章:引导加载器2 - xiaoxiaoyaya的专栏 - ... 从头开始编写操作系统(6) 第5章:引导加载器3 - xiaoxiaoyaya的专栏 - ... 从头开始编写操作系统(3) 第2章:基本理论 - xiaoxiaoyaya的专栏 - CS... 从头开始编写操作系统(2) 第1章:介绍 - xiaoxiaoyaya的专栏 - CSDN... 使用VB6编写COM加载项(方法一:AddinInstance) 女人的美丽从头开始 使用c++开发excel插件(第4章编写一个完整的xll) J2EE项目代码编写规范 - fbtdjs的专栏 - CSDN博客 微软操作系统最核心开发故事第4章:死胡同 保健从头开始 强身始于足下3 Eclipse 插件安装方法和插件加载失败解决办法 - TATA的专栏 - CSDN博客 Drupal专业开发指南 第2章 创建一个模块(1) - g089h515r806的专栏 - CSDNBlog 怎样才能拍出好的摄影作品 (1)从头开始 (原创) 怎样手动删除C盘内的垃圾文件 - 操作系统 Photoshop从头开始 数码摄影从头开始 健康从头开始 C#处理文本文件的常用操作(转) - sluggard的专栏 - CSDN博客 C 中Reference与指针(Pointer)的使用对比 - wu928320442的专栏 - CSDN博客 C2连续的三次B样条插值(c++) - coolend的专栏 - CSDN博客 [转载]从头开始写毛爷爷的故事 从头开始锻炼意志力(1)–选择你的目标 编写超级可读代码的15个最佳实践 - 蒋宇捷的专栏 - CSDN博客