0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

内存是怎么映射到物理地址空间的?内存是连续分布的吗?

冬至子 来源:UEFI社区 作者:wolf uefiblog 2023-06-30 15:59 次阅读

如果我们将两个4G内存插入内存插槽,得到的内存地址空间是0到8G吗?是不是0到4G是第一根内存,4到8G是第二根内存呢?实际情况相差甚远,内存在物理地址空间的映射是分散的。一部分原因是4G以下有Memory map IO(mmio)空间和PCIe的配置空间,另一个原因是Interleaving会打撒内存地址到各个Channel、DIMM甚至是Rank和bank上。今天我们就一起来了解一下x86系统的地址空间分布。

物理地址空间

一个典型的物理地址空间是这样的:

图片

其中只有灰色部分是真正的内存,其余都是MMIO。而内存被分为High DRAM和Low DRAM,如图:

图片

为什么要把内存强行分割成两块呢?因为历史的包袱。最早内存都很小,32位的地址(4G)空间看起来永远也用不完,低地址被分配给内存用,高地址就自然而然被分配用来给Memory map IO。既然已经分给它们了,为了兼容以前的驱动,这一块就被固定下来。再有内存就只能从4G以上分配了。

Low MMIO和High MMIO

Low MMIO结构如下图:

图片

其中有几块要特别说明一下:

1.Boot Vector的空间是BIOS内容映射的地址,它的大小是可以调节的,为了满足不同大小的BIOS。

2.Local APIC是APIC中断模式各个内核local APIC寄存器的映射地址。

3.PCI ECAM也有叫做PCIBAR,是PCIe配置地址空间的映射地址。它的起始地址可调,台式机BIOS一般会把它设置得很高,这样4G以下内存会比较大,方便32位Windows使用。举个例子,如果我们把PCIe BAR(BEGREG)设为0x80000000,那么尽管插了8G DIMM,4G以下也不会超过2G的内存可以使用,而2到8G的真实内存都被映射到在4G地址空间以上了,而这些是32位Windows使用不了的。所以有的主板运行32位操作系统发现可用内存小了一大块就是这个原因。它的大小可以修改,一般可以设为64MB和128MB。

High MMIO被BIOS保留作为64位mmio分配之用,例如PCIe的64位BAR等。

Low DRAM和High DRAM

4G以下内存最高地址叫做BMBOUND,也有叫做Top of Low Usable DRAM (TOLUD) 。BIOS也并不是把这些都报告给操作系统,而是要在里面划分出一部分给核显、ME和SMM等功能:

图片

红框中是在low DRAM被“偷”的部分

4G以上的内存最高端叫做Top of Up Usable DRAM (TOUUD) ,再上面就是High MMIO了。

1MB以下比较特殊,里面全部都是已经被淘汰的传统BIOS和DOS关心的内容,我们叫它DOS Space或者Legacy Region:

图片

在那里,我们习惯用传统的实模式地址来划分它们的具体内容:

1.0~640KB,传统DOS空间。

2.A段和B段,传统SMM空间。VGA的MMIO也被映射到这里,可以通过寄存器切换。

3.C段和D段,legacy opROM映射空间和EBDA空间。

4.E段和F段,BIOS空间的Lower和Upper映射地址。BIOS的rom内容也会被映射到这里,方便Legacy BIOS实模式跳转到保护模式。

内存的Interleave

从前面可以看出内存在地址空间上被拆分成两块:Low DRAM和High DRAM。那么在每块地址空间上分配连续吗?现代内存系统在引入多通道后,为了规避数据的局部性(这也是Cache为什么起作用的原因)对多通道性能的影响,BIOS基本缺省全部开启了Interleaving,过去美好的DIMM 0和DIMM 1挨个连续分配的日子一去不复返了。

什么是Interleaving?简单来说,就是让内存交错起来,如下面的动图:

图片

这是一个bank层级的模4的interleaving。在桌面电脑上,常见的还有Channel级的、DIMM级的和Rank级的。

服务器上Interleaving更是不可或缺,它的粒度更细,可以达到数十bytes层级的interleave,它和内存的其他特性,如类似磁盘阵列RAID的内存spare, mirror特性,构成了复杂异常的内存映射系统。在BIOS里面,台式机/笔记本内存映射相对简单,只有一个大表和数十个寄存器;而在服务器BIOS中,有数个相互关联的大表和寄存器阵列来解码(decode)内存的请求,代码的硬件逻辑也是相当复杂。关于它,我会有一篇专栏文章讨论地址译码和地址反向解码,详细内容那里再说,这里只需要知道,物理内存分布在各个DIMM上就够了。

物理地址到内存单元的反推

BIOS实际上一手导演的内存的分配,它当然可以从任何物理地址反推回内存的单元地址。我们可以用下面一组数据来唯一确定某个内存单元:

Channel #;DIMM #; Rank #;Bank #;Row #;Column #

在内存分配表缺失的情况下,BIOS甚至可以通过它填过的寄存器重建这个映射表。但实际上BIOS并不希望一般用户知道这些信息,因为有安全性问题。

暴露内存信息容易招来内存侧信道攻击(Side Channel),比较有名的有Row hammer攻击。简单的来说它是通过反复写某个内存单元,借助内存的特性,希望影响相邻Row/Column的内容。

有些情况确实需要知道这些信息,就是内存出错的时候。和大家想象的不同,内存是会出错的。尤其云服务器中内存的出错是十分频繁的。出错起来也千奇百怪,开始可能是偶尔的随机错误,经过ECC等校正后,就再也不会复现;而有时是某个Bit总是出错,进而慢慢的整个row、column或者相邻的cell开始出错,从可以纠正的错误变成不可修正的错误,导致服务器必须停机。这时候就必须知道哪个内存坏了,进而换掉它。

报告给操作系统,但这个信息里面只有物理地址,如何才能知道是哪个内存单元坏了呢?在Linux上面可以通过edca(参考资料4),有编程经验的同学可以通过edca的程序接口(参考资料3),可以得到更加丰富的信息。

如何关掉Interleaving

对内存有特殊需求的朋友,如果希望内存连续,可以在BIOS里面关闭所有的Interleaving来达成这个目标:

图片

注意是所有的。之后可以通过SMBIOS来看到内存分布信息(dmidecode)。

结论

BIOS作为内存的大管家,也负责内存的分配和映射memory map。它会把这些信息通过E820, GetMemoryMap函数和SMBIOS传递给操作系统。操作系统在此基础上再建立页表,产生虚拟地址。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 寄存器
    +关注

    关注

    30

    文章

    5028

    浏览量

    117723
  • Linux系统
    +关注

    关注

    4

    文章

    567

    浏览量

    26913
  • DRAM芯片
    +关注

    关注

    1

    文章

    80

    浏览量

    17881
  • PCIe接口
    +关注

    关注

    0

    文章

    111

    浏览量

    9529
  • DOS系统
    +关注

    关注

    0

    文章

    9

    浏览量

    1342
收藏 人收藏

    评论

    相关推荐

    鸿蒙内核源码分析:物理地址映射

    MMU的本质 虚拟地址(VA):就是线性地址,鸿蒙内存部分全是VA的身影,是由编译器和链接器在定位程序时分配的,每个应用程序都使用相同的虚拟内存地址
    的头像 发表于 11-03 10:28 1811次阅读

    操作系统中的逻辑地址物理地址

    本文是关于操作系统中逻辑地址物理地址之间的区别。计算机操作系统中的内存使用两种不同类型的地址物理地址
    发表于 09-14 14:26 3154次阅读

    Linux内核内存管理之内核非连续物理内存分配

    我们已经知道,最好将虚拟地址映射到连续页帧,从而更好地利用缓存并实现更低的平均内存访问时间。然而,如果对内存区域的请求并不频繁,那么考虑基于
    的头像 发表于 02-23 09:44 379次阅读
    Linux内核<b class='flag-5'>内存</b>管理之内核非<b class='flag-5'>连续</b><b class='flag-5'>物理</b><b class='flag-5'>内存</b>分配

    为什么MMU的地址映射物理地址会跳变?

    关于MMU的地址映射,32位的cpu有4G的虚拟地址空间,将它分为4096个小块,每个小块是1M,用描述符进行虚拟地址
    发表于 08-22 05:45

    关于ARM的统一编制与内存映射机制

    中很大一部分是留给内存条中的内存的,但也常被映射到其他存储器上(如显存、BIOS等)。在程序指令中的虚拟地址经过段映射和页面
    发表于 10-23 15:53

    【HarmonyOS】虚拟地址<->物理地址是如何映射

    MMU的本质虚拟地址(VA): 就是线性地址, 鸿蒙内存部分全是VA的身影, 是由编译器和链接器在定位程序时分配的,每个应用程序都使用相同的虚拟内存地址
    发表于 11-03 16:20

    鸿蒙内核源码分析(内存映射篇):虚拟地址物理地址之间是如何映射

    MMU的本质虚拟地址(VA): 就是线性地址, 鸿蒙内存部分全是VA的身影, 是由编译器和链接器在定位程序时分配的,每个应用程序都使用相同的虚拟内存地址
    发表于 11-19 10:52

    ARM32 Linux的内存布局

    Kernel维护的,所以Kernel可以决定1GB的虚拟地址空间具体映射到什么物理地址。但是不管Kernel怎么映射,最多也只能
    发表于 04-24 14:20

    Linux虚拟内存物理内存的深刻分析

    内存地址,这是有独立内存空间的好处当不同的进程使用同样的代码时,比如库文件中的代码,物理内存中可以只存储一份这样的代码,不同的进程只需要把自己的虚拟
    发表于 05-31 08:00

    IO端口与IO内存区别详解

    地址的概念 1)物理地址:CPU地址总线传来的地址,由硬件电路控制其具体含义。物理地址中很大一部分是留给
    发表于 01-17 12:40 1658次阅读
    IO端口与IO<b class='flag-5'>内存</b>区别详解

    鸿蒙内核中虚拟地址物理地址之间是如何映射

    虚拟地址(VA): 就是线性地址 鸿蒙内存部分全是VA的身影 是由编译器和链接器在定位程序时分配的,每个应用程序都使用相同的虚拟内存地址空间
    发表于 11-19 14:45 9次下载
    鸿蒙内核中虚拟<b class='flag-5'>地址</b>与<b class='flag-5'>物理地址</b>之间是如何<b class='flag-5'>映射</b>的

    详解io端口与io内存

    (一)地址的概念 1)物理地址:CPU地址总线传来的地址,由硬件电路控制其具体含义。物理地址中很大一部分是留给
    发表于 02-11 15:37 0次下载
    详解io端口与io<b class='flag-5'>内存</b>

    Linux内存映射的原理

    物理地址是处理器在系统总线上看到的地址。使用RISC的处理器通常只实现一个物理地址空间,外围设备和物理
    的头像 发表于 01-15 09:55 1609次阅读

    Linux虚拟地址空间物理地址空间的关系

    很多人接触Linux的内存管理是从malloc()这个C语言库函数开始,也是从那时开始就知道了虚拟内存的概念。但很多人可能并不知道虚拟地址是如何转换成物理地址的,今天带你搞懂虚拟
    的头像 发表于 10-08 11:40 505次阅读
    Linux虚拟<b class='flag-5'>地址</b><b class='flag-5'>空间</b>和<b class='flag-5'>物理地址</b><b class='flag-5'>空间</b>的关系

    linux内存性能优化介绍

    也不同;图示为 32 位和 64 位系统的虚拟地址空间内存映射是将虚拟内存地址映射到
    的头像 发表于 11-10 15:23 304次阅读
    linux<b class='flag-5'>内存</b>性能优化介绍