如何写一个bootloader

声明:本文为学习Codeproject文章的个人总结性文章,

    原文:http://www.codeproject.com/Articles/664165/Writing-a-boot-loader-in-Assembly-and-C-Part

 

本人开发环境:

  操作系统:Ubuntu 32位(64位的会有pushl等指令的不能执行等问题,最好为32位)

  工具:as ld dd bochs

  语言:at&t 16位汇编

 

计算机启动运行于real mode,ROM会读取硬盘(或其他介质,如软盘)的CHS模式的0柱面,0磁道,1扇区的的数据到内存0x7c00处,然后到此处执行。所以bootloader就是一段代码,将这段代码写入0柱面,0磁道,1扇区中。

好了,原理简单介绍完毕。

 

我的当前用户目录是/home/chao/,所以我要在~/Documents/目录下来写代码和进行其他的操作。

创建test.S文件

 1 .code16                    
 2 .text                        
 3      .global _start;
 4 _start:                    
 5 
 6      movb $'X' , %al
 7      movb $0x0e, %ah
 8      int  $0x10
 9 
10      . = _start + 510
11      .byte 0x55
12      .byte 0xaa

解释一下代码的意义。

1     movb $'X' , %al
2        movb $0x0e, %ah
3        int  $0x10

这是call BIOS interpret,调用号为0x10,查阅资料得知,0x10是Video Service,根据AH中的参数来调用不同的程序,这里AH中是0x0e,功能为Write Character in TTY Mode,也就是向终端写入字符,写入的字符从AL中获取,也就是字符X。

1 . = _start + 510
2       .byte 0x55
3       .byte 0xaa

因为一个有效的启动扇区最后的两个字节内容必须是0x55,0xaa(这是延续下来的,如果不是这两个字节内容,那么这个启动扇区会被认为是无效的,不能启动,所以这两个字节我把它称为验证字节),所以会有地2,3行内容,至于. = _start + 510,这里的 . 代表当前位置,也就是说,把当前位置设置为从代码开始增加510 bytes的位置,因为一个扇区大小为512 bytes(以前也有别的大小,但是后来512成为主流),所以两个字节的大小留给验证字节。

 

至此,我们的demo  bootloader代码就写好了,下面进行汇编,链接。

  • as test.S -o test.o
  • ld –Ttext 0x7c00 --oformat=binary test.o –o test.bin

-Ttext 0x7c00 告诉linker你想把代码加载到内存0x7c00处(至于为什么是这个地方,可以百度,很有意思),我们生成的是test.bin,也就是二进制文件,可以直接执行。

好了,程序有了,还需要把它写入存储介质的启动扇区,那我们就来创建一个。

  • dd if=/dev/zero of=floppy.img bs=512 count=2880
  • dd if=test.bin of=floppy.img

我们创建了一个512 bytes的img文件,然后把我们的程序写入。

现在/home/chao/Documents/目录下面应该是这个样子的

如何写一个bootloader

 

好了,启动设备已经就绪,我们还需要测试下它行不行,那就用到bochs了,它是一个虚拟机软件,

安装命令:

sudo apt-get install bochs bochs-sdl

有的地方说安装bochs-x,但是会出现问题,保险起见还是用bochs-sdl.

现在我们为bochs写一个配置文件

在/home/chao/Documents/目录下创建bochsrc.txt

1 megs: 32
2 #romimage: file=/usr/share/bochs/BIOS-bochs-latest, address=0xf0000
3 #vgaromimage: /usr/share/bochs/VGABIOS-lgpl-latest
4 floppya: 1_44=floppy.img, status=inserted
5 boot: a
6 log: bochsout.txt
7 mouse: enabled=0
8 display_library: sdl

注意:2,3行中的路径可能不同,根据自己的系统查找BIOS-bochs-latest和VGABIOS-lgpl-latest(也可能是其它的而不是VGA,根据自己的情况设置)。

为了方便,可以创建一个build.sh脚本

 

1 as test.S -o test.o
2 ld -Ttext 0x7c00 --oformat=binary test.o -o test.bin
3 dd if=/dev/zero of=floppy.img bs=512 count=2880
4 dd if=test.bin of=floppy.img

 

如果把创建img文件的步骤放入脚本中,那么/home/chao/Documents/目录下现在有3个文件

 

如何写一个bootloader

 

 

打开终端,切换到此目录,执行build.sh,然后所需要的文件都有了

如何写一个bootloader

然后执行命令

bochs

可以看到在bochs中显示字符 X

如何写一个bootloader

至此,一个demo bootloader就写完了。

这段代码并没有干什么事情,只是解释了如何在计算机启动时执行我们的代码,真正的bootloader会加载内核程序(或者加载其他的程序,通过其他的程序来加载内核)。