更高的半内核初始化

rpj*_*nst 5 bootstrapping kernel osdev virtual-memory

在初始化我的内核时,我需要做一些事情:1)需要启用分页,2)物理内存管理器需要从grub解析内存映射,以及3)各种启动代码需要访问需要的数据留在那里以后(例如GDT,IDT,内存管理结构).

这些步骤之间的依赖性让我发疯.对于较高的一半,内核在其虚拟地址处链接,因此我提出的选项是1)在汇编中启用分页,这将涉及遵循所有多引导指针(在汇编中),因此它们仍然可以访问到物理内存管理器,然后将它们全部取消映射,2)将启动代码链接到其物理地址,然后执行一些指针操作以访问其物理地址处的内核结构,或者3)不要使用更高的一半核心.

还涉及引导物理内存管理器而不知道编译时的物理内存量.我很确定在分配第一个结构时我必须小心避免所有的多引导结构,或者先使用它们然后不要担心覆盖它们(虽然我仍然需要处理模块和这种方法可能涉及在设置物理内存管理器时将多引导表复制到我需要的已知位置.

这些问题是我到目前为止避免使用更高半内核的原因.有没有人有一个很好的系统来解决这些依赖关系?也许这个GDT技巧的一些变化是访问其链接/虚拟地址的内核和物理地址的多重引导表,或使用某种预定义的页表来避免上述问题,可能涉及PSE?

Job*_*Job 6

我是这样解决这个问题的:

我的内核映像由 GRUB 加载到(物理)地址 0x01000000(16MB,就在 ISA DMA 区域上方)。该图像基本上由两部分组成:

  1. “早期初始化”部分。此部分包含为准备跳转到上半内核而执行的代码。我还在本节中为准备期间使用的堆栈和堆保留了一些空间。本节中的所有代码都链接到(虚拟)地址 0x01000000。
  2. 图像的其余部分包含属于上半部分内核的代码和数据。这部分中的所有代码都链接在(虚拟)地址 0xc0000000 (3GB) 处。

由于早期 init 部分中的代码链接在与加载位置相同的地址处,因此 GRUB 可以毫无问题地跳转到此代码中。这个早期的初始化代码执行以下步骤:

  1. 将 GRUB 传递给内核的 MBI 结构重新定位。早期 init 部分中的堆用于此目的。
  2. 标识将从物理地址 0x0 开始的所有页面映射到早期 init 部分使用的最后一个页面的物理地址。身份映射意味着虚拟地址与物理地址相同。这确保了在启用分页后仍然可以执行早期 init 部分中的代码。
  3. 映射虚拟地址 0xc0000000 处的高半内核。
  4. 启用分页。
  5. 跳转到上半部分内核。

此时,其余的初始化工作由上半部分代码完成。这包括设置 GDT、IDT、内存管理…… 请注意,MBI 被重定位到一个众所周知的位置,因此您不必担心用您自己的数据结构覆盖它。

关于物理内存管理器的一个小词:我所做的是计算我的数据结构所需的页面数量,从内核映像之后的第一页开始分配这些结构,并在这些数据结构之后开始处理页面。

我希望这个解释是清楚的。如果不是,请告诉我。如果您愿意,我也可以为您提供我的内核的副本。