【问题标题】:Higher half kernel initialization高半内核初始化
【发布时间】:2011-09-07 12:31:44
【问题描述】:

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

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

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

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

【问题讨论】:

    标签: kernel bootstrapping virtual-memory osdev


    【解决方案1】:

    这就是我解决这个问题的方法:

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

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

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

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

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

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

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

    【讨论】:

    • 谢谢!一个问题 - 初始化堆(我猜)包含重新定位的 MBI,当你完成它时可以丢弃它,但听起来它也包含初始映射的页表。一旦你创建了你的第一个流程,你是否也放弃了这些?
    • @Rusky:是的,MBI 可以被丢弃,但我不这样做,因为它太小了。我没有将页面目录和页表放在那个堆中,而是放在非常低的内存中(大约 4KB)。我不会丢弃这些,因为我运行的第一个进程将继承它们。 IE。我的第一个进程将在我在初始化期间设置的地址空间中运行。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多