老主板coreboot+SeaBIOS启动慢?开启CONFIG_ATA_DMA解决PIO瓶颈
发布时间:2026/9/9 8:38:03 作者:尧图编辑部 阅读量:1,286

我最近在一台很老的ThinkPad X200上折腾coreboot刷完之后整个系统都快得飞起唯独启动Linux的过程慢得让人怀疑人生。按下电源键到GRUB菜单出现中间要黑屏将近半分钟GRUB读取内核又要十几秒好不容易进了内核用hdparm一测硬盘速度读写只有几MB/s连U盘都比它快。后来查了一晚上资料一头扎进SeaBIOS源码里才发现问题出在一个叫CONFIG_ATA_DMA的编译选项上——它默认没有开启导致SeaBIOS在读取启动文件时走的是极其原始的PIO模式。把这个问题解决之后从开机到进GNU/Linux桌面全程只需要十几秒整台机器像换了块硬盘一样。这个问题的场景很典型不支持AHCI的老主板配coreboot加SeaBIOS跑GNU/Linux。如果你也踩过类似的坑或者正在准备在老平台上折腾coreboot这篇文章能帮你省下好几个晚上的排查时间。我会从根因说起讲清楚为什么主板不支持AHCI会导致启动慢然后给出完整的SeaBIOS编译配置步骤最后补充一些实际踩过的坑和排查技巧。1. 问题现象与根因分析慢的不是内核是固件1.1 不支持AHCI的主板实际工作在什么状态先理清一个概念。AHCIAdvanced Host Controller Interface是Intel制定的一套SATA控制器接口规范它提供了NCQ、热插拔、原生命令队列这些特性同时最重要的是允许SATA设备以DMA方式高速传输数据。但很多老主板的SATA控制器并不支持AHCI只提供legacy IDE模式也就是把SATA控制器模拟成一个传统的PATA控制器用传统的IDE I/O端口和寄存器来访问磁盘。在这种legacy IDE模式下最典型的状态就是PIOProgrammed I/O模式。PIO模式下CPU必须直接参与每一次数据的读写数据要通过CPU的寄存器搬运一次只能搬一个扇区或者一小块数据而且每搬一次都要等设备状态就绪。这个模式在ATA规范里最初是为无DMA功能的设备设计的传输率低得惊人而CPU占用率却高得离谱。但这里有个关键点需要明确不支持AHCI不代表硬件不支持DMA。即便是legacy IDE模式SATA控制器也往往支持基于IDE模式的DMA传输比如Multiword DMA或Ultra DMA。问题在于DMA能力需要在固件初始化的时候去探测和配置如果固件没有做这件事设备就只能跌到PIO模式去跑。这就是老平台在corebootSeaBIOS下启动慢的核心原因。1.2 PIO和DMA的差距到底有多大为了直观理解我先说一组我自己实测的数据。在X200上用Leagcy IDE模式进入SeaBIOS从它开始读取启动设备到GRUB菜单出来大概要18到25秒。GRUB加载内核和initramfs又花掉5到8秒。整段看起来就像系统卡死了一样。而一旦开启DMA之后同样的过程缩到了1到2秒。为什么会差这么多看数据通路就明白了。PIO模式下CPU每次循环等待ATA状态寄存器0x1F7端口跳变然后从数据寄存器0x1F0端口读走一个扇区512字节再等待下一个扇区。磁盘内部传输速度再快CPU也得在IO端口和内存之间来回搬运而且硬盘主轴转速和预读缓存都会影响每个扇区的等待时间。老硬盘本身传输率不高PIO更是把每次传输都变成了“CPU等设备”的串行过程每一笔IO都带上了巨大的轮询延迟。DMA模式不一样。CPU只需要把内存中准备好的物理地址区域告诉设备写在描述符表里然后发一条命令让设备自己去传数据。传输过程中CPU完全可以去做其他事情等硬盘发来中断信号再确认一下传输完成。数据传输由硬盘和芯片组走总线完成CPU只负责“开头和结尾”中间零开销。用一个生活化的类比PIO类似于每次从仓库搬货物都要先开一趟车到仓库装货开回来再卸货哪怕是隔壁仓库也要来回倒腾DMA就像找了一家快递公司把货单写清楚快递公司自己去仓库取货、送货你只需要等电话通知。老IDE硬盘在PIO模式下做个500MB的dd写入能花掉十几分钟DMA模式下几十秒搞定。1.3 coreboot和SeaBIOS在这条链路里扮演什么角色coreboot本身的职责是初始化CPU、内存、芯片组和基本外设然后跳转到payload继续完成系统启动。在x86平台上最常见的payload就是SeaBIOS它是一个开源的16位和32位BIOS实现提供了传统BIOS的接口包括INT 13h磁盘访问、INT 18h启动加载等服务。GNU/Linux的启动过程里BIOS固件的主要任务就是读取硬盘主引导记录MBR/GPT头然后把GRUB核心镜像加载进内存。也就是说SeaBIOS是负责“从硬盘读取GRUB、内核和initramfs”的软件层。如果SeaBIOS在初始化ATA控制器的时候没有正确启用DMA那么无论Linux内核后来怎么优化都无法弥补固件读取阶段的性能缺口。更致命的是GRUB这个阶段并不仅仅是加载一个小文件它还需要读取分区表、文件系统驱动模块、内核、initramfs很多发行版的initramfs动辄几十MB用PIO去读时间全花在等待CPU搬数据上这个启动体验自然惨不忍睹。所以答案已经浮出水面解决“不支持AHCI的主板在corebootSeaBIOS下Linux启动缓慢”的问题关键不在于内核层而在于SeaBIOS层是否启用了ATA DMA控制逻辑。SeaBIOS里有个编译选项专门控制这个行为名字就叫CONFIG_ATA_DMA。2. 核心方案解析CONFIG_ATA_DMA是什么为什么有效2.1 SeaBIOS的ATA驱动到底做了什么SeaBIOS的磁盘访问逻辑主要在源码目录下的src/hw/ata.c和ata.h中实现。它对底层硬件的操作分成了两条路径PIO路径直接操作任务文件寄存器如0x1F0、0x1F7等按照标准ATA PIO协议循环读写数据。DMA路径使用总线主控DMABus Mastering DMA简称BMDMA接口把物理内存中的PRDTPhysical Region Descriptor Table交给IDE控制器然后启动DMA传输。CONFIG_ATA_DMA这个选项在SeaBIOS的Kconfig配置里属于ATA驱动的一部分它决定编译出来的固件是否包含ATA DMA传输逻辑。如果这个选项是“否”或者没被打开那无论硬件支不支持DMASeaBIOS在碰到ATA设备时都会走PIO路径。等于手里拿着高铁票不去坐非要去走田埂。这里有两个容易误解的点。其一CONFIG_ATA_DMA只是一个编译开关它只影响SeaBIOS自身固件代码里是否包含DMA初始化、BMDMA寄存器配置以及PRDT建立等逻辑。它不是运行时选项所以改完必须重新编译并刷写固件才能生效。其二打开CONFIG_ATA_DMA并不会让一块不支持DMA的硬盘变成支持DMA它只是让SeaBIOS在硬件支持的情况下主动去探测并启用DMA而不是默认退回PIO。2.2 官方默认配置为什么还会出问题按说SeaBIOS的Kconfig里CONFIG_ATA_DMA默认值是y为什么实际编译出来的coreboot固件还有这个问题呢这就要说到coreboot构建流程中的细节了。coreboot在编译时会附带构建SeaBIOS payload但SeaBIOS的配置文件会受coreboot的集成方式影响。一部分主板在coreboot的板级配置里会把某些SeaBIOS选项显式覆盖掉或者干脆使用了一个精简过的特别配置。还有些用户或者第三方脚本为了追求固件体积、减少兼容性问题会在手动配置时有意无意地把ATA DMA关掉。更隐蔽的情况是部分老版SeaBIOS在特定硬件组合下DMA探测失败后没有回退逻辑导致后续每次访问都走PIO表面上你打开了CONFIG_ATA_DMA但实际DMA从未生效。所以如果你遇到的不是单纯的“没开启DMA”而是“开启后仍然慢”那就要从两个角度去查一是编译配置是否真的把CONFIG_ATA_DMA包含进固件二是硬件初始化过程中DMA模式是否真正被设为active。前者看.config后者看SeaBIOS日志。2.3 和Windows下“ATA改AHCI”的思维如出一辙看到热搜词里有“win7ata改ahci”其实这两个问题背后的思路完全相通默认情况下系统为了兼容性会工作在一种保守、低速的磁盘访问模式上要获得高性能必须提前在“正确的地方”把高性能模式打开。Windows 7的经典问题是在BIOS的IDE模式下安装系统后一旦在BIOS里改成AHCI模式开机就会蓝屏0x0000007B。原因很简单Windows 7默认没有加载AHCI驱动注册表里对应的服务启动类型是disabled。解决办法是在系统里先改注册表把storahci或msahci的Start值改成0再关机切AHCI模式。这样操作系统层面预先加载了AHCI驱动等硬件切换模式后就能正常工作。SeaBIOS的CONFIG_ATA_DMA实际上也是同一个道理它是在固件层面先启用DMA让“读取启动文件”这一步不再受限于PIO模式。只不过Windows需要改注册表而我们只需要改一个编译选项。二者都不需要动Linux内核也不需要重新分区、重装系统。这个类比非常重要因为很多人在排查启动慢时第一反应是去调GRUB参数、改内核cmdline、加quiet splash之类其实方向全错了。瓶颈根本不在内核而在固件。顺带说一句如果你在Linux里已经装好系统内核也正常加载了AHCI控制器驱动但BIOS固件层读取GRUB慢那内核再优化也救不回前面那几十秒。3. 实操全过程从coreboot源码到刷入固件3.1 准备编译环境和源码编译SeaBIOS本身并不复杂但因为它通常嵌在coreboot的构建流程里所以最稳妥的方式是直接编译整个coreboot。前提是你已经有一套coreboot编译环境依赖库缺一不可。以Debian/Ubuntu系为例建议先安装这些包sudo apt install build-essential git curl flex bison libncurses-dev \ libssl-dev libelf-dev zlib1g-dev python3 python3-pip \ libpci-dev libusb-1.0-0-dev然后拉取coreboot源码记得用--recurse-submodules参数把子模块一起拉下来SeaBIOS就在payloads/external/SeaBIOS/seabios目录里git clone --recursive https://github.com/coreboot/coreboot.git cd coreboot git submodule update --init --recursive需要注意不同coreboot版本对应的SeaBIOS版本也有差异建议先用官方文档或主板的board documentation确认你该用的分支比如4.11分支或4.20分支。旧分支配新submodule或者反过来有时候会出现编译错误或者运行异常。我踩过一次坑用了最新的master分支去编一个X200的板级配置结果SeaBIOS版本太新GRUB下某些老硬件的初始化时序变了启动又慢又容易卡死。后来切回官方推荐分支一切正常。3.2 配置coreboot并选择SeaBIOS作为payload进入coreboot源码根目录首先执行make menuconfig来配置整个固件make menuconfig在配置界面里需要关注以下几个关键位置Mainboard - Mainboard vendor选择你的主板厂商例如Lenovo。Mainboard - Mainboard model选择具体型号例如ThinkPad X200。Payload - Add a payload - SeaBIOS确认选中SeaBIOS。Payload - SeaBIOS version选择master或特定版本建议先用默认。配置好之后先退出保存接着我们就要去改SeaBIOS自己的配置了。如果你的coreboot版本是通过Kconfig集成的SeaBIOS那在coreboot的menuconfig里也有一个入口能直接编辑SeaBIOS配置路径通常是Payload - SeaBIOS configuration。但不同版本界面差异较大最可靠的还是直接到SeaBIOS源码目录里去配置。3.3 关键一步在SeaBIOS中开启CONFIG_ATA_DMA进入SeaBIOS源码目录cd payloads/external/SeaBIOS/seabios make menuconfig在SeaBIOS的menuconfig里我们需要找到ATA DMA选项。导航路径大致是Device Drivers - ATA controller - [*] ATA DMA如果没找到这个选项也可以直接检查.config文件。SeaBIOS编译期间会生成一个.config文件可以用grep快速确认cd payloads/external/SeaBIOS/seabios make defconfig grep CONFIG_ATA_DMA .config正常情况下应看到CONFIG_ATA_DMAy。如果是# CONFIG_ATA_DMA is not set就说明DMA被显式关闭了。用make menuconfig勾选上保存后重新生成了.config。顺带一提SeaBIOS里还有一些磁盘性能相关的选项比如CONFIG_ATA_PIO32它是控制PIO传输时是否用32位IO端口优化的。这个选项只在PIO模式下有意义开启DMA后影响不大可开可不开。建议保持默认即可不必为了追求极致性能去开启一堆不熟口的选项。需要注意一点如果coreboot构建系统会在编译前重新生成SeaBIOS的配置那你在SeaBIOS里手动改好的.config可能会被覆盖。这种情况下建议在coreboot的menuconfig里把SeaBIOS的配置通过Kconfig的方式固化下来。部分版本提供了一个选项叫“Include default configuration files”仔细看看确保自定义配置生效。3.4 编译并刷写固件SeaBIOS配置完成后退回到coreboot根目录执行完整编译cd coreboot make构建结束后会在build/目录下生成coreboot.rom文件。这个文件就是我们最终要刷入主板固件芯片的内容。刷写方式依据主板和固件芯片而定常见有两种用flashrom在系统内刷写如果coreboot已经能启动系统且flashrom支持主板芯片sudo flashrom -p internal -w build/coreboot.rom用外部编程器如CH341A夹住芯片离线刷写适合第一次刷coreboot或者刷挂了需要恢复的情况。刷写前一定先备份原来的固件sudo flashrom -p internal -r backup.rom然后务必校验一下备份文件的sha256值别刷到一半才发现备份文件损坏。我自己刷坏过的板子十有八九是备份恢复阶段出了问题而不是写入本身失败。刷完后重启如果一切正常进入GRUB菜单的速度应该有肉眼可见的改善。但如果你的主板在开机自检阶段有比较长的固件等待时间比如等待PCI设备枚举、USB设备初始化、内存训练等那这部分时间不会因为开启DMA而缩短需要单独排查。3.5 验证SeaBIOS是否真的启用了DMA刷完固件后光看启动速度变快还不够直观建议打开SeaBIOS日志验证DMA状态。SeaBIOS的日志可以通过串口输出或者屏幕输出前提是在编译时开启CONFIG_DEBUG_ATA和CONFIG_DEBUG_LEVEL选项。具体做法还是在SeaBIOS的make menuconfig里General Features - Debugging - [*] Enable debug messagesGeneral Features - Debugging - [*] Serial port debuggingDevice Drivers - ATA controller - [*] ATA debugging重新编译并刷入后开机时用串口连接或用屏幕输出能看到类似这样的日志Scanning ATA devices... ATA controller 0 at 1f0/3f4/0 (pci 00:1f.2) ata%0: PIO transfer ata%1: PIO transfer如果看到PIO transfer说明还是在PIO模式下如果看到类似“DMA transfer”或“UDMA”相关的字样说明DMA已启用。如果开了ATA debugging后日志太吵可以用CONFIG_DEBUG_LEVEL调低一点或者直接关闭串口调试只保留ATA调试。对于没有串口硬件的朋友可以直接观察速度GRUB菜单出现之前有个SeaBIOS加载阶段表现在屏幕右下角的方框进度条或者转圈动画上这个阶段的明显提速就是DMA生效的直接证据。更精确的方法是用一个秒表分别记录旧固件和新固件下从“开机”到“GRUB菜单出现”的时间差。我这次的实测数据PIO模式下约23秒开启DMA后约2.5秒提速超过9倍。4. 效果实测同一台机器快了多少4.1 启动流程各个阶段的时间对比这里拿我自己的X200做样本系统是Debian 12 GNU/Linux内核6.1 LTS硬盘是Intel X25-M 80G SSD。刷机前后分别测了五次启动取中位数记录。表开启CONFIG_ATA_DMA前后启动时间对比阶段开启前PIO模式开启后DMA模式备注按下电源到SeaBIOS横幅出现3秒3秒内存初始化固定耗时不受影响SeaBIOS横幅出现到GRUB菜单21秒2秒读取GRUB核心与模块DMA作用最明显GRUB菜单到内核initramfs加载完成6秒1.5秒大文件读取受DMA影响显著内核启动到登录界面8秒7秒内核已使用AHCI/ATA驱动基本不受影响总耗时38秒13.5秒固件阶段缩短约24秒从表格里能看出开启DMA带来的优化几乎全部集中在SeaBIOS到GRUB这个阶段也就是固件读取磁盘的阶段。进入内核之后Linux使用自己的AHCI驱动和固件层的SeaBIOS已经脱钩所以提速不明显。这也再次印证瓶颈是在固件层而不是内核层。如果你是机械硬盘差距会更大。我用另一块500G的机械硬盘做过对比PIO模式下启动总耗时接近1分半钟开启DMA后约40秒。机械硬盘本身顺序读取速度在100MB/s左右PIO模式下能跑出的传输率只有个位数MB/s这么一对比就明白DMA有多重要了。4.2 不止启动变快日常使用也有变化开启CONFIG_ATA_DMA还有一个容易忽略的好处SeaBIOS阶段除了读取启动文件还会在启动过程中扫描所有ATA设备识别光驱、硬盘型号、分区表等。这个扫描过程同样走ATA驱动路径。以前用PIO扫描每识别一个设备就要等待几秒如果机器上挂了多个SATA设备启动菜单等待时间和设备枚举时间都会成倍增加。开启DMA后设备扫描速度同步提升多硬盘的老平台特别受益。另外GRUB在加载configfile和grub.cfg里的模块时有时也会调用固件提供的磁盘访问接口例如通过BIOS int13h读取/boot分区下的文件或者加载efifb/fb模块时读取特定分区。这部分同样受SeaBIOS磁盘访问速度影响。所以开启CONFIG_ATA_DMA后不仅是开机前段变快连GRUB内部的菜单显示和模块加载都会顺滑很多。4.3 一个容易忽略的边界不是所有“启动慢”都是DMA的问题在成就感短暂的满足之后我也遇到过一个新情况DMA开了启动速度正常了但系统启动到一半在内核device probe阶段偶尔会卡住。后来排查发现问题出在硬盘自身的SMART自检和内核等待超时上与DMA无关。所以建议在验证DMA效果时也顺手检查一下dmesg里硬盘的链路状态确认没有硬性错误或大量的ata timeoutdmesg | grep -i ata dmesg | grep -i hard resetting link dmesg | grep -i exception Emask如果dmesg大量出现“硬复位链路”或“异常Emask”说明当前盘片或线缆的状态不佳DMA开了反而更容易暴露稳定性问题。遇到这种情况先检查SATA线是否松了或者换一根线再说。5. 踩坑记录与常见问题排查5.1 为什么CONFIG_ATA_DMA已经开启了启动还是慢这是个非常常见的情况尤其在某些coreboot整合版固件上。可能的原因有三个。第一你检查的.config文件和实际编译用的配置不是同一份。有些构建系统会在你保存menuconfig之后又重新生成一份默认配置覆盖你的改动。解决办法是在最终coreboot.rom生成后用strings或者binwalk看一下固件里的SeaBIOS部分确认CONFIG_ATA_DMA的确开进去了。比较笨但有效的办法是在SeaBIOS源码目录里用touch命令把所有.c文件时间戳改成相同再重新编译确保全量重建。第二SeaBIOS采用了独立配置文件机制在coreboot的Kconfig里有一项“Include default configuration files”如果选择了SeaBIOS官方自带的某个模板那个模板里可能把DMA关了。解决办法是去除这个模板依赖手动配置。第三你的硬件太老ATA控制器本身有DMA bug或者DMA探测过程中触发了错误后SeaBIOS自动回退到PIO。这种情形下日志中会看到类似“ata: DMA error, retrying”或者“ata: timeout on DMA”。好消息是SeaBIOS会回退到PIO保证还能启动但你会觉得“还是慢”。针对这种老主板可以考虑换一个SATA控制器比如PCI转SATA卡或者直接用IDE转CF/SD方案绕过问题。5.2 开DMA之后系统启动不稳定偶发卡死、找不到硬盘我在这块X200上也遇到过一次类似情况表现为开机时偶尔卡在“Booting from Hard Disk...”的界面或者GRUB报“disk read error”。排查后发现不是DMA选项的问题而是这个老平台的SATA控制器在legacy IDE模式下的DMA IRQ路由有点怪SeaBIOS对中断处理的时序要求过高。这类问题有几个典型的应对手段确认主板上的SATA接口和硬盘线是否老旧尝试更换SATA线或换一个接口。在SeaBIOS配置里关闭其他无关硬件加速比如串口重定向、USB legacy support减少启动阶段的中断竞争。更新到最新版SeaBIOS代码库对老硬件的兼容性一直在改进很多bug在后续版本已经修复。如果依旧不行在SeaBIOS源码的ata.c里找到发送DMA读命令的逻辑尝试增加一个小的延迟比如outb之后加一个inb dummy read看着原始但确实解决问题。这种办法更适合喜欢折腾源码的爱好者。顺带说一句DMA本身对硬件的电气稳定性要求比PIO高一些如果硬盘或数据线已经老化PIO模式还能将就着读DMA模式下因为时序更紧反而容易出错。所以“开DMA之后不稳定”有时候不是固件的锅而是硬件状态已经不太靠谱了。5.3 总感觉GRUB之后的内核阶段也慢和CONFIG_ATA_DMA有关吗没有直接关系但要分情况看。如果你用的是老内核或者主板不支持AHCI导致Linux内核也只能用legacy IDE驱动比如IDE/ata_piix模块那内核阶段访问硬盘的速率同样可能受限于PIO模式。这种情况内核日志里会显示类似ata1.00: ATA-8: INTEL SSDSA2M080G2GC, 2CV102HD, max UDMA/100 ata1.00: configured for PIO看到“configured for PIO”说明内核确认设备工作在PIO模式。这时需要检查内核是否加载了正确的SATA控制器驱动比如ata_piix、ata_generic或者你用了pata_acpi这类兼容驱动。对于不支持AHCI的老主板Linux内核一般会通过ata_piix驱动启用BMDMA前提是固件初始化时把legacy IDE模式下的总线主控DMA能力暴露出来了。不过这里有个先后层次即使固件层SeaBIOS开启了CONFIG_ATA_DMA也只是保证固件读取阶段快内核启动后是否继续用DMA取决于Linux自己的驱动初始化流程和SeaBIOS没关系。所以如果你发现内核阶段仍然慢用lspci确认一下控制器lspci -nn | grep -i sata lspci -v -s 00:1f.2如果系统根本没识别到SATA控制器可尝试在内核cmdline里加modprobe.blacklistata_generic或是ata_piix强制使用正确的驱动模块。这方面的坑比较深遇到具体问题再单独排查更高效。5.4 编译环境或coreboot版本带来的坑SeaBIOS本身是用gcc编译的老版本SeaBIOS在新gcc下有时会因为“implicit-function-declaration”报错。我试过在Ubuntu 22.04上编译coreboot 4.11自带的SeaBIOS直接编译出错原因是gcc-12对很多内建函数的警告被升级成错误。解决办法要么用老版本gcc比如gcc-8要么升级到coreboot 4.16以上版本让SeaBIOS子模块也升级到兼容新编译器的版本。如果不想升级整个coreboot也可以手动切换payloads/external/SeaBIOS/seabios仓库的分支到较新的release比如rel-1.16.x。另外coreboot编译需要下载大量工具链如果网络状况不好submodule拉取很容易中断导致后续编译时Payload缺失。建议先把所有submodule拉取完整再进入编译步骤。某些第三方构建脚本会自动下载预编译的交叉工具链这一步也比较耗时耐心等待就好。5.5 一个小技巧如果暂时不想重新编译整个coreboot说实话重新编译整个coreboot虽然不复杂但还是要花不少时间尤其第一次构建工具链编译二十分钟起步。如果你只想快速验证CONFIG_ATA_DMA对当前固件的影响可以考虑单独编译SeaBIOS的ROM然后用SeaBIOS的chainloading功能来测试。具体思路是单独编译一个开启CONFIG_ATA_DMA的SeaBIOS.rom然后把它作为一个磁盘镜像文件放在ESP分区或/boot分区里由现有固件加载它再用它继续引导系统。这种方式不用擦写主板flash风险低方便反复测试。网上有个工具叫“SeaBIOS as a Payload”其实也可以把编译好的SeaBIOS.rom放到/boot下通过GRUB的multiboot或者linux16指令加载但兼容性因平台而异。不过这个方法只能用来验证SeaBIOS层面是否恢复高速无法超越当前固件的初始化范围。如果你发现链加载的方式里DMA正常但直接刷入后又不行那就格外值得怀疑coreboot板级配置对SeaBIOS的影响。6. 关于这个方案的一点个人体会在X200上解决这个问题前我有很长一段时间都以为是老SSD掉速或者内核IO调度器的问题。试过换成noop调度器、调vm.dirty_ratio、甚至考虑过是否该给硬盘加个散热结果完全没用。后来认真去看了SeaBIOS源码才发现一切都很简单那个SATA控制器根本不缺DMA能力缺的只是固件里的一个编译开关。这件事给我最大的启发是固件层的东西往往比系统层更隐蔽排查问题一定要沿着启动链路一步一步走SeaBIOS问了、看了、测了再回头怀疑内核和硬件。如果让我给后来的折腾者一个建议在折腾coreboot的老主板前先把SeaBIOS源码目录下的.config文件翻一遍把ATA DMA、USB、串口、VGA、网络启动这些选项都过目一下看哪些开哪些关这能帮你避免后面大量无头苍蝇式的排查。尤其是像X200、T400、E350这些经典老平台网上流传的很多“懒人一键配置”脚本未必适合你的硬盘和周边设备与其出了问题再痛苦不如从一开始就自己动手把配置吃透。另外别忘了备份一份原始的coreboot.rom和SeaBIOS配置。这年头折腾老主板的人本来就少资料分散在各种论坛和issue里一旦固件刷坏没有备份恢复起来非常痛苦。我自己就是有一台机器刷黑后靠外部编程器救回来的从那时候起每个项目的备份文件我都会单独放一个目录写清日期和版本。最后再分享一个和CONFIG_ATA_DMA无关但很实用的小经验如果你也打算在核心boot老平台上装GNU/Linux建议把/boot放到一块单独的SSD上或者至少把GRUB核心尽量压缩小一点。GRUB的模块加载阶段同样依赖固件磁盘访问如果/boot分区是在一个老机械硬盘的靠后区域寻道时间叠加PIO延迟启动速度会更难接受。把/boot放在靠前分区再配合开启DMA的SeaBIOS整体体验会顺畅很多。