作者: 陈立中 | 日期: 2025年6月7日
位置: 成都瑞贺数理科技有限公司, 中国四川省成都市(http://www.chengduredhare.cn/)
目录
本指南解释了提供的UEFI驱动(DummyDriver.c)和MPI头文件(mpi2.h)中的代码流程和关键函数。该驱动使用MPIv2(消息传递接口)与9400-16i主机总线适配器(HBA)交互,通过UEFI HII(人机界面基础设施)显示HBA信息。
1. 代码流程概述
驱动入口点: DummyDriverEntry
- 初始化HII
- 添加HII包(字符串、表单)以在BIOS设置中显示数据。
- 安装EF_I_HII_CONFIG_ACCESS_PROTOCOL用于表单回调。
- 定位串口I/O协议
- 配置串口用于调试输出(UseSerialPort)。
- 定位HBA
- 扫描PCI总线查找9400-16i HBA(厂商ID 0x1000, 设备ID 0x00AC)。
- 检查HBA状态
- 读取门铃寄存器确定HBA状态(复位/就绪/运行/故障)。
- 发送IOC Facts请求
- 从HBA获取固件版本、端口数量和机箱信息。
- 更新HII字符串
- 用HBA详细信息(固件版本、PCI位置等)填充BIOS设置菜单。
2. DummyDriver.c中的关键函数
Locate9400HBA
功能: 在PCI总线上查找9400-16i HBA。
步骤:
- 获取所有支持gEfiPciIoProtoco1Guid的句柄。
- 对每个句柄:
- 读取PCI配置空间检查厂商/设备ID(0x1000/0x00AC)。
- 将HBA详情保存到g_HBA9400(PCI位置、BARs、句柄)。
输出: 通过串口打印HBA的BDF(总线/设备/功能)。
Identify9400HBAState
功能: 从门铃寄存器(BAR1偏移0x00)读取HBA状态。
状态:
- MPI_IOC_STATE_RESET (复位)
- MPI_IOC_STATE_READY (就绪)
- MPI_IOC_STATE_OPERATIONAL (运行)
- MPI_IOC_STATE_FAULT (故障)
输出: 通过串口打印状态(如"9400HBA当前处于运行状态")。
HBA9400_issue_ioc_facts
功能: 请求HBA信息(固件版本、端口、机箱)。
步骤:
- 发送MPI2_FUNCTION_IOC_FACTS握手消息。
- 接收回复到g_HBA9400.data。
- 解析Mpi2IOCFactsReply_t获取:
- 固件版本(FwVersion)
- 端口数量(NumberOfPorts)
- 最大机箱数(MaxEnclosures)
输出: 用检索到的数据更新g_HBA9400。
reset_9400
功能: 如果HBA卡在复位/故障状态则重置。
步骤:
- 通过HostInterruptMask禁用中断。
- 向HostDiagnostic寄存器写入MPI2_DIAG_RESET_ADAPTER。
- 等待50ms,然后清除复位。
验证: 通过Identify9400HBAState检查复位后状态。
send_mpt_handshake_message
功能: 发送MPI握手消息(如IOC Facts)。
步骤:
- 检查HBA状态(如果处于故障状态则失败)。
- 用消息功能/长度触发门铃(MPI2_DOORBELL_OFFSET)。
- 等待门铃中断(wait_for_9400HBA_doorbell)。
- 向门铃寄存器写入消息DWORDs。
关键: 使用wait_for_9400HBA_handshake_response确认IOC准备就绪。
recv_9400_handshake_data
功能: 接收握手回复(如IOC Facts响应)。
步骤:
- 为每个回复DWORD等待门铃中断。
- 从门铃寄存器读取回复数据。
- 验证回复头中的IOCStatus。
3. 关键MPI结构与寄存器(mpi2.h)
HBA寄存器(映射到BAR1)
| 寄存器 | 偏移 | 功能 |
|---|---|---|
| Doorbell | 0x00 | 状态位(31:28),向IOC发送消息。 |
| HostInterruptStatus | 0x30 | 检查中断(如MPI2_HIS_DOORBELL_INTERRUPT)。 |
| HostInterruptMask | 0x34 | 屏蔽中断(如重置期间禁用)。 |
| HostDiagnostic | 0x08 | 触发重置(MPI2_DIAG_RESET_ADAPTER)。 |
IOC Facts消息
typedef struct _MPI2_IOC_FACTS_REPLY {
U16 IOCStatus; // 状态(0x0000 = 成功)
U32 IOCLoginfo; // 错误详情
U8 NumberOfPorts; // 活动端口
U16 MaxEnclosures; // 最大支持机箱数
MPI2_VERSION_UNION FwVersion; // 固件版本
} MPI2_IOC_FACTS_REPLY;
关键字段:
- IOCStatus: 成功/失败(如MPI2_IOCSTATUS_SUCCESS)。
- FwVersion: 固件版本(主/次/单元/开发)。
- NumberOfPorts: 活动SAS/SATA端口。
HBA状态(门铃位31:28)
#define MPI2_IOC_STATE_RESET (0x00000000)
#define MPI2_IOC_STATE_READY (0x10000000)
#define MPI2_IOC_STATE_OPERATIONAL (0x20000000)
#define MPI2_IOC_STATE_FAULT (0x40000000)
4. 串口调试
UseSerialPort
- 使用EFI_SERTAL_IO_PROTOCOL初始化串口(115200波特, 8N1)。
- 通过SerialPrintf打印调试消息(如"9400 HBA固件: X.Y.Z")。
示例输出
PRINT(L"找到9400-HBA, BDF=%02x-%02x-%02x", bus, dev, func);
PRINT(L"9400HBA当前处于运行状态");
5. HII集成
更新BIOS设置菜单
- 创建HII句柄:
HiHandle = HiAddPackages(&g_leobummyDriverGuid, ImageHandle, ...); - 设置动态字符串:
UnicodeSPrint(HiMessage, ... "固件: %d.%d", major, minor); HiisetString(HiHandle, STRING_TOKEN(STR_9400_FW_VER), HiiMessage, NULL); - 在BIOS设置中显示:
- HBA固件版本。
- PCI位置(总线/设备/功能)。
- 端口/机箱数量。
6. 初级工程师重要注意事项
1. PCI枚举:
- 始终使用EFI_PCI_IO_PROTOCOL访问PCI配置空间。
- 检查厂商/设备ID以定位HBA。
2. 门铃协议:
- 发送消息后轮询HostInterruptStatus检查MPI2_HIS_DOORBELL_INTERRUPT。
- 超时处理很关键(使用gBS->Stall进行微秒级延迟)。
3. 错误处理:
- 验证回复中的IOCStatus(非零表示失败)。
- 操作前检查MPI_IOC_STATE_FAULT状态。
4. HII:
- 令牌(如STRING_TOKEN(STR_9400_FW_VER))必须与.VFR文件匹配。
流程图

本指南为理解驱动与9400 HBA的交互提供了基础。研究MPI规范以了解高级功能。
7. 程序运行截图
在EFI Shell下加载驱动

在高级菜单下显示简单驱动

在简单驱动菜单中显示9400基本信息

1806

被折叠的 条评论
为什么被折叠?



