十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

裸金属服务器UEFI自检工具:21项硬件测试一键出报告

裸金属服务器UEFI自检工具:21项硬件测试一键出报告 裸金属服务器的硬件排查说多了都是泪。手头没有带外管理系统或者BMC还没配好网段的时候突然来一台点不亮、装系统装到一半蓝屏、跑着跑着重启的机器你只能守着显示器插U盘、敲命令、一遍一遍看POST卡在哪个代码。所以我写了这个跑在UEFI环境里的整机自检工具不需要进系统不依赖操作系统启动就是图形界面21项硬件测试逐项跑全部执行完自动把结果写成报告。这篇博文就把它怎么设计、怎么实现、怎么在裸机上真正用起来一次说清楚。适合所有做服务器维护、机房交付、硬件测试和折腾DIY装机的朋友尤其是被“玄学硬件故障”折磨过的人。1. 为什么不用现成工具而要自己写一个UEFI自检程序先说清楚背景。市面上不是没有硬件检测工具但很多都是跑在Windows或者Linux里的。问题是裸金属服务器最常见的故障场景恰恰是“系统还没装好”“系统起不来”“系统不稳定”这时候你需要的是一个不依赖磁盘、不依赖操作系统的检测手段。BIOS和UEFI固件自带的POST信息太原始很多故障只会导致蜂鸣器叫几声或者屏幕黑一下你根本不知道是哪根内存条出了问题。传统做法是抱一堆替换件去试费时间还容易把机房搞乱。1.1 裸金属排查场景的实际需求我在实际维护里遇到的典型场景大概有三类。第一类是收到一批二手服务器节点能不能点亮、硬件是否完整需要快速摸底第二类是已经上架的机器出现随机重启、MCE报错但业务系统不能随便停只能用可引导的U盘在做维护窗口时跑一轮检测第三类是装机测试新到的整机要在交付前做稳定性验证。这三个场景有一个共同特点检测工具必须跑在操作系统之前。只有这样才能绕过驱动、内核、文件系统的干扰直接对CPU、内存、PCIe设备、SMBIOS固件做最底层的访问。所以我的思路就是做成一枚可引导的UEFI应用程序插进USB口开机从U盘引导整个检测独立于任何现有系统。另一个痛点是现场可视化。机房维护人员不可能盯着串口终端去读日志真要碰上问题最好屏幕上能看到哪个模块红了、哪个模块绿了还有实时进度条。UEFI下虽然还没有完善的图形栈但有GOP协议Graphics Output Protocol我们可以直接操作framebuffer画界面。这就是“全程可视化”的技术基础。1.2 为什么选UEFI而不是Linux内存诊断盘或者FreeDOS有人会问你做一个精简Linux memtester smartctl不就行了完全可以但有几个问题。第一精简Linux内核本身有几百兆U盘启动慢而且在某些服务器主板上兼容性并不好特别是老旧的RAID卡和网卡内核起来之后驱动没加载根本认不到设备。第二Linux启动本身会初始化大量设备如果故障恰恰出在初始化阶段工具根本跑不到检测逻辑。UEFI应用程序的优势在于它直接运行在UEFI固件提供的运行时环境上设备访问通过固件协议完成比如用Block IO协议读盘、用Serial IO协议收发串口数据、用GOP协议显示图形。这样我们写的检测逻辑相对纯粹可以集中精力做硬件压力测试而不是先处理操作系统兼容性问题。在开发环境上我选择用TianoCore EDK2来构建因为UEFI规范本身就是Intel主导推动的EDK2是事实上的参考实现。它提供了一整套开发库包括Shell库、Protocol接口封装、常用数据结构定义。用C语言开发代码量可控而且能编译出X64平台的.efi文件直接放进FAT32分区的U盘就能启动。2. 21项测试是怎么设计的覆盖“整机”而不是拆开单测最初我也考虑过只做内存测试和CPU整数运算测试但很快发现不够用。裸金属故障往往不是单一部件问题而是一个故障引发多个部件异常。比如内存有位翻转可能导致CPU缓存一致性报错也可能导致NVMe控制器DMA失败。所以工具的设计思路是“分层探测、逐项测压、汇总归因”。整个自检体系分成六个大类一共21项测试。启动时先读取SMBIOS信息把主板型号、BIOS版本、CPU型号、内存条容量、硬盘型号等基础信息展示在屏幕上然后逐项开始压力测试。2.1 测试清单和分类逻辑CPU性能与稳定性测试CPU多线程整数运算、浮点运算、缓存带宽测试内存测试地址线测试、数据线测试、随机翻转测试、全内存压力测试存储测试SATA/NVMe设备枚举、SMART健康状态读取、顺序读写测试、随机读写测试外设接口测试USB控制器枚举、USB存储读写、串口环路测试、网卡基础寄存器读写平台总线测试PCIe设备枚举与链路状态、ACPI表完整性、RTC实时时钟走时、CMOS读写固件与显示测试SMBIOS结构校验、GOP显示模式切换、帧缓冲读写回读每类测试并不是简单的“通过/不通过”而是分成三个等级信息采集、功能检查、压力测试。比如内存项目里地址线测试是功能检查随机翻转测试已经带有一定压力最后第四遍全内存写入0x5A/0xA5模式并回读才算真正的压力测试。在压力策略上我参考了MemTest86的做法但不是无脑循环。默认执行一轮完整测试共21项如果用户选择“快速模式”只跑信息采集和功能检查两类大约15秒钟就能出结果适合批量装机快速筛选如果选择“老化模式”内存压力测试和CPU浮点测试会循环60分钟适合新机稳定性验收。2.2 关键测试的原理与参数内存地址线测试的原理是这样的假设系统有4GB内存我们需要验证从地址0到最高地址之间的所有地址线能否独立被访问。方法是在某条地址线对应的高低位地址写入不同的值再回读如果两条地址线发生短路写入的值就会互相干扰。具体实现里我对每一根地址线依次设置0x01和0x00的pattern然后马上从相邻地址读回比对是否一致。因为只是地址范围的探测并不需要填满全部内存所以这个测试一秒钟就能完成。数据线测试则更直观。以64位总线为例我依次写入0x0000000000000001、0x0000000000000002这些单bit数据再写入0xFFFFFFFFFFFFFFFF整体反转值分别检查数据线上的每一位是否正常。如果回读的值出现了错位比如写入0x01读到0x00说明数据线存在短路或者开路马上把出错的地址和期望值显示到日志区。存储测试里最容易踩坑的是NVMe顺序读写的参数选择。我做过对比4KB小块随机读写的压力比1MB大块顺序读写大得多但测试时间也长得多。工具默认先做1MB大块顺序写读各64MB再做4KB随机写读各16MB。对于企业级NVMe盘这个量级已经能暴露大部分固件问题又不至于像全盘读写那样耗掉几个小时的寿命。SATA盘则额外增加一个SMART属性读取重点关注05重新分配扇区计数、C5当前待映射扇区、C6离线不可修复扇区这三项。RTC测试看起来简单其实容易忽略。我让RTC从当前时间开始计时5秒然后读回时间计算偏差允许误差在1秒以内。曾经碰到一台机器所有大项都通过但RTC每天快40秒导致NTP总是同步失败最终就是靠这项测试揪出来的。3. 工程实现从EDK2环境搭建到图形界面与报告生成技术路线定了之后开发过程其实比想象中顺利但也确实有不少坑。下面说一下工程实现上的关键环节包括怎么搭建编译环境、怎么画图形界面、怎么把报告写出去。3.1 开发环境和构建流程我用的主机是Ubuntu 22.04安装EDK2的方式很简单直接克隆TianoCore的源码仓库然后配置编译环境。EDK2自带了一个叫.edk2的环境文件配合build命令就能完成编译。git clone https://github.com/tianocore/edk2.git cd edk2 make -C BaseTools source edksetup.sh注意EDK2会依赖几个子模块库像MdePkg、MdeModulePkg这些虽然都是基础包但打开工程之前建议先同步git submodule update --init编译目标平台选X64。在OvmfPkg下面有专门的QEMU模拟平台我建议在裸机上跑之前先用QEMU加OVMF固件做一轮仿真验证不然每次都是往U盘里写、跑到机房大佬的机器上试错效率太低。build -a X64 -t GCC5 -p OvmfPkg/OvmfPkgX64.dsc这条命令会生成OVMF.fd固件文件以及我们应用App的HardwareDiag.efi。在QEMU里启动验证用到的启动参数大致如下qemu-system-x86_64 -bios OVMF.fd -hda fat:rw:./efi-disk3.2 用GOP协议实现可视化界面UEFI的图形界面并没有像Windows那样的窗口系统和字体库一切都要自己来。我的做法是在程序启动时调用gST-ConOut和gST-ConsoleOutHandle来获取当前的输出模式然后通过Graphics Output Protocol拿到底层framebuffer的地址和像素格式。GraphicsOutputProtocol NULL; Status gBS-LocateProtocol( gEfiGraphicsOutputProtocolGuid, NULL, (VOID**)GraphicsOutputProtocol );拿到framebuffer指针后就可以直接按像素点绘制矩形、进度条、文字。字体这块是最麻烦的部分EDK2的gST-ConOut-OutputString只能在文本模式下输出而我们用的是图形模式字体就会被隐藏。我内置了一个16x16的ASCII码点阵字库把常用字符的bitmap存成数组显示时按像素遍历复制到framebuffer里。进度条的绘制相对简单。我把屏幕下方800x40像素的区域用作总进度条每一项测试内部再有一个小进度条比如内存测试的进度是按已测试内存块数来计算的。当某一项测试失败时把该项状态栏从绿色改为红色同时测试结束后弹出对话框列出失败项。整个图形界面的更新频率我控制在20Hz左右避免频繁操作framebuffer导致显示闪烁。其实GOP接口并不保证100%硬件加速很多服务器主板的显示实现很简陋帧缓存在显存里从CPU写数据的效率并不高。实测下来20Hz完全是可接受的反而把频率调太高会出现画面撕裂。3.3 报告生成文本格式和保存路径一键出报告是本工具的核心功能。报告我选择了纯文本格式而不是JSON或者HTML因为机房环境里你永远不知道接下来要用什么软件打开报告。纯文本用记事本都能看方便直接复制粘贴到工单系统或者发给远程的同事。报告内容包括以下模块机器身份信息主板厂家、产品型号、序列号、BIOS版本、BMC版本如果SMBIOS里有CPU信息型号、物理核心数、线程数、当前频率、支持的指令集内存信息内存条数量、每条容量、最大容量、内存速率每项测试的执行结果包括测试名称、状态、执行耗时、详细错误信息整体结论通过/失败失败项按严重程度排序报告保存到哪里这个设计我做过多轮权衡。最直观的方案是写进FAT32的U盘因为我们在UEFI下运行可以通过Block IO协议找到自己所在的启动卷直接在根目录下新建一个HWDiagReport_YYYYMMDD_HHMMSS.txt文件。这要求启动U盘是FAT32格式NTFS在UEFI下默认不可写exFAT也依赖第三方驱动。另外一个重要输出通道是串口。数据中心服务器通常带COM口机房里面也有串口服务器。每次测试结束后工具会把同样内容的报告通过Serial IO协议从COM1输出。这对于没有接显示器的远程机房场景特别有用维护人员只要接上串口线就能拿到结果。写文件的代码核心是构建一个EFI_FILE_HANDLE然后调用WriteFile接口。需要注意编码问题UEFI的文件系统接口默认处理的是UCS-2字符而我们生成的是ASCII的文本所以写入时要做一次简单的转换否则报告里中文和特殊符号会乱码。因为我只写ASCII字符所以主要是控制每个字符的长度转成UCS-2的CHAR16数组。EFI_FILE_PROTOCOL *RootFs NULL; VolumeHandle NULL; Status gBS-HandleProtocol( DeviceHandle, gEfiSimpleFileSystemProtocolGuid, (VOID **)RootFs ); RootFs-Open( RootFs, FileHandle, L\\HWDiagReport.txt, EFI_FILE_MODE_CREATE | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_READ, 0 );4. 在裸机上跑通全流程一步步来写完之后我拿一台型号比较老的Supermicro服务器做了实测。这台机器的问题症状是偶尔开机不自检、内存单通道只有一半容量被识别一直怀疑是CPU底座接触不良但不好确认。下面记录一下实际跑的完整过程。4.1 制作启动U盘制作U盘我用的是Rufus格式选FAT32分区类型选GPT目标系统UEFI。其实也可以用命令行完成在Linux主机上把分区格式化为FAT32之后直接把HardwareDiag.efi拷贝到U盘根目录再新建一个/EFI/BOOT/目录把efi文件重命名为BOOTX64.EFI放进去。$ sudo mkfs.vfat -F 32 /dev/sdb1 $ sudo mount /dev/sdb1 /mnt $ sudo mkdir -p /mnt/EFI/BOOT $ sudo cp HardwareDiag.efi /mnt/EFI/BOOT/BOOTX64.EFI $ sudo umount /mnt之所以必须重命名为BOOTX64.EFI是因为UEFI固件在从U盘启动时默认查找的路径就是\EFI\BOOT\BOOTX64.EFI。如果你用NVRAM引导项那还可以自定义路径但对于排查用的U盘我们要做的是“插上就能启动”而不是依赖已有的引导配置。Secure Boot的问题放到下一节统一说先提醒一句如果你的机器启用了Secure Boot编译出来的.efi没有签名会被固件拒载。测试这台机器我先把Secure Boot关闭了。4.2 执行自检与观察要点插入U盘开机按F11进入引导菜单选择U盘设备机器很快进入我们自己写的图形界面。第一屏是硬件信息概览我看到SMBIOS里显示内存总量是64GB但工具枚举出的内存条只有一条32GB说明第二根内存没被识别和之前BIOS里的现象一致。接着点击“开始测试”。工具先快速执行CPU和内存的基础测试然后进入内存压力测试。为了模拟故障我在屏幕上盯着进度条大概跑到37%的时候日志区突然跳出一条错误数据线测试失败期望值0x0000000000000005实际值0x0000000000000001。这个错误信息非常具体直接指到了地址线和数据线交叉区域的某一位。因为我做的地址线测试会构造一个回环模式如果某一位数据线短路到地写入的值会被拉低。看到这个错误我就更怀疑是CPU和内存之间的信号完整性出了问题。最后关机重新插拔CPU重新涂硅脂再次测试内存压力测试完整跑过21项全部通过。整个测试过程大约耗时9分半钟其中内存压力测试占了大头7分钟CPU浮点运算占1分钟存储读写和其余项目只占1分半钟。结束后报告文件自动写入U盘根目录屏幕上也弹出了汇总结果。4.3 怎么读报告里的关键信息报告文件打开后重点看两个地方。一是Summary段它会列出“总测试项21、通过21、失败0、警告2”。警告项不一定是硬件问题比如温度传感器读取到42度、风扇转速为0这可能是某些被动散热主板的正常现象但也会记录下来供人工判断。二是查找FAILED关键字如果存在失败项报告会在失败条目下面打印详细错误。之前那台机器测试失败时报告里除了指出具体地址还会建议“尝试重新安装内存条或检查CPU socket针脚”。这些建议是我在代码里预置的“专家规则”根据不同的失败组合给出。报告中的硬件信息部分也非常有用因为很多机器连标签都没有只能靠SMBIOS里的序列号去资产管理数据库里查。工具每轮测试都会把完整的SMBIOS view dump下来这相当于顺手干了一件资产盘点的事。5. 踩坑记录与问题排查速查表这个工具从v0.1到现在的稳定版本我踩了不少坑。挑几个典型的记录下来希望能帮到想做UEFI自检工具的人。5.1 Secure Boot把工具拦下来怎么办服务器出厂默认一般都开启Secure Boot。自研工具没有微软签名也没钱买签名证书所以最直接的办法是进BIOS设置里把Secure Boot模式从Standard切换为Setup或Custom并清空Platform Key。不同主板的操作路径不一样Dell是在System Security菜单下SuperMicro是在Security Secure Boot。需要提醒的是如果这台机器需要跑Windows 11或者某些对Secure Boot强制要求的Linux发行版检测完最好把Secure Boot恢复原状并重新安装Platform Key。我们做运维的不能为了方便自己而破坏了生产机器的安全基线。5.2 有些主板不支持UEFI引导怎么办这就是热搜里常被问到的问题其实老一代服务器主板可能连UEFI都不支持或者只支持Legacy/BIOS引导。遇到这种机器UEFI工具就彻底没法直接启动。我的解决办法是把自检工具编译成一个EFI shell下的程序配合UEFI Shell启动盘先进入Shell.efi然后手动加载工具。如果主板连UEFI Boot都不认得那我建议使用IPMI的SOL串口重定向或者直接用烧录器备份固件。但这个操作风险很高普通维护场景不推荐。更实际的做法是先用这枚U盘在一台正常工作的UEFI机器上生成基础报告确认工具本身没问题再拿到目标机器上通过带外方式观察POST是否正常。5.3 内存测试的时间怎么控制内存测试是最耗时的一项尤其对于大容量机器。默认的全内存压力测试在64GB机器上大约7分钟但如果到了256GB甚至512GB时间会线性增长可能接近半小时。这在批量交付场景里太慢了。我在参数设计上做了两个优化。一是默认的“快速模式”只做地址线和数据线测试不做全内存0x5A/0xA5回写二是“老化模式”里全内存压力测试的次数默认是5轮但支持传入参数改成2轮。实际使用中我建议新机器做一轮完整老化模式机器已经跑过半年以上的做快速模式就够了没必要每次都花半小时。5.4 图形界面在部分主板上花屏UEFI的GOP实现并不统一。有的服务器主板集成显卡只能支持最小分辨率比如1024x768而我们的界面设计是按1920x1080来的。如果直接操作framebuffer按固定坐标绘制画面就会出现花屏或显示不全。解决方法是启动时查询GraphicsOutputProtocol-Mode获取当前分辨率然后所有控件都基于这个分辨率做等比例缩放。具体实现里我定义坐标都是相对于屏幕宽高的百分比而非像素绝对值。比如进度条固定在屏幕宽度80%、高度90%的位置。这样做之后在VGA、集成显卡和独立显卡上都表现一致。5.5 一张速查表方便排查时对照现象可能原因排查方向UEFI启动后黑屏Secure Boot开启进入Setup模式或清空PK内存测试随机报某个地址错误内存接触或地址线故障重插内存替换内存条测试NVMe读取测试反复超时NVMe掉盘或供电不足检查电源线和M.2槽位报告文件没有写入U盘U盘分区为NTFS/exFAT重新格式化为FAT32图形界面花屏但测试正常GOP分辨率不兼容修改控件为百分比坐标Serial串口没有输出BMC占用COM1检查BIOS串口重定向设置或换COM2纯文本报告中文乱码UEFI文件系统编码不匹配只用ASCII字符或统一转UCS-2结尾说点实在的我在实测中最大的体会是裸金属硬件排障工具的价值不在于单项测试有多专业而在于把它整合成一个开箱即用的“体检仪”。21项测试哪一项单独拿出来都有现成方案但能把它们串在UEFI环境里、用图形化界面呈现、最后一键出报告这个体验才是刚需。最后分享一个扩展思路这枚U盘完全可以做成一个双启动盘一半放自检工具一半放批量装机用的自动化脚本。机器先跑一遍自检确认无故障再进入装机流程一套流程下来比原来先装机后测试要省不少时间。我已经在自己的维护流程里这么干了效果还不错。如果你也遇到类似的硬件玄学问题不妨按这个思路封装一个属于你自己的UEFI自检工具。
返回列表