前期工作
在此之前,笔者已经大致掌握了如何创建一个能boot的Floppy Disk Image。笔者的启动镜像内的目录结构参考了James的bootloader的目录结构。
因为笔者用Mac开发,所以对应的update_image.sh修改为如下(接受一个参数作为编译后的kernel地址):
#!/bin/bash
hdiutil attach -mountpoint boot_folder boot.img
cp $1 boot_folder/
hdiutil detach boot_folder
探索过程及最后解决方案
- 【失败】以James的Genesis教程为例做为出发点
问题:编译失败。
main.c:4:17: warning: declaration of 'struct multiboot' will not be visible outside of this function [-Wvisibility]
int main(struct multiboot *mboot_ptr)
^
main.c:4:5: error: first parameter of 'main' (argument count) must be of type 'int'
int main(struct multiboot *mboot_ptr)
^
1 warning and 1 error generated.
make: *** [main.o] Error 1
在寻找解决方案的过程中,慢慢发现osdev.org的强大之处:其教程比较贴近目前的软硬件水平,能找到很多问题的解决方案。其中有一篇资料详细地解释了James教程的问题。
- 【成功】Bare Bones
和教程不同的是,笔者仍然使用floppy disk image作为启动镜像
源码笔记
Bare Bones教程中的注释十分详细,建议读者仔细阅读。
笔者此部分的练习代码将以Bare Bones教程为基础,进行简单的定制。下文是代码的简要总结:
最重要的说明:
grub在加载完我们的内核后进入文本模式(text mode),当然你也可以设置其它模式(参考文档)。
文本模式下,我们只需要简单地将需要显示的字符串(只支持ascii)写入0xB8000作为起始地址的一段缓冲区中。缓冲区大小为(85列x20行),而缓冲区中的每个单位是一个用16bit表示的带有颜色配置的字符。其中高8位为需要显示的字符,低8位中的高4位为前景色、低4位为背景色。值得一提的是,我们需要自己实现控制字符(如\t,\n等)对应的逻辑。
源码地址(目前是一个private的git repository,计划完成所有练习后再made public。)
boot.s
目的:完成C内核所不能完成的操作,包括但不限于对文件格式的操作。具体的指令可在此文档中查找相应说明。
为什么boot.s中操作这么少?
boot.s并没有担当bootloader的角色。bootloader的任务由grub完成。
kernel.c
只是简单地在屏幕打印一句“Hello\tWorld\n”。
util.c
目前只要一个strlen()函数。
vga.c
屏幕显示相关的功能。主要增加了scroll()、clear()两个函数,以及对特殊的控制符的支持(制表符和换行符等)。
link.ld
linker脚本