简介在系统启动早期ACPI表为内核描述硬件拓扑与资源分配其中的DMARDMA重映射报告表是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 特性、中断路由、设备拓扑等信息。DMARDMA 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之类的错误。再比如说RMRRReserved 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 / .txtlspci -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: base0x00000000bf000000 end0x00000000bf1fffff DRHD found: base0x00000000fed90000 IOMMU supported Unit: 0 Flags: 0x0 Device Scope: PCI Bus 0, Device 2, Function 0解析结果会列出 DRHDDMA Remapping Hardware Unit Definition、RMRR、ATSRAddress 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 到 15OEM ID比如LENOVO、DELL。偏移 16 到 23OEM Table ID 和 OEM Revision。偏移 24 到 27Creator ID 和 Creator Revision。偏移 28 到 29Host Address Width表示系统物理地址宽度常见值是 0x2638 位、0x2E46 位。偏移 30 到 31Flagsbit 0 表示是否有 INTR_REMAP。偏移 32 开始结构体数组每个结构体开头第一个字节是类型第二个字节是长度。结构体类型对应关系Type含义0DRHDDMA Remapping Hardware Unit Definition1RMRRReserved Memory Region Reporting2ATSRAddress Translation Services Reporting3RHSARemapping 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看看你的固件在不知不觉间已经变了多少。有时候一份看着没什么用的“直接存储”文件反而能帮你解释一个困扰很久的疑难杂症。本文还有配套的精品资源点击获取