简介:在系统启动早期,ACPI表为内核描述硬件拓扑与资源分配,其中的DMAR(DMA重映射报告)表是Intel VT-d和IOMMU功能正常工作的关键。当BIOS/固件备份中出现dmar.rar这类直接存储的原始表文件时,它们往往承载着排查PCIe设备直通故障、RMRR区域配置异常的重要线索。本文从ACPI表解析原理出发,介绍如何通过acpidump、dmar_parse等工具校验、解压与解读DMAR二进制数据,并对比实际系统中的VT-d状态,帮助运维与驱动开发人员定位IOMMU相关问题。 前两天整理旧移动硬盘,翻出来一个名为dmar.rar_直接存储的压缩包。这名字一看就是当年从某台服务器上紧急备份东西时随手改的:原始文件名dmar.rar,后面加“_直接存储”说明它是原样从机器里拖出来、不做任何加工处理的存在。懂行的人看到“dmar”两个字,第一反应应该是 DMA Remapping,也就是 ACPI 表里的 DMAR 描述表;不懂行的人可能以为这是个什么软件安装包,解压出来发现几个不带后缀的文件,直接懵掉。
这篇博文我就把这套东西彻底讲明白:dmar 到底是什么文件,为什么它会以 .rar 形式出现,“直接存储”这种操作背后有哪些值得注意的细节,以及拿到一个dmar.rar之后,从校验、解压、存放到解析 DMA Remapping 表的完整流程。适合三类人看:一是做过 BIOS/固件调试、经常跟 ACPI 表打交道的运维和驱动开发,二是搞虚拟化、PCIe 透传时被 VT-d 问题折腾过的人,三是纯粹在硬盘角落发现同名文件、想搞清楚它有没有用的好奇心选手。
1. 先弄明白“dmar”到底是什么,再谈“直接存储”
1.1 DMAR 表在 ACPI 体系里的位置
你可以在 Linux 下执行dmesg | grep -i dmar看到一堆DMAR:开头的日志,比如DMAR: Host address width 46、DMAR: DRHD base: 0x000000fed90000。这些日志不是某个驱动随便打的,而是内核在启动阶段解析 ACPI 表时,根据 DMAR 表里的内容输出的。
ACPI 表是 BIOS/UEFI 固件留给操作系统的一系列内存数据结构,里面描述了主板上的电源管理、CPU 特性、中断路由、设备拓扑等信息。DMAR(DMA Remapping Reporting)是其中专门描述 DMA 重映射硬件能力的一张表。它最重要的作用,是告诉操作系统:这台上是否有支持 VT-d 的重映射硬件单元(Remapping Hardware Unit),它们各自管理哪些设备,哪些内存区域是保留的,哪些设备需要特殊的 RMRR 处理。
所以 DMAR 不是一个普通的用户态配置文件,而是系统启动早期、内存管理还没完全铺开时,内核就要读的关键表之一。如果这张表缺失、损坏或者和你机器的实际硬件不匹配,轻则 VT-d 功能起不来,重则某些 PCIe 设备的 DMA 直接出错,甚至在启动阶段就 panic。
1.2 为什么搞虚拟化和 PCIe 透传的人绕不开它
做虚拟化平台或者折腾 PCIe 设备直通(Passthrough)的人,对 DMAR 表的敏感度极高。
以 QEMU/KVM 环境为例,你要把一张物理网卡或 GPU 透传进虚拟机,宿主机必须开启 IOMMU。Intel 平台对应的就是 VT-d,而内核启用 VT-d 的第一步,就是去解析 DMAR 表。如果 DMAR 表描述的设备作用域(Device Scope)和实际 PCI 拓扑对不上,内核就无法给目标设备建立正确的重映射域,后续直通的时候只能报Device is not behind IOMMU之类的错误。
再比如说,RMRR(Reserved Memory Region Reporting)条目描述了一些保留内存区域。这些区域可能是某些集成设备在 DMA 时固件约定要访问的区域,比如显卡的 OpRegion。如果 RMRR 没配好,内核对这块保留区域的处理就会出问题,典型表现是启动时黑屏、显卡驱动加载后系统直接重启。
所以一个dmar.rar里面存的,往往就是一组用于分析这些问题的表文件:有些是完整 ACPI 表的二进制导出,有些是经过解码的文本文件。而“直接存储”就是告诉你:这些文件是从原机 ACPI 里一字不差抠出来的,没有经过转换和加工。
2. “直接存储”不等于双击解压:我从 dmar.rar 里取文件的完整流程
2.1 拿到压缩包后的第一道工序:完整性校验
看到dmar.rar_直接存储这种名字,我第一反应不是直接右键解压,而是先看一下压缩包里有没有校验文件。因为这种文件通常是从服务器紧急备份出来的,传输过程可能经过 U 盘、网盘、微信文件传输助手等不靠谱渠道,任何一位校验位不对,后面解析出来的全是垃圾数据。
我一般先解压,但解压之后不急着用,先对每个文件做 SHA-256 校验。具体做法是把压缩包里的sha256sums.txt拿出来,在 Linux 下执行:
sha256sum -c sha256sums.txt如果没有校验文件,我就自己解压后对关键文件算一次哈希,和从原机提取时记录的值对比。这一步很多人会跳过,但我觉得对 DMAR 这类二进制表文件来说,必须做。因为 ACPI 表里任何一个字节的偏差都可能导致解析结果完全错误,而这类错误又不会像文本文件那样肉眼可见。
2.2 解压后的目录规划与文件命名
直接存储的压缩包解压出来,经常会看到下面几种类型的文件:
| 文件类型 | 常见后缀 | 内容说明 |
|---|---|---|
| 完整 ACPI 表导出 | .dat / .bin / .aml | 从/sys/firmware/acpi/tables/DMAR或acpidump导出的原始二进制 |
| 解码后的文本 | .txt / .lst | 用dmar_parse、acpixtract解析后的可读内容 |
| 内核日志 | .log / .dmesg | 包含DMAR:前缀的相关日志 |
| 硬件拓扑信息 | .lspci / .txt | lspci -vvv等命令的输出,用于对照 Device Scope |
很多人解压之后不管三七二十一直接全部塞到一个目录,文件名也不改,过几天再回来看完全不知道谁是谁。我的建议是解压后立刻建一个标准化目录:
dmar_case_20250115/ ├── raw/ │ ├── DMAR.dat │ └── acpidump.dat ├── parsed/ │ ├── dmar_parse_output.txt │ └── rmrr_list.txt ├── logs/ │ └── dmesg_iommu.log └── pci/ └── lspci.txt这种结构的好处是,后续无论是自己排查问题还是把问题抛给别人,都能快速定位数据来源。毕竟这些表文件不像源码那样有注释,不靠目录结构去约束,很容易乱。
2.3 直接存储的“直接”到底指什么
“直接存储”这个说法在运维语境里,指的是文件从源位置完整保留、不经过二次加工地放到存储介质上。听起来很简单,但实际操作里有个很容易被忽略的点:文件在存储介质上的物理位置和文件系统层面的“直接存储”无关,真正重要的是文件内容本身没有被修改。
拿 DMAR 表来说,直接存储意味着以下几种操作都是禁止的:
- 不要用文本编辑器打开
.dat文件后另存为,那会破坏二进制结构。 - 不要用
dos2unix之类的工具转换换行符,二进制文件根本不需要换行符。 - 不要在解压后对文件做任何格式转换,比如把
.dat转成.bin,除非你明确知道自己在做什么。 - 不要用网盘自带的在线预览功能去“看”这些文件,预览过程可能改写文件元数据。
我见过最离谱的一次,是有人把 ACPI 表导出文件用 Excel 打开了一遍然后保存,整个文件被套了一层 OLE 容器,结构彻底毁掉。所以“直接存储”的本质不是操作上的“直接”,而是语义上的“原样保留”:压缩包里的字节是什么,存到目标介质、传到别人手里时还是什么。
3. 解析 DMAR 文件的正经姿势:从 RAR 到 DMA Remapping 表
3.1 提取 ACPI 原始表:acpidump
如果你的dmar.rar里只存了一个acpidump.dat,那你需要先把这张总表拆开,把 DMAR 表单独提取出来。acpidump是acpica-tools软件包里的一个工具,在 Ubuntu/Debian 上安装方式很简单:
sudo apt install acpica-tools然后用它生成当前系统的完整 ACPI 转储:
sudo acpidump > acpidump.dat这里有个细节:acpidump输出的文件本身也是文本和二进制混合的格式,不能直接当原始 ACPI 表去解析。你需要用acpiextract把它拆成一个个独立的表文件:
acpiextract -a acpidump.dat执行之后,当前目录下会出现DMAR.dat、MCFG.dat、DSDT.dat等文件。其中DMAR.dat就是我们要分析的 DMA Remapping 描述表。
如果你是从/sys/firmware/acpi/tables/直接导出的,那得到的就是已经拆分好的DMAR文件,不需要再做这一步。具体命令:
sudo cat /sys/firmware/acpi/tables/DMAR > DMAR.dat3.2 dmar_parse 工具的使用
拿到DMAR.dat之后,光靠xxd看二进制可读性太差。我自己的习惯是用dmar_parse这个工具来解析。这个工具在很多系统的acpica-tools里没有直接集成,通常需要从源码编译,或者用pmtools里的替代方案。
假设你已经编译好dmar_parse,执行方式很简单:
./dmar_parse DMAR.dat正常输出会像下面这样:
DMAR Parsing... RMRR found: base=0x00000000bf000000 end=0x00000000bf1fffff DRHD found: base=0x00000000fed90000 IOMMU supported Unit: 0 Flags: 0x0 Device Scope: PCI Bus 0, Device 2, Function 0解析结果会列出 DRHD(DMA Remapping Hardware Unit Definition)、RMRR、ATSR(Address Translation Services Reporting)等结构。重点关注DRHD的基地址和Device Scope,这是判断 IOMMU 和 PCIe 设备归属关系的关键信息。
3.3 手工解析 DMAR 表结构
有些情况下工具解析会失败,或者你想验证工具的输出是否靠谱,这时候就需要手工解析。
DMAR 表的结构其实不复杂,核心是表头加一串结构体。首先要看的是表头前 36 字节:
- 偏移 0 到 3:签名
"DMAR",如果这里不是44 4D 41 52,说明文件不对。 - 偏移 4 到 7:长度,整个表的总字节数。
- 偏移 8 到 9:修订号,常见是 1。
- 偏移 10 到 11:校验和,整个表所有字节相加取低 8 位,结果应为 0。
- 偏移 12 到 15:OEM ID,比如
LENOVO、DELL。 - 偏移 16 到 23:OEM Table ID 和 OEM Revision。
- 偏移 24 到 27:Creator ID 和 Creator Revision。
- 偏移 28 到 29:Host Address Width,表示系统物理地址宽度,常见值是 0x26(38 位)、0x2E(46 位)。
- 偏移 30 到 31:Flags,bit 0 表示是否有 INTR_REMAP。
- 偏移 32 开始:结构体数组,每个结构体开头第一个字节是类型,第二个字节是长度。
结构体类型对应关系:
| Type | 含义 |
|---|---|
| 0 | DRHD,DMA Remapping Hardware Unit Definition |
| 1 | RMRR,Reserved Memory Region Reporting |
| 2 | ATSR,Address Translation Services Reporting |
| 3 | RHSA,Remapping Hardware Status Affinity |
手工解析时,用xxd DMAR.dat | head -20先看前 64 字节,对照上面对应关系就能识别出结构体。后续的 Device Scope 结构嵌套在 DRHD 里,每个 Device Scope 结构是 2 字节头加变长数据,里面对应 PCI 设备的 Segment、Bus、Device、Function 编号。
4. 实战复盘:一次从 dmar.rar 到 VT-d 状态确认的完整流程
4.1 在 Linux 下快速确认 DMAR 表是否被正确加载
拿到dmar.rar里的文件之后,在目标机器上第一步不是立刻解包,而是先看当前系统有没有正确加载 DMAR 表。因为很多时候你处理的是离线备份,解出来的文件是要拿到现场机器上做对照的,而不是在本机解析完就完事。
我常用的检查命令:
dmesg | grep -i -E "DMAR|IOMMU|VT-d"正常情况下会看到类似输出:
DMAR: IOMMU enabled DMAR: DRHD base: 0x00000000fed90000 DMAR: IOMMU supported DMAR: ATSR flags: 0x0如果只有DMAR: IOMMU enabled而没有后续的 DRHD 信息,或者直接提示DMAR: DRHD translation failure,那说明内核虽然找到了 DMAR 表,但表里的结构和实际硬件不匹配。
另一个检查入口是/sys/firmware/acpi/tables/:
ls -la /sys/firmware/acpi/tables/有DMAR文件说明固件把表传给了系统。如果你需要把它导出和 rar 里的文件做对比,直接:
sudo cp /sys/firmware/acpi/tables/DMAR /tmp/DMAR_now.dat sha256sum /tmp/DMAR_now.dat再和 rar 里的原始文件做哈希对比。这个对比能快速判断:你手里的dmar.rar是不是就是当前这台机器上的那份。
4.2 用 RMRR 定位一个 DMA 重映射实际问题
去年有一个实际案例:一台服务器做 PCIe 网卡直通,虚拟机一启动就报 DMA 错误,但格式上看起来一切正常,IOMMU 也开了。
排查时我先dmesg看到 DMAR 表正常加载,然后用上面的方法导出当前系统 DMAR 表,和故障前备份的dmar.rar解出来的DMAR.dat做对比,发现两者完全一致。唯一可疑的点是 RMRR 区域大小只有 2MB,而网卡固件需要的 DMA 区域正好跨过了这个边界。
这个问题的根因在 RMRR:设备 DMA 时访问的地址被限定在保留区域内,区域配置不够就会在访问边界外时触发错误。而 RMRR 是固件在 DMAR 表里写死的,你没法在操作系统层面改它,只能通过更新 BIOS 固件来修正。
这个案例说明了一件事:dmar.rar里的表文件不是拿来直接“用”的,它是排查问题时的基准。遇到 VT-d 相关故障,第一件事就是把当前系统的 DMAR 表和备份的 DMAR 表做逐字节对比,确认故障是和固件版本变化有关,还是单纯配置问题。
5. 这些坑我替你踩过了:dmar 文件直接存储的常见翻车点
5.1 压缩包里的文件与当前系统版本不匹配
不要以为 BIOS 更新过之后,之前的 dmar 备份还能直接用。有些主板更新 BIOS 后会改 ACPI 表的内容,特别是设备作用域的 PCI 总线编号会变。如果你拿旧的 dmar 文件去分析新系统的 IOMMU 状态,结论完全可能是错的。
我现在的习惯是 RAR 备份命名时一定会带上固件版本号,比如dmar_F2.3_20240115.rar,同时把dmidecode -t bios的输出存成一个文本文件丢进包里。这样以后回看时能一眼知道这份表对应哪个固件版本。
5.2 直接存储的路径问题:中文目录与特殊字符
“直接存储”这个操作,有时会让文件名里混入中文目录和空格。我自己就吃过亏:把 dmar 文件存放的目录命名为服务器数据/最终版(新)/,后来用脚本批量解析时路径中有空格和全角括号,shell 脚本直接炸了。
建议所有 ACPI 表相关文件的父目录全部用英文、数字、下划线,不要用空格、中文括号、特殊符号。这纯属血的教训,但越是简单的事越容易在紧急时被忽略。
5.3 备份时别只存一个 RAR:哈希值才是护身符
如果你是这个压缩包的“生产者”,在制作dmar.rar时,我有一个强烈建议:把哈希文件放到压缩包外面,和压缩包并列存在。因为一旦整个 RAR 文件损坏,包内的sha256sums.txt也会一并失效,你照样无法判断损坏发生在传输前还是传输后。
所以我的标准做法是,在打包目录下执行:
sha256sum DMAR.dat acpidump.dat > sha256sums.txt rar a dmar_$(date +%Y%m%d).rar DMAR.dat acpidump.dat sha256sums.txt cp sha256sums.txt dmar_$(date +%Y%m%d)_SHA256.txt这样即使 RAR 包损坏,外部那个_SHA256.txt依然可以作为校验基准。很多“直接存储”的包根本没有这层保护,导致后面所有分析都建立在不完整数据上,排查方向从一开始就是错的。
5.4 解压 RAR 时的编码问题
RAR 文件在 Linux 下用unrar解压时,偶尔会遇到文件名乱码的问题。这不是文件损坏,而是因为 RAR 压缩包里的文件名编码是 GBK,系统默认 UTF-8 解码不对。尤其是那种从 Windows 服务器用 WinRAR 直接打出来的包,文件名里有中文的话,在 Linux 下解压后目录名直接变成乱码。
处理办法是解压后立刻用convmv转换文件名编码:
convmv -f gbk -t utf-8 --notest -r .如果不关心文件名只关心文件内容,也可以在解压时就只解文件、不解目录结构:
unrar e dmar.rar但我不建议经常这么做,因为 DMAR 相关的多个文件往往有逻辑关联,平铺解压容易丢失分组信息。先修正编码再完整解压,才是稳妥路线。
6. 说一点我现在的习惯
我现在的习惯是,不管是自己导出的 ACPI 表,还是从网上或者同事手里拿到的 dmar 类压缩包,第一动作永远是先算哈希并记录时间戳,再谈解析。这种二进制的固件表文件,真的不是拿来“读”的,而是拿来“比对”的:和当前系统的表现做对比,和故障前后的状态做对比,和不同固件版本之间的差异做对比。没有校验基准,这些对比全都没有意义。
如果你看完这篇,回头也去翻了翻自己硬盘里那个dmar.rar_直接存储,我建议顺手做三件事:一是把压缩包复制一份到正规备份盘里,别让唯一的副本躺在下载目录里;二是解压后配一个README.txt,写上来源机器、导出时间、固件版本号,哪怕只有一行字,一个月后你都会感谢自己;三是如果包里有 DMAR.dat,用它去对比一下当前系统的/sys/firmware/acpi/tables/DMAR,看看你的固件在不知不觉间已经变了多少。有时候,一份看着没什么用的“直接存储”文件,反而能帮你解释一个困扰很久的疑难杂症。
本文还有配套的精品资源,点击获取