前言
用通用的GRUB/GRUB2来引导操作系统,可以跳过编写boot loader的步骤,达到简化编程的目的。还可以使得操作系统通用,不用烧写U盘等操作,只需要添加对Multiboot的支持即可。从上电到BIOS,再到搬移kernel.bin到1M地址等操作可以参阅作者的书籍。
说明
本次编译的东西只是基础deamon版本,并未支持64位环境。编译所用的都是32位elf文件,multiboot对32位elf支持较好。后面再记录引导64位OS的方法。
一、选择GRUB版本
要想使用GURB/GURB2引导系统,得遵循GURB的Multiboot/Multiboot2
的规范(specification)。查阅了官方文档Multiboot和Multiboot2之后,发现GRUB2版本设计的版本功能更强大,支持直接到IA-32
模式,对于学习操作系统来说,这部分工作还是手动实现,能学到更多;还支持UEFI规范的一些操作,为了减轻复杂性,暂时选择Multiboot规范(legacy)。
二、如何启动自己的elf
grub2中直接提供了multiboot和multiboot2命令,可分别用于引导符合multiboot v1规范和multiboot v2规范的内核。下面做个示例:
menuentry 'grub test'--class gnu --class os {
load_video
insmod gzio
# insmod part_msdos
# insmod xfs
# set root='hd0,msdos1'
echo 'loading kernel.elf'
multiboot /kernel.elf
}
Note: #注释的部分,每个主机都不同,具体多少可以参考系统中其它menuentry。
二、Multiboot Specification
对于GRUB这种通用的boot loader来说,与OS之间交互的主要设计实现接口有三,如下:
- The format of an OS image as seen by a boot loader.
- The state of a machine when a boot loader starts an operating system.
- The format of information passed by a boot loader to an operating system.
下面只记录最关键的部分,官方文档中对数据结构的定义做了很多说明,此处不再累述。详细信息查阅官方手册Multiboot。
三、编写程序
官网所给的例程比较详细的说明了如何让自己的OS兼容Multiboot Specification,可以先理解,再拿来使用,测试。具体内容参见官方的:
4.3 Example OS code
四、链接脚本
下面给个简单示例,可自由发挥:
OUTPUT_FORMAT("elf32-i386")
OUTPUT_ARCH(i386)
ENTRY(_start)
SCTIONS
{
. = 0x00100000;
.text ALIGN (0x1000) :
{
*(.text)
}
.rodata ALIGN (0x1000) :
{
*(.rodata*)
}
.data ALIGN (0x1000) :
{
*(.data)
}
.bss :
{
sbss = .;
*(COMMON)
*(.bss)
ebss = .;
}
}
五、编译
笔者曾经尝试过很多中办法,因为grub老是提示无法找到Header,要么就是Magic Number不对,尝试过很多办法都无解。后来搜索和gcc编译相关的资料,发现了可能是编译参数未指定,导致编译出来的无法被grub识别。下面给出测试过的可以通过multiboot引导的编译参数:
gcc -m32 -march=i386 -I. -Wall -Wextra -fno-builtin -nostdlib -nostartfiles -nodefaultlibs ...
ld -m elf_i386 ...
Note: 下面对几个重要的参数做说明
参数 | 含义 |
---|---|
-nostartfiles | 指定入口函数 |
-nodefaultlibs | 不使用默认库文件 |
-nostdlib | 不使用标准库函数 |
fno-builtin | 不使用gcc的内建函数 |
六、结果
本次在虚拟机中模拟multiboot环境,可以使用,最后显示一条45°的斜线(cmain函数中最后一个功能),效果如下图:
效果图
网友评论