尽管有多个芯片组,操作系统如何获取 x86 PC 的内存映射?

Eng*_*ody 1 c assembly bare-metal osdev acpi

第一:这个问题在这里有重复:

像 Windows 或 Linux 这样的现代操作系统如何知道芯片组特定的内存映射?

但是这个问题的答案是关于设备树和ACPI(对于旧式PC),没有详细信息我需要编写汇编或C代码来利用ACPI表中的信息,我现在尝试首先了解旧式PC以及如何为了解码 ACPI 的表,我尝试进行一些搜索,发现最重要的表是 DSDT ,现在我的问题是如何解码表中的信息以获取详细的内存映射(范围)并获取哪些设备连接到CPU,如何获取内存中DSDT的地址? ,我尝试进行一些搜索,但我无法理解我认为与该主题相关的 AML 语言。如果有人详细说明并提供了解 ACPI 表并为初学者解码它们的良好材料,我将很有帮助,问题是对我来说,我无法记住标准的固定内存映射,因为我想知道相同的操作系统版本如何在不同的芯片组上运行,必须有一种动态方法来检测整个映射,因此获取整个映射的建议过程是还有我的另一个问题

另请注意,这是我学习如何直接与裸机硬件设备单独通信的第一步(这是第二步)

谢谢

Bre*_*dan 5

让我们将其分为 3 个不同的问题。

如何获取DSDT在内存中的地址?

固件提供指向(一个或 2 个)ACPI 表的指针,其中包含所有其他表的索引。这些表是RSDT(根系统描述符表)和XSDT(扩展根系统描述符表);它们之间唯一真正的区别是 XSDT 支持 64 位地址(如果可能的话应该使用),而旧的 RSDT 不支持(并且应该被视为“已弃用”,并且仅用作现代 64 位操作的后备)系统)。这些表主要提供所有其他表的标识符和地址;因此,如果您想查找特定的表(例如 DSDT),您可以在索引中搜索标识符(例如 4 个 ASCII 字符“DSDT”)并查找包含该表物理地址的条目。

指向索引的指针包含在称为 RSDP(根系统描述指针)的特殊结构中;对于不同类型的固件,可以以不同的方式找到它。对于 BIOS,您必须搜索物理内存的几个特定区域,寻找特殊的结构(具有特殊的签名和有效的校验和);对于 UEFI,您只需询问固件(并避免“缓存冲击”搜索)。

这都是ACPI规范描述的(比较清楚),包括如何找到RSDT(例如“根系统描述指针(RSDP)”部分),还包括所有结构和表的格式,以及其含义和目的所有领域。

如何解码DSDT中的信息?

因为启动后情况可能会发生变化(由于热插拔支持等);静态表不能用于某些事情,ACPI 通过定义一种称为 ASL(ACPI 汇编语言)的特殊语言来解决这个问题(并产生更多问题),该语言被编译成称为 AML(ACPI 机器语言)的可移植字节码。

DSDT 包含此 AML。

为了理解它,您需要一个 AML 解释器来执行 DSDT 中包含的 AML。

这是“非常具有挑战性”——要自己完成,您可能需要花费数月时间研究 ACPI 规范(以及数年时间解决不同计算机中的错误)。大多数人移植一个名为 ACPICA 的开源实现(最初由 Intel 创建)(请参阅https://acpica.org/)。

可悲的是;能够执行 AML 只是第一步。您还需要了解 ACPI 的命名空间、AML 提供的函数/方法以及它们应该执行的操作。让情况变得更糟;ACPI 的 AML 期望了解操作系统是什么,然后启用/禁用各种功能并更改其行为以适应操作系统(取决于操作系统被告知的内容);通常,AML 识别的唯一操作系统是 Windows 版本,如果您告诉它其他内容,它会禁用各种功能,因此大多数操作系统只是撒谎并说它们是 Windows 版本,这样 AML 就不会提供残缺的功能其能力的子集。然而; “每个版本的 Windows 的作用”(以及 AML 对于每个特定版本的 Windows 的行为方式)是一场可怕的未记录的(根据 ACPI 规范)灾难。幸运的是; ACPICA 还隐藏了大部分这种痛苦(对于移植 ACPICA 的人来说)。

如何获取详细的内存映射(范围)以及哪些设备连接到 CPU?

大多数情况下你不知道。具体来说,您不只是通过一个漂亮的步骤“获得详细的内存映射”。

反而; int 0x15, eax=0xE820首先,您从固件(来自 BIOS 或GetMemoryMap()UEFI)获取有关物理内存的一些最少信息。然后,您使用各种不同的来源向该最少信息添加更多详细信息,包括但不限于指令CPUID(物理地址实际有多少位)、ACPI“APIC/MADT”表(针对 IO APIC 和本地APIC 地址)、ACPI“EDT/HPET”表(针对 HPET 地址)、ACPI“MCFG”表(针对 PCI Express 内存映射配置空间区域的地址)、ACPI“SRAT”表(针对内存的 NUMA 信息)区域和“热插拔 RAM”信息),以及可能(可选)SMBIOS 表(如果您关心安装的 RAM 类型等问题)。

从静态/不变的来源获得所有您想要的信息后;您切换到“阶段 2”,其中涉及不断管理内存映射并尝试在发现来自各种设备的信息(并通过热插拔事件进行修改)时使其保持最新。这就是能够执行 AML(从 DSDT,使用 AML 解释器)变得很重要的地方。它还涉及总线特定方法(例如,扫描 PCI 总线并从每个 PCI 设备的 BAR/基地址寄存器中提取信息)。

请注意,这不仅仅是填充内存映射的详细信息。最好将其视为发现设备使用的资源,其中包括 IO 端口、IRQ 线、DMA 通道(而不仅仅是物理地址空间的区域)。

另请注意,只有当您拥有能够使用信息“驱动”设备的设备驱动程序时,您才真正了解有关设备的信息。如果你不这样做,那么你拥有的内存映射只会说“保留”,你不会知道为什么,但你可能没有理由关心为什么。

最后说明

乍一看,这“非常令人畏惧”。不要担心——你可以(而且应该)从小处开始,忽略大部分,直到很久以后。仅使用固件中有关物理内存的最少信息,您就可以做很多事情;并添加代码来完成几乎所有其他事情(如果有一天它对您的操作系统确实很重要)。