将内核加载到内存中 - 如何自己编写加载程序?

时间:2011-06-19 21:32:39

标签: kernel bootstrapping bootloader portable-executable

我正在努力在D中制作自己的启动加载程序和内核,而且我遇到了一个绊脚石。

背景

  • 我从头开始写一切。因此引导扇区处于组装状态。而且我使用GRUB。
  • 我正在使用Qemu进行测试。
  • 引导扇区将内核从“磁盘”(当前只是一个平面二进制文件,其第一个扇区是引导加载程序,其余部分是内核代码)读入虚拟地址0xC0000000,并调用{{ 1}},我内核的入口点。
  • 我正在为我的内核使用 PE文件格式。 (请不要告诉我使用Elf - 我的选择是PE。)

问题

能够加载PE文件是内核工作的一部分。那么我如何首先将内核本身加载到内存中,以便它可以实际正确执行?

我无法从引导扇区执行此操作,因为(1)它不适合512字节,(2)在汇编时执行痛苦。显然,我也无法在内核中做到这一点。那我该怎么做呢?

1 个答案:

答案 0 :(得分:8)

GRUB如何做到这一点?

在GRUB中,512字节引导扇区不加载内核。相反,它加载引导加载程序的其余部分,远大于512字节。正是这个第二阶段的引导加载程序加载了内核。你必须做类似的事情。

加载第二阶段的代码可以比加载完整内核的代码简单得多 - 它基本上将几个扇区直接加载到固定的内存地址中(在低内存中 - 此时它仍处于实模式)并跳转到固定的内存地址。

这个第二阶段大多用C语言编写。在跳转到C函数之前,你只需要在汇编中进行一些设置(进入保护模式,设置堆栈,以及其他一些低级处理器的东西)。做其余的设置。

Linux内核过去做过这样的事情。您可以将原始内核直接复制到软盘中。它的前512个字节是一个软盘引导扇区,它将接下来的几个扇区(仍处于实模式)加载到低内存中的固定地址。接下来的几个扇区有代码(仍然在汇编中)将内核的其余部分加载到固定的内存地址,并跳转到其真正的入口点。如今,IIRC的大部分代码被删除了,Linux内核现在依赖于外部引导程序。