至强服务器BIOS/UEFI驱动开发笔记
至强服务器BIOS/UEFI驱动开发笔记
- 驱动开发基础
- Hello UEFI Driver 项目
- 选择项目位置
- 初始化驱动代码文件结构
- 驱动程序入口和基本功能
- 导入AMI工程
- AMI平台Hello UEFI Driver 编译问题
- 测试结果
- 打印设备列表
- 继续开发`HelloWorldSupported`函数
- 依赖配置
- 使用脚本编译
- 编译测试此DXE驱动模块
- 改进`HelloWorldSupported`函数
- 问题
- 继续实验
- AMI实战
- SDL和CIF
- 以界面方式增加工程
- 以代码方式增加工程
- RoboVeb
- 踩过的坑
- AMI VEB构建技巧
- AMI VEB命令行构建
- AMI构建单个工程
- AMI App开发
- 关键函数和协议
- 主要步骤
- HellWorld.c
- 测试结果
- PCI Driver开发
- 基于EDKII工程的HelloWorldDxe
- 测试结果
- 继续开发`Supported`函数
- 测试结果
- AMI PCI 驱动开发
- 新增加的DXE驱动放到和BIOS固件的哪里?
- U盘和键盘全消失等问题
- 矛盾的根源
- UDK2015
- 编译环境
- Windows编译环境
- OvmfPkg
- VS2008安装问题
- UDK2017
- OVMF 2015
- 经典的DXE驱动案例
- VGA驱动
- 仿照VGA驱动修改MyPciDxe
- 以上代码迁移到服务器
- 驱动的其它属性
- 工具类函数
- 简化的Supported函数与初步的Start函数
- 驱动的名字
- 实验使用的CPU架构Broardwell。
- EFI App的构建过程实际上先构建可以在OS上运行的动态库/可执行文件,然后利用PE32+工具改为UEFI运行。
- UEFI基于GObject(https://docs.gtk.org/gobject/)用C模拟OOP或C++。
- JRE 1.7安装目录整个拷贝到
VisualeBios.exe所在目录,并改名为jre。则Visual Bios的启动不需要安装JRE。卸载JRE 1.7验证。 - UEFI编译系统强制要求函数的局部变量统一声明在函数体的头部,否则报错。
- GRUB运行在BDS阶段,因为GRUB运行期间未调用ExitBootServices方法,实际调用此方法的是OS Loader。
- UEFI环境特点
- 支持X86、X64、ARM等平台
- 单核CPU,没有线程,没有进程
- 没有抢断/优先级
- 没有中断,唯一的路径是定时器
- 模块内部通讯通过Protocols(协议)和Events(事件)
- C语言编程(原文:Programming is done through C language,实际上有汇编)
- 包的声明用dsc,模块的声明用inf,模块的依赖用dec
驱动开发基础
Hello UEFI Driver 项目
用UEFI Shell装载驱动进行测试。受载板平台限制,测试工程放在AMI项目里。
选择项目位置
与UEFI App开发不同,驱动代码所处项目架构应当与硬件构成映射关系。如果驱动代码与驱动硬件不在相同架构,则开发者需要手动处理固件布局才成封装成为正确的固件。我亲自踩坑证明这个说法:

关键错误消息:Build\GetPpiName.c(1) : fatal error C1083: Cannot open include file: '/RELEASE_MYTOOLS/PpiTableIA32.c': No such file or directory。不知道驱动项目存放须按规定的开发者会认为这个问题是玄学问题,怎么生成的代码找不到生成的代码呢?建议参照下图和项目结构选择合适的UEFI驱动存储放置:

根据驱动目标选择合适的项目位置。本示例的目标为USB键盘驱动,因此选择MdeModulePkg/Bus。当然,如果你已对BIOS固件布局已非常清楚,你可以随意。
初始化驱动代码文件结构
新建目录HelloWorldDxe,新建HelloWorldDxe.inf,代码如下:
[Defines]INF_VERSION = 0x00010005BASE_NAME=HelloWorldDxeFILE_GUID = de296c9d-8bac-08bc-ac6d-db2998aff781MODULE_TYPE = UEFI_DRIVERVERSION_STRING = 0.1ENTRY_POINT = DriverMain[Sources]HelloWorldDxe.c[Packages]MdePkg/MdePkg.decMdeModulePkg/MdeModulePkg.dec[LibraryClasses]BaseLibBaseMemoryLibDebugLibMemoryAllocationLibPrintLibUefiDriverEntryPointUefiLib
驱动程序入口和基本功能
新建HelloWorldDxe.c,代码如下:
#include <Uefi.h>
#include <Protocol/DriverBinding.h>
#include <Protocol/ComponentName2.h>
#include <Protocol/ComponentName.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiDriverEntryPoint.h>
#include <Library/UefiLib.h>
#include <Library/DebugLib.h>#define HELLOWORLD_VERSION 0x10EFI_STATUS EFIAPI HelloWorldStart(IN EFI_DRIVER_BINDING_PROTOCOL* This,IN EFI_HANDLE Controller,IN EFI_DEVICE_PATH_PROTOCOL* RemainingDevicePath
)
{EFI_STATUS status = EFI_SUCCESS;Print(L"[HelloWorldStart] HelloWorld driver started.\n");return status;
}EFI_STATUS EFIAPI HelloWorldSupported(IN EFI_DRIVER_BINDING_PROTOCOL* This,IN EFI_HANDLE Controller,IN EFI_DEVICE_PATH_PROTOCOL* RemainingDevicePath
)
{EFI_STATUS status = EFI_SUCCESS;Print(L"[HelloWorldSupported] HelloWorld driver supported.\n");return status;
}EFI_STATUS EFIAPI HelloWorldStop(IN EFI_DRIVER_BINDING_PROTOCOL* This,IN EFI_HANDLE Controller,IN UINTN NumberOfChildren,IN EFI_HANDLE* ChildHandleBuffer
)
{EFI_STATUS status = EFI_SUCCESS;Print(L"[HelloWorldStop] HelloWorld driver stopped.\n");return status;
}EFI_DRIVER_BINDING_PROTOCOL g_helloworld_driver_binding = {HelloWorldSupported,HelloWorldStart,HelloWorldStop,HELLOWORLD_VERSION,NULL,NULL
};EFI_STATUS EFIAPI DriverMain(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE* SystemTable
)
{EFI_STATUS status = EFI_SUCCESS;status = EfiLibInstallDriverBindingComponentName2(ImageHandle,SystemTable,&g_helloworld_driver_binding,ImageHandle,NULL,NULL);ASSERT_EFI_ERROR(status);return status;
}
导入AMI工程
- 在ModuleExplorer视图中依次展开:
Components、Core、MdeModulePkg、LibraryInstances,右键单击,选择弹出菜单Add INF Module。关于Select EDK Project Root选项,选择结果无论是否正确,导入结果都存在错误。下文第2步和第3步就是纠错。

- 找到导入的工程,移动生成的
sdl文件到inf文件所在目录,并更名。

- 按下图所示修改
MdeModulePkg\Library\LibraryInstances.cif


- 关掉VeB软件,重新打开。编译报错:
<work root>\Build\GrangevillePkg\RELEASE_MYTOOLS\X64\MdeModulePkg\Bus\HelloWorldDxe\HelloWorldDxe\DEBUG\AutoGen.h(16) : fatal error C1083: Cannot open include file: 'Uefi.h': No such file or directory。原因是HelloWorldDxe.inf有错。具体错误是Package依赖错误地写成dsc,正确的做法是写成dec
AMI平台Hello UEFI Driver 编译问题
-
AMI的工程不能运行EDKII提供的命令

-
VeB不允许编译单个驱动
这是假象。实际原因是VeB没有把导入INF生成的
sdl文件放到inf所在目录。解决办法是移动sdl文件到inf文件所在目录并修正上级cif文件中的错误。

测试结果
- UEFI Shell运行运行
load指令可见大量的HelloWorld输出,说明UEFI驱动管理支持一个设备绑定多个驱动,不会因为某个设备已存在绑定的驱动而停止匹配新驱动。UEFI如何选择调用哪个驱动呢?驱动的版本的如何在驱动选择中发挥作用的? - 服务器启动慢问题存在新证据,证据指向问题发生在SEC或者PEI阶段。下图右边神秘的数字,在
HelloWorldDxe集成进BIOS固件之前不确定它显示时CPU执行阶段。现在可以证明处于DXE阶段。那么,从通电到HelloWorldDxe产生输出的大约10秒钟时间,很可能都处于SEC和PEI阶段。现在没有确定串口设备未初始化造成的HelloWorldDxe无输出的时间。

-
EFI Shell启动时会再执行一次设备驱动管理过程。

-
UEFI驱动管理在得到
Supported函数的返回结果为EFI_SUCCESS后立即调用Start函数。上图Supported输出与Start输出成对出现无间断说明这一点。 -
任何驱动应在EFI Shell中先
load试运行。否则驱动出错造成很大的麻烦。DXE出错的结果是载板变砖头,救砖的办法可能只有把FLASH从电路板上焊下来,烧好程序后再焊上去。 -
固件烧录与固件运行时不同。以下截图的实验:
- A版本包含HelloWorldDxe驱动,B版本与2023XXXX版本相同,唯一的区别是重新编译。编译环境、工具完全相同。
- 固件升级到A版本,重启后驱动绑定过程出现大量的HelloWorld打印
- 固件升级到B版本,重启时控制台出现大量的HelloWorld打印

打印设备列表
继续开发HelloWorldSupported函数
目标:以字符串形式输出所有Device关键字,尝试寻找设备特征,在特征中搜寻键盘设备。代码如下:
EFI_STATUS EFIAPI HelloWorldSupported(IN EFI_DRIVER_BINDING_PROTOCOL* This,IN EFI_HANDLE Controller,IN EFI_DEVICE_PATH_PROTOCOL* RemainingDevicePath
)
{EFI_STATUS status = EFI_SUCCESS;EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* device2txt = NULL;CHAR16* device_path = NULL;status = gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid, NULL, (void**)&device2txt);if (EFI_ERROR(status)){Print(L"[HelloWorld Driver] LocateProtocol result: %d\n", status);return status;}device_path = device2txt->ConvertDeviceNodeToText(RemainingDevicePath, TRUE, TRUE);Print(L"[HelloWorld Driver] device: %s\n", device_path);return EFI_UNSUPPORTED;
}
依赖配置
这里采用VeB配置。
- 新增外部依赖
DevicePathLib

- 新增Protocols依赖
gEfiDevicePathProtocolGuid和gEfiDevicePathToTextProtocolGuid

使用脚本编译
脚本编译的目的是为CI做准备。
@echo off
chcp 65001
title AMI UEFI Build Tool
echo Any question can be sent to zhtqs8@163.com
set CCX86DIR=<work root>\software\Aptio_5.x\x86\x86
set CCX64DIR=<work root>\software\Aptio_5.x\x86\amd64
set TOOLS_DIR=<work root>\software\Aptio_5.x\BuildTools
set PATH=%PATH%;<work root>\software\Aptio_5.x\x86\x86
set PATH=%PATH%;<work root>\software\Aptio_5.x\amd64
set PATH=%PATH%;<work root>\software\Aptio_5.x\x86
set PATH=%PATH%;<work root>\software\Aptio_5.x\BuildTools
set PATH=%PATH%;<work root>\software\Aptio_5.x\BuildTools\Bin\Win32
set PATH=%PATH%;<work root>\software\Aptio_5.x\VisualeBios\jre\bin\
cd <work root>
cmd /k
运行指令make rebuild,结果如下:

编译测试此DXE驱动模块
-
编译,确认编译输出
- Done - Build end time: 17:07:12, Sep.15 2023 Build total time: 00:00:07 -
运行
load HelloWorldDxe.efi,确认结果RemainingDevicePath的值始终为:F3 EE 00 F0。期望的结果为不同的设备不同的值。UEFI Driver Writer’s Guide大部分示例显示,Supported适用的流程是开发者用期望的Protocol尝试打开。结果成功就是支持,结果失败就是不支持。很多示例㫫示Start还会把这个逻辑再运行一次。RemainingDevicePath不一定指设备,它还兼顾方便开发者在当前设备下挂载子设备。另外:
相关文章:
至强服务器BIOS/UEFI驱动开发笔记
至强服务器BIOS/UEFI驱动开发笔记 驱动开发基础Hello UEFI Driver 项目选择项目位置初始化驱动代码文件结构驱动程序入口和基本功能导入AMI工程AMI平台Hello UEFI Driver 编译问题测试结果打印设备列表继续开发`HelloWorldSupported`函数依赖配置使用脚本编译编译测试此DXE驱动…...
Linux:Termius连接本地虚拟机与虚拟机快照
Termius连接本地虚拟机与虚拟机快照 1. Termius连接本地虚拟机2. 虚拟机快照与还原2.1 设置快照以及恢复 附录 1. Termius连接本地虚拟机 ifconfig -a 查看配置 连接成功 2. 虚拟机快照与还原 在学习阶段我们无法避免的可能损坏Linux操作系统。 如果损坏的话,重新…...
高校教务系统登录页面JS分析——四川大学
高校教务系统密码加密逻辑及JS逆向 本文将介绍高校教务系统的密码加密逻辑以及使用JavaScript进行逆向分析的过程。通过本文,你将了解到密码加密的基本概念、常用加密算法以及如何通过逆向分析来破解密码。 本文仅供交流学习,勿用于非法用途。 一、密码加…...
Kafka SASL认证授权(四)认证源码解析
Kafka SASL认证授权(四)认证源码解析。 官网地址:https://kafka.apache.org/ 一、认证流程 在了解kafka网络模型的基础上,了解它的认证流程: ApiVersionsRequest->SaslHandshakeRequest->a series of SASL client and server tokens corresponding to the mechani…...
软件测试学习(一)基础概念、实质、说明书测试、分类、动态黑盒测试
目录 软件测试概念、背景 软件测试员究竟做些什么 大多数软件测试员应该具备的素质 软件测试的实质 完全测试程序是不可能的 测试无法显示潜伏的软件缺陷 并非所有软件缺陷都要修复 软件测试员在产品小组中不受欢迎 术语:精准和准确 产品说明书的测试技术…...
在fastapi中实现异步
在FastAPI应用中使用异步特性可以提高并发性能,但如果您要调用的模型是同步的,可能会导致阻塞。为了实现异步处理,您可以将阻塞的操作委托给线程池或进程池,以便异步执行。 以下是一种基本方法来实现异步处理图片识别任务&#x…...
js数组去重
在JavaScript中,有很多方法可以用来去除数组中的重复项。以下是一些常见的方法: 方法一:使用Set Set是ES6中的新数据类型,它只存储唯一值。因此,我们可以利用这一特性来去重。 let array [1, 2, 3, 2, 1, 4, 3, 5,…...
【前端】根据后端返回的url进行下载并设置文件下载名称
在我们项目当中存储文件是存储到厂商的服务器上的,然后厂商返回一个可以直接下载url地址,但是前端使用这个url下载的时候永远都是保存一个名字,这时候我们就需要设置文件保存的名称, 那么如何实现呢?使用了fet…...
《视觉SLAM十四讲》公式推导(一)
文章目录 CH3 三维空间刚体运动CH3-1 旋转矩阵的推导CH3-2 旋转矩阵是正交矩阵的证明CH3-3 变换矩阵的逆的推导CH3-4 罗德里格斯公式推导 CH3 三维空间刚体运动 CH3-1 旋转矩阵的推导 (1)二维空间中的旋转矩阵 易得 { x ′ ∣ O P ′ ∣ c o s ( θ …...
简单好用的解压缩软件:keka 中文 for mac
Keka是一款功能全面、易于使用的文件压缩和解压缩软件,为Mac用户提供了便捷的文件管理工具。它支持多种压缩格式,具有快速解压和强大的压缩功能,让您能够轻松地处理各种文件压缩需求。 隐私非常重要 安全共享只需设置密码并创建高度加密的文…...
【UE 插件】UE4 虚幻引擎 插件开发(带源码插件打包、无源码插件打包) 有这一篇文章就够了!!!
目录 0 引言1 快速入门1.1 新建插件的前提1.2 创建插件步骤1.3 打包插件 2 无源代码的插件制作3 插件详细介绍3.1 插件的使用方法3.1 UE 预置插件模版3.1.1 空白3.1.2 纯内容3.1.3 编辑器独立窗口3.1.4 编辑器工具栏按钮3.1.5 编辑器模式3.1.6 第三方库3.1.7 蓝图库 3.2 插件中…...
C# CodeFormer 图像修复
效果 项目 代码 using Microsoft.ML.OnnxRuntime; using Microsoft.ML.OnnxRuntime.Tensors; using OpenCvSharp; using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; using System.Windows.Forms;namespace 图像修复 {p…...
Android Studio的笔记--HttpURLConnection使用GET下载zip文件
HttpURLConnection使用GET下载zip文件 http get下载zip文件MainActivity.javaAndroidMainfest.xmlactivity_main.xmllog http get下载zip文件 MainActivity.java 用HttpURLConnection GET方法进行需注意: 1、Android 9及以上版本需要设置这个,否则会有…...
phantom3D模体
phantom是人头模型,分为2D和3D两种,matlab中可直接调用phantom(size)生成2D数据,如图1,而三维需要对应函数文件,下载:3D 图1 2D phantom 3D模体为一个椭球体,只能生成xyz三个方向相同维度的模…...
贪心算法解决批量开票限额的问题
具体问题:批量订单开票 限制:1.开最少的张数 2.每张限额10w # 贪心算法 def split_invoice_by_item(items):items_sorted sorted(items, keylambda x: x.price, reverseTrue)invoices []for item in items_sorted:# 尝试将商品加入已有的发票中added …...
Unity后台登录/获取数据——BestHTTP的使用Get/Post
一、使用BestHTTP实现登录功能(Post) 登录具体的步骤如下: 1:传入你的用户名和密码,这是一条包括链接和用户名密码的链接 2:使用BestHTTP的Post功能将链接传到服务器后台 3:后台拿到了你传送…...
【Windows日志】记录系统事件的日志
文章目录 一、概要二、Windows日志介绍 2.1 应用程序日志2.2 系统日志2.3 安全日志 三、查看与分析日志四、常见事件ID 4.1 登录事件 4.1.1 4624登陆成功4.1.2 4625登陆失败 4.2 特权使用4.3 账户管理事件4.4 账户登录事件5.2 事件ID汇总 一、概要 Windows主要有以下三类日…...
物联网开发学习笔记——目录索引
什么是物联网? 物联网的英文名称是Internet of Things。IoT则是Internet of Things的缩写。 通俗地说,就是把设备与互联网连接起来,进行信息交互。 目录 一、开发环境配置 工欲善其事必先利其器,首先是开发环境配置。 开发环…...
Prometheus:优秀和强大的监控报警工具
文章目录 概述Prometheus的底层技术和原理数据模型数据采集数据存储查询语言数据可视化 Prometheus的部署Prometheus的使用配置数据采集目标查询监控数据设置警报规则 查看数据可视化总结 概述 Prometheus是一款开源的监控和警报工具,用于收集和存储系统和应用程序…...
Appium
# 获取元素和屏幕截图 echo on adb shell uiautomator dump /sdcard/app.uix adb pull /sdcard/app.uix F:\APP\app.uixadb shell screencap -p /sdcard/app.png adb pull /sdcard/app.png F:\APP\app.png卸载appium npm uninstall appium -g 重新安装appium npm install -g a…...
[特殊字符] 智能合约中的数据是如何在区块链中保持一致的?
🧠 智能合约中的数据是如何在区块链中保持一致的? 为什么所有区块链节点都能得出相同结果?合约调用这么复杂,状态真能保持一致吗?本篇带你从底层视角理解“状态一致性”的真相。 一、智能合约的数据存储在哪里…...
【Python】 -- 趣味代码 - 小恐龙游戏
文章目录 文章目录 00 小恐龙游戏程序设计框架代码结构和功能游戏流程总结01 小恐龙游戏程序设计02 百度网盘地址00 小恐龙游戏程序设计框架 这段代码是一个基于 Pygame 的简易跑酷游戏的完整实现,玩家控制一个角色(龙)躲避障碍物(仙人掌和乌鸦)。以下是代码的详细介绍:…...
设计模式和设计原则回顾
设计模式和设计原则回顾 23种设计模式是设计原则的完美体现,设计原则设计原则是设计模式的理论基石, 设计模式 在经典的设计模式分类中(如《设计模式:可复用面向对象软件的基础》一书中),总共有23种设计模式,分为三大类: 一、创建型模式(5种) 1. 单例模式(Sing…...
利用ngx_stream_return_module构建简易 TCP/UDP 响应网关
一、模块概述 ngx_stream_return_module 提供了一个极简的指令: return <value>;在收到客户端连接后,立即将 <value> 写回并关闭连接。<value> 支持内嵌文本和内置变量(如 $time_iso8601、$remote_addr 等)&a…...
Oracle查询表空间大小
1 查询数据库中所有的表空间以及表空间所占空间的大小 SELECTtablespace_name,sum( bytes ) / 1024 / 1024 FROMdba_data_files GROUP BYtablespace_name; 2 Oracle查询表空间大小及每个表所占空间的大小 SELECTtablespace_name,file_id,file_name,round( bytes / ( 1024 …...
【HarmonyOS 5.0】DevEco Testing:鸿蒙应用质量保障的终极武器
——全方位测试解决方案与代码实战 一、工具定位与核心能力 DevEco Testing是HarmonyOS官方推出的一体化测试平台,覆盖应用全生命周期测试需求,主要提供五大核心能力: 测试类型检测目标关键指标功能体验基…...
【网络安全产品大调研系列】2. 体验漏洞扫描
前言 2023 年漏洞扫描服务市场规模预计为 3.06(十亿美元)。漏洞扫描服务市场行业预计将从 2024 年的 3.48(十亿美元)增长到 2032 年的 9.54(十亿美元)。预测期内漏洞扫描服务市场 CAGR(增长率&…...
电脑插入多块移动硬盘后经常出现卡顿和蓝屏
当电脑在插入多块移动硬盘后频繁出现卡顿和蓝屏问题时,可能涉及硬件资源冲突、驱动兼容性、供电不足或系统设置等多方面原因。以下是逐步排查和解决方案: 1. 检查电源供电问题 问题原因:多块移动硬盘同时运行可能导致USB接口供电不足&#x…...
【算法训练营Day07】字符串part1
文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接:344. 反转字符串 双指针法,两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...
【Java_EE】Spring MVC
目录 Spring Web MVC 编辑注解 RestController RequestMapping RequestParam RequestParam RequestBody PathVariable RequestPart 参数传递 注意事项 编辑参数重命名 RequestParam 编辑编辑传递集合 RequestParam 传递JSON数据 编辑RequestBody …...
