【问题标题】:Why do x86-64 systems have only a 48 bit virtual address space?为什么 x86-64 系统只有 48 位的虚拟地址空间?
【发布时间】:2011-10-06 17:07:12
【问题描述】:

在一本书中,我读到了以下内容:

32 位处理器有 2^32 个可能的地址,而当前的 64 位处理器有 48 位地址空间

我的预期是,如果是 64 位处理器,地址空间也应该是 2^64。

所以我想知道这个限制的原因是什么?

【问题讨论】:

  • 这本书一定是专门讲了AMD64架构(x86-64)的当前实现。仅使用低 48 位。不过,这不是硬件限制——所有 64 位都可用。
  • 识别这本书总是一个好主意。
  • 我猜物理地址线不是空闲的(你至少需要 16 个额外的 CPU 引脚)。而且我还不知道有任何硬件可以在同一处理器上用物理 RAM 芯片填充 48 位空间。当这变得可行时,我确信 AMD 会添加缺失的 16 个引脚 :)
  • 甚至,The 32-bit processors have 2^32 possible addresses 不一定正确,可以存在只有 24 个“引脚”用于寻址内存的 32 位 cpu。例如。 68EC020(更便宜的 68020 版本)是 32 位 CPU,但有 24 位用于寻址内存。
  • 64 位物理寻址存在一个非常现实的问题,虚拟内存页面太小。这会在每次上下文切换时产生巨大的页面目录和极其昂贵的 TLB 缓存刷新。从 4KB 页面移动到 4MB 页面是一种选择,但与当前的操作系统非常不兼容。

标签: x86-64 virtual-memory cpu-architecture


【解决方案1】:

回答原问题:无需添加超过 48 位的 PA。

服务器需要最大的内存量,所以让我们尝试更深入地挖掘。

1) 最大(常用)的服务器配置是 8 Socket 系统。一个 8S 系统只不过是 8 个服务器 CPU 通过高速相干互连(或简称为高速“总线”)连接起来形成一个单一节点。那里有更大的集群,但它们很少而且相距甚远,我们在这里讨论的是常用配置。请注意,在实际使用中,2 Socket 系统是最常用的服务器之一,而 8S 通常被认为是非常高端的。

2) 服务器使用的主要内存类型有字节可寻址的常规 DRAM 内存(例如 DDR3/DDR4 内存)、Memory Mapped IO - MMIO(例如附加卡使用的内存)以及配置空间用于配置系统中存在的设备。第一种类型的内存通常是最大的(因此需要最大数量的地址位)。一些高端服务器也会使用大量的 MMIO,这取决于系统的实际配置。

3) 假设每个服务器 CPU 可以在每个插槽中容纳 16 个 DDR4 DIMM。最大尺寸 DDR4 DIMM 为 256GB。 (根据服务器的版本,每个插槽可能的 DIMM 数量实际上少于 16 个 DIMM,但为了示例,请继续阅读)。

所以理论上每个插槽可以有 16*256GB=4096GB = 4 TB。 对于我们的示例 8S 系统,DRAM 大小可以最大为 4*8= 32 TB。这意味着 寻址此 DRAM 空间所需的最大位数为 45 (=log2 32TB/log2 2)。

我们不会详细介绍其他类型的内存(MMIO、MMCFG 等),但这里的重点是,对于 8 插槽系统来说,最“要求”的内存类型是当今可用的最大类型 DDR4 DIMM (256 GB DIMM)仅使用 45 位。

对于支持 48 位的操作系统(例如 WS16),还有 (48-45=) 3 个剩余位。 这意味着如果我们仅将低 45 位用于 32TB 的 DRAM,我们仍然有 2^3 倍的可寻址内存可用于 MMIO/MMCFG,总共 256 TB 的可寻址空间。

所以,总结一下: 1) 48 位物理地址足以支持当今“满载”大量 DDR4 的最大系统以及需要 MMIO 空间的大量其他 IO 设备。确切地说是256TB。

请注意,这个 256TB 地址空间(=48 位物理地址)不包括任何磁盘驱动器,如 SATA 驱动器,因为它们不是地址映射的一部分,它们只包括可字节寻址的内存,并且暴露于操作系统。

2) CPU 硬件可以选择实现 46、48 或 > 48 位,具体取决于服务器的代数。但另一个重要因素是操作系统可以识别多少位。 今天,WS16 支持 48 位物理地址 (=256 TB)。

这对用户意味着,即使一个大型、超现代的服务器 CPU 可以支持 >48 位寻址,但如果您运行的操作系统仅支持 48 位 PA,那么您只能利用256 TB。

3) 总而言之,有两个主要因素可以利用更多的地址位(= 更多的内存容量)。

a) 您的 CPU 硬件支持多少位? (这可以通过 Intel CPU 中的 CPUID 指令来确定)。

b) 您正在运行什么操作系统版本以及它识别/支持多少位 PA。

(a,b) 的最小值最终将决定您的系统可以利用的可寻址空间量。

我写了这个回复,没有详细研究其他回复。此外,我还没有深入研究 MMIO、MMCFG 和整个地址映射结构的细微差别。但我确实希望这会有所帮助。

谢谢, 阿南德·K·埃纳曼德拉姆, 服务器平台架构师 英特尔公司

【讨论】:

  • 这个问题询问的是 48 位 virtual 地址空间大小(要求虚拟地址是规范的)。您确实需要比物理位更多的虚拟位,因此高半内核可以将所有物理内存映射到单个地址空间(它自己的或用户空间)。正如您所说,HW 只需要实现 DRAM 控制器 + MMIO 可以使用的 PA 位,并且可以使用 x86-64 页表格式中最多 52 位限制的任何数量。 (Why in 64bit the virtual address are 4 bits short (48bit long) compared with the physical address (52 bit long)?)
  • 4 级页表格式也施加了 48 位 VA 限制,直到 HW + SW 支持 57 位 VA 的 PML5 页表。无论如何,这是一个有用的答案,但似乎发布在错误的问题下。我不确定是否有更好的地方,所以我想我们可以把它留在这里,希望通过编辑添加标题来说明 PA 与 VA 的关系。
【解决方案2】:

很多人都有这种误解。但是我向您保证,如果您仔细阅读此内容,阅读此内容后您的所有误解都会被清除。

说一个处理器 32 位或 64 位并不意味着它应该分别具有 32 位地址总线或 64 位地址总线!...我再说一遍,没有!!

32 位处理器意味着它具有 32 位 ALU(算术和逻辑单元)......这意味着它可以在 32 位二进制操作数(或简单地说具有 32 位的二进制数)上运行,类似地,64 位处理器可以在64 位二进制操作数。因此,32 位或 64 位处理器并不表示可以安装的最大内存量。它们只是显示了操作数可以有多大......(为了类比,你可以想象一个 10 位计算器可以计算高达 10 位的结果......它不能给我们 11 位或任何其他更大的结果......虽然它是用十进制表示,但为了简单起见,我说这个类比)......但你所说的是地址空间,它是内存(RAM)的最大直接可接口大小。 RAM 的最大可能大小由地址总线的大小决定,而不是数据总线的大小,甚至不是定义处理器大小(32/64 位)的 ALU 的大小。是的,如果处理器具有 32 位“地址总线”,那么它能够寻址 2^32 字节=4GB 的 RAM(或者对于 64 位,它将是 2^64)......但是说处理器 32 位或 64 位有与此地址空间无关(地址空间=它可以访问内存的距离或 RAM 的最大大小),它仅取决于其 ALU 的大小。当然,数据总线和地址总线的大小可能相同,然后看起来 32 位处理器意味着它将访问 2^32 字节或 4 GB 内存……但这只是巧合,不会相同对于所有人....例如,英特尔 8086 是一个 16 位处理器(因为它具有 16 位 ALU),所以正如您所说,它应该访问 2^16 字节 = 64 KB 的内存,但事实并非如此。它可以访问高达 1 MB 的内存以拥有 20 位地址总线....如果您有任何疑问,您可以谷歌:)

我想我已经把我的观点说清楚了。现在来回答你的问题......因为 64 位处理器并不意味着它必须有 64 位地址总线,所以在一个 48 位地址总线中没有任何错误64 位处理器...他们将地址空间缩小以使设计和制造便宜....因为没有人会使用这么大的内存(2^64 字节)...如今 2^48 字节已经绰绰有余.

【讨论】:

  • 我认为你的观点很清楚,但在你所说的关于 16 位 8086 CPU 的内容中我不明白一件事:16 位 CPU 如何处理 20 位地址?它是否通过两步操作来处理它?即使地址总线是 20 位宽,一旦到达 CPU,寄存器宽度显然只能占用 16 位……他们是怎么做到的?
  • 嗯...2步操作。段寄存器只包含高 16 位。然后乘以 10H 变成 20 位,然后加上偏移量。
【解决方案3】:

CPU 被认为是“N 位”主要取决于它的数据总线大小,以及它的大部分实体(内部架构):寄存器、累加器、算术逻辑单元 (ALU )、指令集等。例如:老式的摩托罗拉 6800(或 Intel 8050)CPU 是 8 位 CPU。它具有 8 位数据总线、8 位内部架构和 16 位地址总线。


  • 虽然 N 位 CPU 可能有一些不是 N 大小的实体。例如 6809 在 6800 上的改进(它们都是带有 8 位数据总线的 8 位 CPU)。 6809 中引入的显着增强包括使用两个 8 位累加器(A 和 B,可以组合成一个 16 位寄存器 D)、两个 16 位索引寄存器(X、Y)和两个16 位堆栈指针。

【讨论】:

  • 已经有 an answer 以摩托罗拉 68000 / 68020 为例说明了这一点。这个问题实际上是关于 x86-64,而不是旧的 8 / 16 位 CPU。在 x86-64 的情况下,主要因素之一是更宽的虚拟地址需要更深的页表,而你所说的旧芯片不存在这个因素。
  • 数据总线宽度不必与寄存器或 ALU 宽度相匹配。例如,P5 Pentium 有 64 位数据总线(对齐的 64 位加载/存储保证是原子的),但寄存器/ALU 只有 32 位(集成 FPU 除外,而在后来的 Pentium MMX 中,SIMD ALU。)
  • OP 写道:“我的期望是,如果它是 64 位处理器,地址空间也应该是 2^64。” ........您写道:“这个问题实际上是关于 x86-64,而不是旧的 8 / 16 位 CPU”。 ........我认为你错过了OP问题的本质。 OP 问题是错误假设的结果,即 64 位 CPU 应该具有 64 位地址总线。关于 ALU,我写了它的 大部分 实体;不是全部。
  • 通过重新发布此评论停止向我发送垃圾邮件。是的,由于您描述的原因,OP当然是错误的,但我指出您的答案看起来也犯了类似的错误。你说“因此它的大部分实体:寄存器和累加器,算术逻辑单元(ALU)......”,听起来你说这些东西与数据总线宽度相匹配.短语“a big part”意味着您说的是哪些部分,而不是仅在某些时候对这些部分正确。
【解决方案4】:

仅使用 64 位 VA 的低 48 位是不正确的,至少在 Intel 64 中是这样。使用高 16 位,有点,有点。

英特尔® 64 和 IA-32 架构软件开发人员手册中的第 3.3.7.1 节规范寻址 说:

规范地址必须将位 63 到 48 设置为零或一(取决于位 47 是零还是一)

所以第 47 位到第 63 位形成一个超位,要么全为 1,要么全为 0。如果地址不是规范形式,则实现应该出错。

在 AArch64 上,这是不同的。根据ARMv8 指令集概述,它是一个 49 位 VA。

AArch64 内存转换系统支持 49 位虚拟地址(每个转换表 48 位)。虚拟地址从 49 位进行符号扩展,并存储在 64 位指针中。可选地,在系统寄存器的控制下,64 位指针的最高有效 8 位可以保存一个“标记”,当用作加载/存储地址或间接分支的目标时,该标记将被忽略

【讨论】:

  • 只有低 48 位是有效的,但硬件会检查它是否正确符号扩展为 64 位。 IDK 为什么他们没有指定零扩展;也许他们希望更方便地检查高半地址与低半地址(仅通过检查符号位)。或者可能是为了避免使 2^48 边界变得特殊,因此靠近顶部的地址可以方便地放入 32 位符号扩展常量中。我认为后者的可能性更大。
  • 无论如何,当前的 HW 检查规范可防止软件将忽略的位用于标记指针,这些位将在未来的 HW 上中断,因此它是可以在需要时扩展未来硬件的机制的一部分. (由于非易失性内存直接连接到物理和虚拟地址空间,这可能比他们预期的要快。)
  • 我的 Core i5 上的 Linux 上的 procfs 说它被映射到 7ffd5ea41000-7ffd5ea62000。根据上述“规范”规则,此地址范围是有意义的。位 48-63 为 0,使其成为正确的规范地址。有点奇怪的是 Linux 源代码中的一些地址。在 include/asm/pgtable_64_types 它说#define __VMALLOC_BASE _AC(0xff92000000000000, UL)。这不是一个规范的地址。这样的地址将以 0xffff8 开头。不知道为什么。
  • 是的,IIRC Linux 将规范范围的下半部分用于用户空间,并且(大部分)将高半部分用于仅内核映射。但是一些内核内存被导出到用户空间,比如[vsyscall] 页面。 (这可能会导出当前 PID 之类的东西,以便 getpid() 纯粹是用户空间。@ 987654323@ 也可以在用户空间中使用 rdtsc + 内核导出的比例因子。虽然其中一些是我认为在 @987654324 @,位于下半部分的顶部附近。)
  • 了解__VMALLOC_BASE 的作用。估计没有直接使用。
【解决方案5】:

在我看来,这是页面大小的结果。每个页面最多包含 4096/8 =512 个页表条目。 2^9 = 512。所以 9 * 4 + 12=48。

【讨论】:

    【解决方案6】:

    除了在 CPU 地址路径中节省晶体管之外,还有一个更严重的原因:如果增加地址空间的大小,则需要增加页面大小、增加页表的大小,或者拥有更深的页表结构(即更多级别的翻译表)。所有这些都会增加 TLB 未命中的成本,从而损害性能。

    【讨论】:

    • Intel is proposing a 5-level paging scheme 从当前的 48 位扩展到 57 位。 (与当前 x86-64 页表相同的每级 9 位/4k 页)。每级使用 10 或 11 位需要更改 page-walk 硬件,因此这可能不是大内存的最佳设计,但它是双模 CPU 的明智扩展,它还需要支持 4-当前格式的级别表。
    • 当然,2M或1G的hugepages,从top level到huge-page table entry只有4或3级页表,而不是页目录指针。
    【解决方案7】:

    任何关于总线大小和物理内存的答案都有点错误,因为 OP 的问题是关于虚拟地址空间而不是物理地址空间。例如,对某些 386 的所谓类似限制是对它们可以使用的物理内存的限制,而不是对虚拟地址空间的限制,虚拟地址空间始终是完整的 32 位。原则上,即使只有几 MB 的物理内存,您也可以使用完整的 64 位虚拟地址空间;当然,您可以通过交换来做到这一点,或者对于您希望在大多数地址映射同一页面的特殊任务(例如某些稀疏数据操作)。

    我认为真正的答案是 AMD 只是便宜而且希望现在没人会在意,但我没有可引用的参考资料。

    【讨论】:

    • “便宜”我猜你的意思是不添加永远不会使用的引脚,不为不会使用的晶体管占用芯片空间,并使用释放的空间来使现有指令更快?如果这很便宜,我就在!
    • 80386 允许 2 * 4096 个选择器,每个选择器最多包含 4GB 内存(总共 32TB)。 80286 允许 2 * 4096 个选择器,每个选择器最多包含 64KB (1GB)。
    • 非线性分段黑客在我的书中不算作地址空间。便携式软件无法使用它们。
    • @R.. - 我认为便携式软件的定义是它可以。 :-) 例如,C++ 禁止将指针比较到不同的数组中,以便它们可以位于单独的 4GB 段中。
    • 如果您的编译实际上会生成巨大的指针并为每个内存取消引用加载一个段寄存器,那么可以。但实际上这非常慢,而且每个人都使用小内存模型和__far(或更糟糕的是,FAR/far!)指针......
    【解决方案8】:

    内部本机寄存器/操作宽度不需要反映在外部地址总线宽度中。

    假设您有一个 64 位处理器,它只需要访问 1 兆字节的 RAM。只需要一个 20 位地址总线。为什么要为您不会使用的所有额外引脚的成本和硬件复杂性而烦恼?

    摩托罗拉68000是这样的;内部为 32 位,但带有 23 位地址总线(和 16 位数据总线)。 CPU 可以访问 16 兆字节的 RAM,并且要加载本机数据类型(32 位)需要两次内存访问(每个访问 16 位数据)。

    【讨论】:

    • 但是 68000 被认为是“16/32 位”cpu,而不是“完整”的 32 位 cpu,所以可以说它在 16 位过去还有一脚;我选择了 68020 作为例子,因为它的低成本 68EC020 版本只有 24 位地址,虽然 68020 是一个“完整的”32 位 cpu...+1 考虑了这个出色的处理器系列!跨度>
    • @ShinTakezou:老实说,80386SX 是 16 位 CPU(因为它具有与 80286 类似的地址空间)还是 32 位(因为它具有 80386DX 的内部架构)?一个人可以像你一样说,但另一个(这个)说“内部才是最重要的”——你可以引用我的话。
    • @Olof 我认为,在“内存”(即外部世界)的上下文中,外部才是最重要的,所以 68000 是一个 16 位 CPU(需要 2 个“步骤”来读取 32位数据):D
    • @ShinTakezou:内存上下文,甚至缓存,总是在 cpu 本身之外,即使它们在现代处理器中耦合得非常紧密。 8088 在内部与 8086 相同,尽管它有 8 条数据总线,而 8086 有 16 条。我看不出您显然认为什么是显而易见的,即 8088 应该与 Z80、8080、8085 等归为同一组。在这种情况下,数据总线的宽度问题似乎微不足道
    • 我根本不是这方面的专家,所以我没有什么明显的东西。我只是想注意到需要对过去进行更锐利的切割,人们可能认为 68000 仍然存在一个“旧时代”的处理器,因此它的地址空间被限制为小于 32 位似乎是“自然的”;而 68020 可以是 32 位,因此 68EC020 的存在及其限制表明它是一种选择不是因为“那个(或这个)时间的限制”,而是出于其他考虑(比如如果拥有 64 个引脚没有真正的优势,那就让它更便宜),这或多或少是这个答案的论点。
    【解决方案9】:

    因为这就是我们所需要的。 48 位为您提供 256 TB 的地址空间。好多啊。你不会很快看到一个需要更多的系统。

    于是 CPU 制造商走捷径。它们使用允许完整的 64 位地址空间的指令集,但当前的 CPU 只使用低 48 位。另一种方法是浪费晶体管来处理多年来不需要的更大地址空间。

    因此,一旦我们接近 48 位限制,只需释放处理完整地址空间的 CPU,但不需要对指令集进行任何更改,也不会破坏兼容性。

    【讨论】:

    • 640kb 对任何人来说都足够了。
    • 你还在运行 8088 系统吗,bdares?
    • @bdares:类比不好。 8088/8086 架构的指令集内置了 640k 限制。只有制作一个新的ISA(386)才有可能打破这个障碍。另一方面,x86_64 支持 ISA 中的所有 64 位。只是当前一代的硬件无法全部使用...
    • @R。实际上,CPU 的限制是 1 兆字节。 IBM PC 将其中的一部分指定用于内存映射外围设备、BIOS 等。其他一些 8088/8086 设计(Zenith Z100,如果内存服务)指定较少用于外围设备等,而相应地更多用于应用程序。
    【解决方案10】:

    阅读wikipedia article的限制部分:

    一台 PC 不能包含 4 PB 的内存(由于当前内存芯片的大小,如果没有别的原因),但 AMD 设想了大型服务器、共享内存集群和其他物理地址空间的使用,在可预见的将来可能会接近这一点,并且 52 位物理地址提供了充足的扩展空间,同时不会产生实现 64 位物理地址的成本

    也就是说,此时实现完整的 64 位寻址毫无意义,因为我们无法构建一个可以完全利用这样一个地址空间的系统 - 所以我们选择了对今天(和明天)系统实用的东西。

    【讨论】:

    • 4 PB 中的 4 来自哪里?如果我们谈论的是 64 条地址线,我们应该以 32 条地址线(即 4 GB)使地址空间的平方结束。平方,我们应该有 16,而不是 4 PB。我错过了什么吗?
    • 它来自当前的物理限制(52 位)——关键是我们无法在 PC 中放置足够的 RAM 来支持这个受限范围,更不用说完整的 64 位所需的内存了-位地址空间。
    猜你喜欢
    • 2018-03-12
    • 2021-01-06
    • 1970-01-01
    • 2011-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-13
    • 2019-07-03
    相关资源
    最近更新 更多