本回我们进行一次实验性的实操环节,机器上电运行相应BIOS代码,然后BIOS加载硬盘的MBR分区内容,并执行MBR代码。本次实验使用Bochs虚拟机模拟整个x86架构的真实机器。实验过程中我们需要为Bochs虚拟机创建一块虚拟硬盘,实验中所说的加载硬盘MBR分区也就是加载该虚拟机硬盘上的MBR分区。
1.首先使用Bochs虚拟机自带的工具bximage创建一块虚拟硬盘YT_OS_DISK.img,该工具比较强大,可以创建多种格式的虚拟硬盘,可以被VMware、VirtualBox等虚拟平台识别。
2. 其次需要把编写好的MBR代码写进入虚拟硬盘YT_OS_DISK.img的MBR分区,因为创建虚拟硬盘默认分区大小是512字节,所以MBR代码写入YT_OS_DISK.img前512字节。如下图所示使用dd命令写硬盘,mbr.bin为MBR源代码mbr.S编译出来的二进制文件,mbr.S源代码内容讲解和编译放在下面分析。
3.最后启动Bochs虚拟机,BIOS会加载该虚拟硬盘的MBR分区,MBR分区代码执行结果如下图所示。可能有些同学仅仅看这个输出觉得没有什么,就是打一个字符串而已,但是这和你平时所写的应用程序输出字符串有很大的区别。这个输出是计算机启动阶段进行的输出,是由BIOS加载MBR代码后进行的输出。此时计算机都还处于启动早期阶段,操作系统都还没加载进内存,不是类似C语言中的“printf”输出机制哦!
本回实验的mbr.bin是裸二进制程序,不是ELF等应用程序格式。mbr.bin的源程序为汇编代码mbr.S,主要分为三部分,第一部分设置实模式下的各段寄存器基地址;第二部分调用BIOS提供的中断功能清理当前屏幕内容;第三部分直接操作显存进行字符串的输出。
实模式下设置各段寄存器的段基地址如下图所示,vstart告诉编译器,整个mbr的内存编址是从0x7c00开始,因为mbr.bin会被BIOS加载到物理内存0x7c00处执行。本实验的显卡为文本模式,段寄存器为显卡映射到内存的段基地址0xb800,我们只要往该段内存写入相应的字符,显示器就会显示对应的字符,具体硬件层面的原因,就需要更深入了解了。
为了避免其它输出到屏幕的信息影响我们的判断,现调用BIOS提供的功能进行屏幕的清空。
接下来,就需要往显存内存段写入我们想要输出的字符,一个字符的输出需要占用两个字节,第一个字节为显示字符,第二个字节为字符的属性,如前景颜色、背景色,是否闪烁等。
真实环境中的MBR的运行本质也就类似这样,只不过它实际的功能是扫描活动分区,然后活动分区中的Boot loader,Boot loader去加载操作系统内核。下一回我们就继续完善MBR,让它去加载一个简易的Boot loader来演示整个过程。
注
1. mbr.S编译成二进制可执行程序mbr.bin使用NASM汇编编译器,具体的命令如下所示:
2. 现代计算机有很多已经支持UEFI启动,UEFI的启动方式与BIOS有所不同,感兴趣的同学可以作为扩展了解。
======================================================================
各位看官如果对本系列有兴趣,大家一起学习交流,可以加一下该系列微信公众号,鼓励继续写的动力。声明此公众号是个人申请用于交流学习底层技术,不会涉及其他商业行为。
======================================================================