Kernel 将内核加载到内存——如何编写加载程序本身?

Kernel 将内核加载到内存——如何编写加载程序本身?,kernel,bootstrapping,bootloader,portable-executable,Kernel,Bootstrapping,Bootloader,Portable Executable,我正在用D制作自己的引导加载程序和内核,我遇到了一个绊脚石 背景: 我从头开始写。因此引导扇区正在组装中。我没有用GRUB。 我正在使用Qemu进行测试。 引导扇区从磁盘读取内核,该磁盘当前只是一个平面二进制文件,其第一个扇区是引导加载程序,其余扇区是虚拟地址0xC0000000中的内核代码,并调用kmain,我的内核的入口点。 我正在为我的内核使用PE文件格式。请不要告诉我使用Elf-我的选择是PE。 问题 能够加载PE文件是内核工作的一部分。那么,首先我如何将内核本身加载到内存中,以便它能够

我正在用D制作自己的引导加载程序和内核,我遇到了一个绊脚石

背景: 我从头开始写。因此引导扇区正在组装中。我没有用GRUB。 我正在使用Qemu进行测试。 引导扇区从磁盘读取内核,该磁盘当前只是一个平面二进制文件,其第一个扇区是引导加载程序,其余扇区是虚拟地址0xC0000000中的内核代码,并调用kmain,我的内核的入口点。 我正在为我的内核使用PE文件格式。请不要告诉我使用Elf-我的选择是PE。 问题 能够加载PE文件是内核工作的一部分。那么,首先我如何将内核本身加载到内存中,以便它能够正确执行呢

我无法从引导扇区执行此操作,因为1它不适合512字节,2在汇编中执行此操作很痛苦。显然,我也不能在内核本身中实现它。那么我应该怎么做呢?

GRUB是怎么做的

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

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

第二个阶段大部分可以用C编写。在跳到C函数完成其余的设置之前,您只需要在程序集中进行一些设置,进入保护模式,设置堆栈,以及其他一些低级处理器的工作


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

您已经基本回答了自己的问题。加载PE或Elf等复杂文件格式需要相当多的基础设施。所以内核不应该使用它。Windows内核也没有.exe格式。它应该是可以直接加载到内存和内存中的普通机器代码executed@jalf:Windows内核ntoskrnl.exe是有效的PE文件。。。不是吗?双击它,然后看看会发生什么@日本航空:嗯。。。你曾经双击过DLL吗?那些是PE文件吗?但是是的,我被更正了。然而,我的观点仍然是。任何可执行文件格式,无论是PE、Elf还是其他格式,都是为了提供由操作系统加载和执行的通用可执行文件。对于内核,几乎不需要这种文件格式提供的基础结构。您所需要的只是能够将一块可执行代码加载到内存中,并开始执行它。显然,微软选择将其打包为PE文件,但除非您正在编写下一个Windows,否则该决定和约束不必适用于您,只需添加,使用int 13h将扇区加载到内存中就需要在实模式下进行。