UEFI Shell作为现代计算机系统启动过程中的关键组件,提供了一个介于固件和操作系统之间的强大交互环境。与传统的BIOS界面相比,UEFI Shell不仅支持更丰富的硬件访问能力,还具备完整的脚本执行和应用程序运行功能。在硬件开发和测试领域,这种预操作系统环境的价值尤为突出——它允许工程师在操作系统加载前直接与硬件交互,进行底层诊断和验证。
我曾在多个硬件验证项目中深度使用UEFI Shell环境,最典型的案例是在某存储控制器开发过程中,通过Shell脚本实现了对NVMe SSD的自动化压力测试。相比传统方法需要在操作系统下运行测试工具,UEFI Shell方案将测试时间缩短了约40%,因为省去了操作系统加载和初始化过程。这种效率提升对于需要反复进行硬件验证的制造环节尤为重要。
提示:UEFI Shell 2.0是当前主流标准,相比早期的EFI Shell增加了标准化输出格式(-sfo)、命令查询等关键功能,建议新项目直接基于UEFI Shell 2.0开发。
UEFI Shell脚本文件通常以.nsh为扩展名,其语法类似于传统批处理脚本但具备更多硬件相关的特殊命令。一个完整的测试脚本应包含以下基本结构:
code复制# 示例:硬件健康检查脚本框架
@echo -off
set -v 1 # 启用详细日志
# 环境初始化
if not exist fs0:\logs mkdir fs0:\logs
set LOGFILE fs0:\logs\test_%date%_%time%.log
# 硬件检测流程
deviceinfo -sfo > %LOGFILE%
smbiosview -t 1 >> %LOGFILE%
# 条件判断与错误处理
if %lasterror% ne 0 then
echo "[ERROR] 硬件信息获取失败" >> %LOGFILE%
exit 1
endif
# 存储设备测试
for %d in fs0 fs1 fs2
if exist %d:\ then
storcli %d: -perf -count 100 >> %LOGFILE%
endif
endfor
关键控制流元素包括:
UEFI Shell提供了一系列针对硬件测试优化的命令:
| 命令类别 | 典型命令 | 功能描述 | 常用参数 |
|---|---|---|---|
| 设备信息 | deviceinfo | 列出所有设备句柄 | -sfo标准化输出 |
| drvdiag | 执行驱动诊断 | -c 指定检测项 | |
| 存储测试 | diskpart | 磁盘分区管理 | -list显示分区 |
| storcli | 存储性能测试 | -perf性能模式 | |
| 内存测试 | memtest | 内存完整性检查 | -a 测试范围 |
| 网络测试 | ifconfig | 网络接口配置 | -l 列出接口 |
| ping | 网络连通性测试 | -n 测试次数 |
在开发某服务器主板的测试脚本时,我们组合使用这些命令实现了自动化测试流水线:
code复制# 存储子系统验证流程
storcli fs0: -perf -count 500 -bs 4k
if %lasterror% == EfiError(3) then
echo "存储性能不达标" >> %LOGFILE%
set TEST_RESULT FAIL
endif
# 内存压力测试
memtest -a 0x100000000 0x200000000 -i 10
if %lasterror% ne 0 then
echo "内存测试失败" >> %LOGFILE%
set TEST_RESULT FAIL
endif
环境变量管理:
错误处理最佳实践:
code复制if %lasterror% == EfiError(8) then
echo "写保护错误,请检查跳线设置"
endif
code复制set RETRY 3
:retry_label
drvdiag -c all
if %lasterror% ne 0 then
set /a RETRY=%RETRY%-1
if %RETRY% gtr 0 goto retry_label
endif
脚本调试技巧:
@echo -on显示执行过程-d参数运行shell进入调试模式dmpstore命令导出环境变量状态虽然UEFI Shell应用程序本质上仍是UEFI应用,但它们通过链接Shell库获得了额外优势:
| 特性 | Shell应用 | 标准UEFI应用 |
|---|---|---|
| 参数解析 | 自动解析为argc/argv | 需手动处理字符串 |
| 文件访问 | 支持映射名(如fs0:) | 需完整设备路径 |
| 环境变量 | 直接访问%VAR% | 需调用RT服务 |
| 控制台输出 | 支持颜色控制 | 仅基础文本 |
| 依赖关系 | 需要Shell环境 | 独立运行 |
典型场景选择建议:
推荐使用EDK II作为开发环境,配置步骤:
安装基础工具链:
code复制# Ubuntu示例
sudo apt install build-essential uuid-dev nasm acpica-tools
获取EDK II源码:
code复制git clone https://github.com/tianocore/edk2.git
cd edk2
git submodule update --init
配置Shell应用项目:
在edk2/AppPkg/Applications/下新建项目目录,创建:
MyTestTool.c:主程序文件MyTestTool.inf:项目描述文件MyTestTool.uni:多语言支持示例INF文件内容:
code复制[Defines]
INF_VERSION = 0x00010005
BASE_NAME = MyTestTool
FILE_GUID = XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
MODULE_TYPE = UEFI_APPLICATION
VERSION_STRING = 1.0
ENTRY_POINT = UefiMain
[Sources]
MyTestTool.c
[Packages]
MdePkg/MdePkg.dec
ShellPkg/ShellPkg.dec
[LibraryClasses]
UefiApplicationEntryPoint
ShellCEntryLib
硬件信息收集工具实现:
c复制#include <Uefi.h>
#include <Library/UefiLib.h>
#include <Library/ShellCEntryLib.h>
#include <Protocol/ShellParameters.h>
EFI_STATUS GetCpuInfo() {
EFI_STATUS Status;
UINTN CpuCount = 0;
// 通过Shell协议获取CPU信息
Status = gShell->GetMapList(NULL, &CpuCount);
if (EFI_ERROR(Status)) {
Print(L"获取CPU信息失败: %r\n", Status);
return Status;
}
Print(L"系统检测到 %d 个CPU核心\n", CpuCount);
return EFI_SUCCESS;
}
INTN EFIAPI ShellAppMain(IN UINTN Argc, IN CHAR16 **Argv) {
EFI_STATUS Status;
// 参数处理示例
if (Argc > 1 && StrCmp(Argv[1], L"-v") == 0) {
Print(L"硬件检测工具 v1.0\n");
}
Status = GetCpuInfo();
if (EFI_ERROR(Status)) {
return Status;
}
// 其他硬件检测逻辑...
return EFI_SUCCESS;
}
编译命令:
code复制build -a X64 -p AppPkg/AppPkg.dsc -m AppPkg/Applications/MyTestTool/MyTestTool.inf
将编译生成的.efi文件部署到以下任一目录即可被Shell自动识别:
fsX:\efi\boot\fsX:\efi\tools\为应用添加帮助文档:
code复制.TH MyTestTool 0 "硬件检测工具"
.SH NAME
收集系统硬件信息的诊断工具
.SH SYNOPSIS
MyTestTool [-v] [-all]
.SH OPTIONS
-v 显示版本信息
-all 执行完整检测(默认快速检测)
在PC制造环节,典型的UEFI Shell测试流程:
startup.nsh预设测试脚本:code复制# 示例startup.nsh
if exist fs0:\test\main.nsh then
fs0:\test\main.nsh
if %TEST_RESULT% == PASS then
\efi\boot\bootx64.efi # 启动操作系统
else
beep 3 1000 # 失败提示音
endif
endif
某OEM厂商的实际参数:
问题1:脚本执行权限不足
dmpstore -all | grep SecureBootset SecureBoot 0问题2:存储设备识别异常
fs0:映射失败code复制# 查看PCI设备列表
pci -l
# 检查存储控制器状态
smbiosview -t 17
# 重新扫描设备
reconnect -r
问题3:内存测试失败
memtest报告ECC错误memtest -a [起始地址] [结束地址]setup_var 0x123 0x1 (示例)smbiosview -t 17定位物理位置并行测试技术:
code复制# 启动后台测试任务
start /b memtest -a 0x0 0x100000000
start /b storcli fs0: -perf -count 100
# 等待任务完成
wait %pid1%
wait %pid2%
脚本预加载:
code复制# 将常用工具加载到内存
load -nc fs0:\tools\storcli.efi
load -nc fs0:\tools\drvdiag.efi
缓存优化:
code复制# 启用磁盘缓存
set -p CACHE_SIZE 32
在某数据中心硬件验证项目中,通过上述优化将测试时间从23分钟缩短至9分钟。
扩展UEFI Shell功能的步骤:
创建命令库项目:
code复制[Defines]
INF_VERSION = 0x00010005
BASE_NAME = MyShellCmd
MODULE_TYPE = UEFI_APPLICATION
LIBRARY_CLASS = MyShellCmdLib|UEFI_APPLICATION
[Sources]
MyShellCmd.c
[Packages]
MdePkg/MdePkg.dec
ShellPkg/ShellPkg.dec
[LibraryClasses]
UefiLib
ShellCEntryLib
实现命令处理函数:
c复制SHELL_STATUS EFIAPI MyCommandHandler(
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable,
IN UINTN ParamCount,
IN CHAR16 **Parameters
) {
if (ParamCount > 1 && StrCmp(Parameters[1], L"-h") == 0) {
Print(L"Usage: MyCommand [-v]\n");
return SHELL_SUCCESS;
}
// 命令实现逻辑...
}
注册命令:
c复制EFI_SHELL_COMMAND MyCommand = {
L"mycmd", // 命令名
MyCommandHandler, // 处理函数
L"mycmd [-v]", // 用法
L"自定义硬件测试命令", // 描述
NULL // 帮助页
};
EFI_STATUS RegisterCommands() {
return ShellCommandRegister(&MyCommand);
}
确保脚本在EFI Shell和UEFI Shell 2.0上都能运行的策略:
功能检测模式:
code复制# 检查Shell版本
set SHELL_VER 1
if exist shellver then
shellver | find "2.0"
if %lasterror% == 0 set SHELL_VER 2
endif
# 条件执行
if %SHELL_VER% == 2 then
# 使用UEFI Shell 2.0特性
smbiosview -sfo > info.csv
else
# 兼容模式
smbiosview > info.txt
endif
命令回退机制:
code复制# 尝试新命令,失败时回退
ifconfig -l > nul 2>&1
if %lasterror% ne 0 then
# 旧版本替代方案
netcfg -l
endif
公共函数库:
将兼容性逻辑封装为公共脚本compat.nsh,通过include指令复用。
脚本签名验证:
code复制# 示例验证流程
if not exist fs0:\certs\verify.efi then
echo "安全模块缺失"
exit 1
endif
fs0:\certs\verify.efi -f %ScriptPath%
if %lasterror% ne 0 then
echo "脚本签名验证失败"
exit 1
endif
执行沙箱:
code复制# 限制脚本访问范围
set -p RESTRICTED_MODE 1
set PATH \efi\tools
审计日志:
code复制# 记录所有命令执行
set -p AUDIT_LOG fs0:\logs\audit_%date%.log
echo [%time%] CMD: %_cmd% >> %AUDIT_LOG%
在金融设备制造场景中,这些安全措施帮助我们将未经授权的配置变更降低了92%。