GNU GRUB

GNU GRUB(GRand Unified Bootloader, GRUB) 是一个来自GNU项目的多操作系统启动程序。GRUB是多启动规范的实现,它允许用户可以在计算机内同时拥有多个操作系统,并在计算机启动时选择希望运行的操作系统。
使用GRUB引导操作系统的过程为:

image.png

  1. BIOS转向第1块硬盘的第1个扇区,即 主引导记录(MBR)

BIOS系统存储于主板的ROM芯片上,计算机开机时,先读取该系统,然后进行加电自检。这个过程中检查CPU和内存、计算机基本的组成单元(控制器、运算器和存储器),以及检查其他硬件,若没有异常就开始加载BIOS程序到内存当中.

  1. MBR中存储了BootLoader信息,BootLoader将加载GRUB;
  2. MBR的工作是查找并加载第二段BootLoader程序。但在系统没启动时,MBR无法识别文件系统,因此需要在这一步加载GRUB。
  3. GRUB查找并加载kernel;GRUB识别文件系统,根据/boot/grub/grub.conf文件查找Kernel信息并加载Kernel程序。当Kernel程序被检测并加载到内存中,GRUB就将控制权交接给Kernel程序。
  4. kernel装载驱动,挂载ROOTFS,执行/sbin/init;
  5. init初始化os,执行runlevel相关程序。

(现代操作系统使用的UEFI启动)

使用Multiboot规范编写loader.s

BootLoader是一段汇编代码,文件名为loader.s,它需要按照Multiboot规范来编译内核才可以被GRUB引导。
按照Mutileboot规范,内核必须在起始的8KB中的包含一个多引导项头(Multiboot header),里面必须包含3个4字节对齐的块:这个多引导项头里面必须有3个4字节对齐的块。

一个魔术块:包含了魔数[0x1BADB002],是多引导项头结构的定义值。
一个标志块:我们不关心这个块的内容,我们简单设定为0。
一个校检块:校检块,魔术块和标志块的数值的总和必须是0。

我们在loader.s中定义他们
image.png

.set MAGIC, 0x1badb002;                 # 魔数块
.set FLAGS, (1<<0 | 1<<1);              # 标志块<br />.set CHECKSUM, -(MAGIC + FLAGS);        # 校验块

下面的伪指令声明了Multiboot标准中的多引导项头
三个块都是32位字段

.section .multiboot
.long MAGIC//long即是4字节
.long FLAGS
.long CHECKSUM

在多引导项头之后,是程序的入口点。kernel的代码在文件kernel.cpp中,loader.s在入口点中跳转到kernel.cpp的函数中执行。首先需要使用.global伪指令告诉链接器程序的入口点,用loader表示,最后是stop代码。

kernel.cpp中主函数的名称是kernelMain,需要传入两个参数,分别是BootLoader的地址和魔数,它们存放于寄存器%eax和%ebx中,将它们压栈以传递参数。kernelMain是一个外部符号,需要提前在loader.s中声明,这些外部符号存在于.text段中。同样地,为了使得loader函数对外部可见,使用.global伪指令向外暴露loader。

.section .multiboot
    # ...
    .long CHECKSUM

.section .text
.extern kernelMain
.global loader

loader:
    push %eax       # bootloader's address in %eax
    push %ebx       # magic number in %ebx
    call kernelMain

stop:
    # 禁用中断
    cli
    # 禁用中断后使用hlt暂停CPU,以后无法再唤醒
    hlt
    jmp stop

标签: none

评论已关闭