UEFI 引导的内核:静态物理内存布局
UEFI-booted kernel: static physical memory layout
作为我的 OS 课程的一部分,我需要在带有 UEFI (OSVF) 的 QEMU 下编写自己的微型 OS 内核 运行。 UEFI 规范似乎相当复杂,我忽略的一件事是是否有可能有一个静态(编译时定义的)物理内存布局,以便我的内核有合理数量的可用物理内存,同时还保留了 UEFI 使用的区域。
让我用xv6 as an example. It has a simple hand-made bootloader run by legacy BIOS. According to the xv6 book澄清一下,这个OS分配物理内存如下:
+------------------+
| Free Space |
+------------------+ 0x00500000
| Kernel |
+------------------+ 0x00100000
| BIOS and I/O | <------------ Bootloader code is loaded here
+------------------+ 0x00000000
如此简单的布局之所以成为可能,是因为设备和 BIOS 使用的所有 "magic" 内存都位于物理范围 [0x00000000; 0x000FFFFF]
内。特别是,引导加载程序在此范围内加载,然后可以自由选择任何内存区域来加载内核。从 0x00500000
开始的免费 space 可以分配给用户space 程序的需要。
我希望在 UEFI 引导的内核中有一个类似的简单内存布局;但是,这似乎不是一件简单的事情。问题是:
- 看起来无法为 UEFI 固件定义一个地址来加载我的内核 - 相反,固件在 运行 时间选择一个地址;
- 似乎没有相当小的物理地址范围可以保证包含所有 UEFI 使用的内存,因此我可以假设剩余的 RAM 可供内核使用。
解决这些问题的方法之一是通过 GetMemoryMap()
使用 UEFI 提供的内存映射。该映射描述了固件使用的所有内存区域。然而,在 运行 时间弄清楚内存布局使事情变得复杂,而不是像 xv6 使用的那样的静态内存布局。为了简单起见,我愿意牺牲一些 RAM space。
那么有没有办法在我的 UEFI 引导内核中实现静态物理内存布局?
So is there a way to achieve a static physical memory layout in my UEFI-booted kernel?
没有。您可以尝试静态分配恰好适用于一台计算机的物理内存区域(UEFI 中内置的内存管理器确实具有 "allocate page/s at this specific physical address" 功能),但不能保证物理地址范围不会由 UEFI 在任何其他计算机上保留;它是哪个物理地址范围没有区别。
相反,在您的引导代码启用分页之前,它可以愉快地使用从引导加载程序的“.bss”部分中的 UEFI 内存管理器 and/or 内存 pre-allocated 分配的页面,而不用关心物理地址是什么是;在您的引导代码启用分页后,物理地址几乎与所有内容都无关(您可以随心所欲地使用虚拟地址 spaces,包括在内核 space 中静态分配虚拟地址范围,如果您不这样做的话不喜欢 security/KASLR).
大多数情况下,对于 UEFI,如果它是 possible/supported,静态分配的物理地址将没有任何好处,也不会使任何事情变得更简单。
作为我的 OS 课程的一部分,我需要在带有 UEFI (OSVF) 的 QEMU 下编写自己的微型 OS 内核 运行。 UEFI 规范似乎相当复杂,我忽略的一件事是是否有可能有一个静态(编译时定义的)物理内存布局,以便我的内核有合理数量的可用物理内存,同时还保留了 UEFI 使用的区域。
让我用xv6 as an example. It has a simple hand-made bootloader run by legacy BIOS. According to the xv6 book澄清一下,这个OS分配物理内存如下:
+------------------+
| Free Space |
+------------------+ 0x00500000
| Kernel |
+------------------+ 0x00100000
| BIOS and I/O | <------------ Bootloader code is loaded here
+------------------+ 0x00000000
如此简单的布局之所以成为可能,是因为设备和 BIOS 使用的所有 "magic" 内存都位于物理范围 [0x00000000; 0x000FFFFF]
内。特别是,引导加载程序在此范围内加载,然后可以自由选择任何内存区域来加载内核。从 0x00500000
开始的免费 space 可以分配给用户space 程序的需要。
我希望在 UEFI 引导的内核中有一个类似的简单内存布局;但是,这似乎不是一件简单的事情。问题是:
- 看起来无法为 UEFI 固件定义一个地址来加载我的内核 - 相反,固件在 运行 时间选择一个地址;
- 似乎没有相当小的物理地址范围可以保证包含所有 UEFI 使用的内存,因此我可以假设剩余的 RAM 可供内核使用。
解决这些问题的方法之一是通过 GetMemoryMap()
使用 UEFI 提供的内存映射。该映射描述了固件使用的所有内存区域。然而,在 运行 时间弄清楚内存布局使事情变得复杂,而不是像 xv6 使用的那样的静态内存布局。为了简单起见,我愿意牺牲一些 RAM space。
那么有没有办法在我的 UEFI 引导内核中实现静态物理内存布局?
So is there a way to achieve a static physical memory layout in my UEFI-booted kernel?
没有。您可以尝试静态分配恰好适用于一台计算机的物理内存区域(UEFI 中内置的内存管理器确实具有 "allocate page/s at this specific physical address" 功能),但不能保证物理地址范围不会由 UEFI 在任何其他计算机上保留;它是哪个物理地址范围没有区别。
相反,在您的引导代码启用分页之前,它可以愉快地使用从引导加载程序的“.bss”部分中的 UEFI 内存管理器 and/or 内存 pre-allocated 分配的页面,而不用关心物理地址是什么是;在您的引导代码启用分页后,物理地址几乎与所有内容都无关(您可以随心所欲地使用虚拟地址 spaces,包括在内核 space 中静态分配虚拟地址范围,如果您不这样做的话不喜欢 security/KASLR).
大多数情况下,对于 UEFI,如果它是 possible/supported,静态分配的物理地址将没有任何好处,也不会使任何事情变得更简单。