前段时间学了一点点关于操作系统的东西,跟着一本分析Linux 0.11 内核代码的书学习的,刚开始的时候,书中讲了关于编写引导区的东西,于是跟着书本上的内容进行实践,中间遇到了很多问题,不过最后还是一点一点解决了,于是打算记下来。
首先先说说引导区,当然指的是最传统的引导方式,不是新的efi方式啦。它是通过bios将驱动器中前512个字节的数据加载到内存当中,然后进行调用进行引导。
当然因为学识有限,先将自己知道的东西浅显的讲一下吧。在计算机刚上电的时候,处理器应该是初始化的状态,其代码指针会指向BIOS ROM所在的位置,通常是处理器可读内存的最高位之前的64KB。接下来BIOS会将其代码段复制到内存最开始1MB的后64KB当中,然后跳转到这个位置并将处理器调整进入实地址模式,初始化各个外设,等BIOS所有的工作完成之后,它会从硬盘或者其他的可以用来启动的存储设备上将其最前边的512字节加载到内存的0x7C00处,这也就是常说的7C00h或者7C00,我们可以认为,从这里开始,就是执行操作系统代码的最开始的地方。而经常听到的55AA则是这512字节的最后两个字节,只有最后两个字节为55AABIOS才会认为这段代码是正常可加载的。当然关于为什么是55AA,我也是不知道的,我在网上看到很多关于这个问题的讨论,说最开始是IBM公司定下的,也有人说是因为它好检测,也有人说它有一位错了很容易发现,真的没有人觉得有可能是最开始制定这个标准的工程师是一个像我这样逗比的人么?要是我的话我就弄成3838。别问我为什么。
接下来呢就是我们可以发挥想象的地方了,也就是说接下来我们可以对这个地方做手脚,想做什么就做什么,因为既然找到了操作系统的最开始的地方,我们也就有方法自己去修改它。
首先因为前面提到,BIOS在这里进入了实地址模式所以我们就可以参照Intel汇编的实地址编程方法。
以下为一段示例代码,其功能是在屏幕上显示一个字符串,并且实现将键盘输入显示到屏幕:
(双击代码区域复制)
.model small .code org 7c00h jmp start start: mov ax,0 mov ss,ax mov sp,7c00h mov ds,ax mov es,ax ;初始化各个寄存器 mov si, offset msg ;设置字符串 mov al,[si] mov cx,35 ;设置字符串长度 mov dx,1000h ;设置DH从屏幕起始行,DL从屏幕起始列。 mov bx,000ch ;设置BH视频页,BL属性值 mov bp,msg ;设置偏移地址 mov ax,1301h ;设置为显示字符串功能 int 10h ;调用BIOS的10h功能 mov ah, 02h ;设置复位光标功能 mov dl, 00h ;复位到0列 mov dh, 00h ;复位到0行 int 10h putloop: mov ah, 10h ;设置读取键盘缓冲区 int 16h cmp al, 0dh ;判断是否为回车 je enterr mov ah, 09h ;不是回车则继续显示 mov bh, 00h mov bl, 71h ;设置字的颜色 mov cx, 01h int 10h mov ah, 03h mov bh, 00h ;显示从键盘读入的字符 int 10h mov ah, 02h add dl, 01h ;光标右移 int 10h jmp putloop enterr: ;是回车 mov ah, 03h mov bh, 00h int 10h mov ah, 02h ;光标换行 mov dl, 00h add dh, 01h int 10h jmp putloop finish: hlt jmp finish msg: db 0dh,0ah db "This is my boot, by Tifer King!" db 0dh,0ah db 00h org start+200h-2 boot_signature: db 055h,0aah ;引导签名55AA end
接下来就是编译这段代码,这可费了番周折,手头上有的汇编编译器是VS2015自带的MASM14.0,在网上看到很多人都说从MASM6.0以后就不能用来编译引导区了,需要下载MASM5.0版本,但是我觉得这有些荒诞,于是爬了很多帖,最后发现其实可以编译的。
打开VS2015的x86工具命令提示符,当然其实也可以直接打开cmd,不过需要自己手动添加masm的path就比较麻烦,而用VS2015命令行工具的好处就在于不用自己设置。然后将上述代码保存到boot.asm文件里边,然后cd到文件所在目录运行:
ml /omf boot.asm
然后就会生成一个boot.obj文件,当然这里链接就会出现问题,可能半天链接不上,没有关系,下载link16.exe,然后按照提示输入obj还有runfile,剩下的不用理会。
将生成的文件用winhex打开,然后将文件最后的512字节复制到硬盘的最开始。当然建议最好不要用自己的硬盘试,会丢失自己硬盘上的数据,因为相当于重建了mbr表。我是将其写入了虚拟机的虚拟硬盘当中运行。
运行效果:
(完)