译:JamesM的内核开发教程
1.环境配置
我们需要一个基础环境来设计开发我们的内核,在本教程中,我假设您使用的是*nix操作系统和GNU工具集。如果您使用的是Windows操作系统,您必须使用诸如cygwin或DJGPP这类*nux模拟环境。即便如此,本教程中的生成文件和命令仍然可能会出错。
1.1目录结构
我的目录布局如下:
tutorial
|
+-- src
|
+-- docs
所有的源文件都放入src中,所有的文档都放入docs中(平时开发你写文档吗?)
1.2编译
教程里的所有例子都已经通过GNU工具集成功编译 (gcc, ld, gas, etc),所有样例代码都是用intel风格汇编书写的,因为我个人认为,使用GNU时,intel风格汇编的可读性比AT&T风格汇编的要好很多。我们要使用NASM来汇编程序。
本教程并不是一个内核引导教程,我们使用GRUB来加载内核。为此,我们需要让GRUB预载一个软驱映像。有很多教程可以指导我们使用GRUB,更可喜的是,你可以在我这里找到我做的一个标准软驱映像,把它放在你的教程目录下吧。
1.3运行
什么都不能替代在真机上进行内核测试,但不幸的是,真机的运行结果无法告诉你到底哪里错了(当然,你可能第一次就写出了没有问题的代码,不是吗?)。使用Bochs吧,他是一个开源的兼容32位及64位的虚拟机。当你的程序出错时,Bochs会通知你,并把一些有用的寄存器状态保存到日志中。另外,Bochs比真机启动的快很多,我的所有例子都可以在Bochs上成功运行。
1.4Bochs
为了运行Bochs,我们需要一个Bochs配置文件(bochsrc.txt),凑巧,下面有一个配置例子。
一定要注意这些BIOS文件的顺序,These seem to change between installations(不同版本可能会有不同???)。如果你用源代码直接编译出Bochs,很可能你没有这些文件。Google一下文件名,并从官网站上下载。
megs: 32
romimage: file=/usr/share/bochs/BIOS-bochs-latest, address=0xf0000
vgaromimage: /usr/share/bochs/VGABIOS-elpin-2.40
floppya: 1_44=/dev/loop0, status=inserted
boot: a
log: bochsout.txt
mouse: enabled=0
clock: sync=realtime
cpu: ips=500000
以上设置使Bochs虚拟出一个32M内存,350MHz P2的CPU。每秒都会刷过很多信息——但我喜欢一个慢速的虚拟机,原因很简单,这样我可以看清很多文字在滚动。
1.5 使用脚本
我们将要频繁的做一些事——编译和连接我们的项目,把生成的二进制内核写入软驱镜像。
1.5.1 生成脚本
# The C and C++ rules are already setup by default.
# The only one that needs changing is the assembler
# rule, as we use nasm instead of GNU as.
SOURCES=boot.o
CFLAGS=
LDFLAGS=-Tlink.ld
ASFLAGS=-felf
all: $(SOURCES) link
clean:
» -rm *.o kernel
link:
» ld $(LDFLAGS) -o kernel $(SOURCES)
.s.o:
» nasm $(ASFLAGS) $<
这段生成脚本将编译SOURCES中的每个文件,并把他们连接在一起生成一个二进制内核。当然,做这些需要一个连接脚本,下面所说的link.ld就是做这个的。
1.5.2 link.ld
/* Correct place. */
/* Original file taken from Bran's Kernel Development */
/* tutorials: http://www.osdever.net/bkerndev/index.php. */
ENTRY(start)
SECTIONS
{
.text 0x100000 :
{
code = .; _code = .; __code = .;
*(.text)
. = ALIGN(4096);
}
.data :
{
data = .; _data = .; __data = .;
*(.data)
*(.rodata)
. = ALIGN(4096);
}
.bss :
{
bss = .; _bss = .; __bss = .;
*(.bss)
. = ALIGN(4096);
}
end = .; _end = .; __end = .;
}
这段脚本告诉LD如何建立内核映像。首先,它告诉LD开始的位置应该在start符号的位置。之后,他告诉LD,.text (你的代码所在)将从0x100000开始执行。之后执行.data段和.bss段,这两项都是page-aligned (ALIGN(4096)),Linux GCC也增加了一个额外的数据段:fodata,这个只是用来初始化,像常数一样。为了简单起见,我们捆绑使用他们。