至强服务器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函数
      • 驱动的名字

  1. 实验使用的CPU架构Broardwell。
  2. EFI App的构建过程实际上先构建可以在OS上运行的动态库/可执行文件,然后利用PE32+工具改为UEFI运行。
  3. UEFI基于GObject(https://docs.gtk.org/gobject/)用C模拟OOP或C++。
  4. JRE 1.7安装目录整个拷贝到VisualeBios.exe所在目录,并改名为jre。则Visual Bios的启动不需要安装JRE。卸载JRE 1.7验证。
  5. UEFI编译系统强制要求函数的局部变量统一声明在函数体的头部,否则报错。
  6. GRUB运行在BDS阶段,因为GRUB运行期间未调用ExitBootServices方法,实际调用此方法的是OS Loader。
  7. UEFI环境特点
    1. 支持X86、X64、ARM等平台
    2. 单核CPU,没有线程,没有进程
    3. 没有抢断/优先级
    4. 没有中断,唯一的路径是定时器
    5. 模块内部通讯通过Protocols(协议)和Events(事件)
    6. C语言编程(原文:Programming is done through C language,实际上有汇编)
  8. 包的声明用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工程

  1. 在ModuleExplorer视图中依次展开:ComponentsCoreMdeModulePkgLibraryInstances,右键单击,选择弹出菜单Add INF Module。关于Select EDK Project Root选项,选择结果无论是否正确,导入结果都存在错误。下文第2步和第3步就是纠错。
    在这里插入图片描述
  2. 找到导入的工程,移动生成的sdl文件到inf文件所在目录,并更名。
    在这里插入图片描述
  3. 按下图所示修改MdeModulePkg\Library\LibraryInstances.cif
    在这里插入图片描述
    在这里插入图片描述
  4. 关掉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 编译问题

  1. AMI的工程不能运行EDKII提供的命令
    在这里插入图片描述

  2. VeB不允许编译单个驱动

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

在这里插入图片描述

测试结果

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

在这里插入图片描述

  1. EFI Shell启动时会再执行一次设备驱动管理过程。
    在这里插入图片描述

  2. UEFI驱动管理在得到Supported函数的返回结果为EFI_SUCCESS后立即调用Start函数。上图Supported输出与Start输出成对出现无间断说明这一点。

  3. 任何驱动应在EFI Shell中先load试运行。否则驱动出错造成很大的麻烦。DXE出错的结果是载板变砖头,救砖的办法可能只有把FLASH从电路板上焊下来,烧好程序后再焊上去。

  4. 固件烧录与固件运行时不同。以下截图的实验:

    1. A版本包含HelloWorldDxe驱动,B版本与2023XXXX版本相同,唯一的区别是重新编译。编译环境、工具完全相同。
    2. 固件升级到A版本,重启后驱动绑定过程出现大量的HelloWorld打印
    3. 固件升级到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配置。

  1. 新增外部依赖DevicePathLib
    在这里插入图片描述
  2. 新增Protocols依赖gEfiDevicePathProtocolGuidgEfiDevicePathToTextProtocolGuid
    在这里插入图片描述

使用脚本编译

脚本编译的目的是为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驱动模块

  1. 编译,确认编译输出

    - Done -
    Build end time: 17:07:12, Sep.15 2023
    Build total time: 00:00:07
    
  2. 运行load HelloWorldDxe.efi,确认结果

    RemainingDevicePath的值始终为:F3 EE 00 F0。期望的结果为不同的设备不同的值。UEFI Driver Writer’s Guide大部分示例显示,Supported适用的流程是开发者用期望的Protocol尝试打开。结果成功就是支持,结果失败就是不支持。很多示例㫫示Start还会把这个逻辑再运行一次。

    RemainingDevicePath不一定指设备,它还兼顾方便开发者在当前设备下挂载子设备。另外:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/107348.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SQL如何导入数据以及第一次上机作业

如何导入excel数据 首先得学会导入数据 使用excel格式不需要改成其它格式&#xff08;如csv&#xff0c;txt&#xff09;&#xff0c;因为你改了到时候还是会报错&#xff08;实践过使用Sum统计总数一直说我数据格式有问题&#xff09; 首先右键TSGL数据库->任务->导入数…

C++前缀和算法应用:矩形区域不超过 K 的最大数值和

基础知识点 C算法&#xff1a;前缀和、前缀乘积、前缀异或的原理、源码及测试用例 题目 给你一个 m x n 的矩阵 matrix 和一个整数 k &#xff0c;找出并返回矩阵内部矩形区域的不超过 k 的最大数值和。 题目数据保证总会存在一个数值和不超过 k 的矩形区域。 示例 1&#x…

机器学习-概述与贝叶斯算法

机器学习的一般步骤&#xff1a;数据搜集、数据清洗、特征工程、数学建模。数据划分&#xff1a;训练集、验证集、测试集。K折交叉验证&#xff1a;解决数据量不够大问题&#xff0c;解决参数调优问题。深度学习不用做特征工程&#xff0c;传统机器学习要。损失函数&#xff0c…

深圳寄包裹到德国

深圳&#xff0c;作为全球最发达的城市之一&#xff0c;以其高效的物流服务在全球范围内享有盛名。如果你正在寻找一种方式将包裹从深圳寄送到德国&#xff0c;那么本文将为你提供详细的步骤和建议。 第一步&#xff1a;了解国际邮寄的基本信息 首先&#xff0c;你需要了解包裹…

Bitquiz重塑Learn to Earn热潮,用户零投入让学习创造价值

Axie 带来的暴富效应、StepN 带来的出圈效应&#xff0c;近期Bigtime 在熊市中的大火&#xff0c;为加密参与者带来的赚取效应&#xff0c;X to Earn 重新成为整个市场关注的重点&#xff0c;GameFi 再次站在了风口浪尖。 大家开始寻找下一个Bigtime&#xff0c;希望能够抓住一…

低代码技术这么香,如何把它的开发特点发挥到极致?

前言 什么是低代码技术&#xff1f; 低代码是一种可视化软件开发方法&#xff0c;通过最少的编码更快地交付应用程序。图形用户界面和拖放功能使开发过程的各个方面自动化&#xff0c;消除了对传统计算机编程方法的依赖。 文章目录 前言低代码平台怎么选&#xff1f;用友Yonbu…

压缩炸弹,Java怎么防止

一、什么是压缩炸弹&#xff0c;会有什么危害 1.1 什么是压缩炸弹 压缩炸弹(ZIP)&#xff1a;一个压缩包只有几十KB&#xff0c;但是解压缩后有几十GB&#xff0c;甚至可以去到几百TB&#xff0c;直接撑爆硬盘&#xff0c;或者是在解压过程中CPU飙到100%造成服务器宕机。虽然…

JOSEF约瑟 多档切换式漏电(剩余)继电器JHOK-ZBL1 30/100/300/500mA

系列型号&#xff1a; JHOK-ZBL多档切换式漏电&#xff08;剩余&#xff09;继电器&#xff08;导轨&#xff09; JHOK-ZBL1多档切换式漏电&#xff08;剩余&#xff09;继电器 JHOK-ZBL2多档切换式漏电&#xff08;剩余&#xff09;继电器 JHOK-ZBM多档切换式漏电&#xf…

Unity 3D基础——缓动效果

1.在场景中新建两个 Cube 立方体&#xff0c;在 Scene 视图中将两个 Cude的位置错开。 2.新建 C# 脚本 MoveToTarget.cs&#xff08;写完记得保存&#xff09; using System.Collections; using System.Collections.Generic; using UnityEngine;public class MoveToTarget : M…

SystemC入门学习-第8章 测试平台的编写

之前的章节&#xff0c;一直把重点放在用SystemC来描述硬件电路上&#xff0c;即如何编写SystemC 的RTL。本章的注意力集中在验证和编写测试平台上。 重点包括&#xff1a; 如何生成时钟信号和激励波形如何编写有响应能力的测试平台如何记录仿真结果 8.1 编写测试平台 测试平…

论文阅读:Rethinking Range View Representation for LiDAR Segmentation

来源ICCV2023 0、摘要 LiDAR分割对于自动驾驶感知至关重要。最近的趋势有利于基于点或体素的方法&#xff0c;因为它们通常产生比传统的距离视图表示更好的性能。在这项工作中&#xff0c;我们揭示了建立强大的距离视图模型的几个关键因素。我们观察到&#xff0c;“多对一”…

JOSEF约瑟 漏电继电器 JD1-200 工作电压:380V 孔径:45mm 50~500mA

JD1系列漏电继电器 系列型号 JD1-100漏电继电器 JD1-200漏电继电器 JD1-250漏电继电器 JD1系列漏电继电器原为分体式固定式安装&#xff0c;为适应现行安装场合需要&#xff0c;上海约瑟继电器厂在产品原JD1一体式漏电继电器基础上进行产品升级&#xff0c;开发出现在较为…

【Rust基础①】基本类型、所有权与借用、复合类型

文章目录 1 基本类型1.1 数值类型1.1.1 Rust 中的内置的整数类型&#xff1a;1.1.2 浮点类型1.1.3 数学运算1.1.4 位运算1.1.5 序列(Range) 1.2 字符、布尔、单元类型1.3 语句和表达式1.4 函数 2 所有权与借用2.1 栈(Stack)与堆(Heap)2.2 所有权原则2.2.1 转移所有权2.2.2 克隆…

【Redis】Java Spring操作redis

目录 引入Redis依赖StringRedisTemplate使用String使用List使用Set使用hash使用zset 引入Redis依赖 StringRedisTemplate 此处RedisTemplate是把这些操作Redis的方法&#xff0c;分成了几个类别&#xff0c;分门别类的来组织的。 此处提供的一些接口风格&#xff0c;和原生的Re…

IP 协议的相关特性(部分)

IP 协议的报文格式 4位版本号&#xff1a; 用来表示IP协议的版本&#xff0c;现有的IP协议只有两个版本&#xff0c;IPv4&#xff0c;IPv6。 4位首部长度&#xff1a; 设定和TCP的首部长度一样 8位服务类型&#xff1a; &#xff08;真正只有4位才有效果&#xff09;&#xf…

Linux C/C++ 嗅探数据包并显示流量统计信息

嗅探数据包并显示流量统计信息是网络分析中的一种重要技术&#xff0c;常用于网络故障诊断、网络安全监控等方面。具体来说&#xff0c;嗅探器是一种可以捕获网络上传输的数据包&#xff0c;并将其展示给分析人员的软件工具。在嗅探器中&#xff0c;使用pcap库是一种常见的方法…

【TensorFlow2 之014】在 TF 2.0 中实现 LeNet-5

一、说明 在这篇文章中&#xff0c;我们将展示如何在 TensorFlow 中实现像 \(LeNet-5\) 这样的基础卷积神经网络。LeNet-5 架构由 Yann LeCun 于 1998 年发明&#xff0c;是第一个卷积神经网络。 数据黑客变种rs 深度学习 机器学习 TensorFlow 2020 年 2 月 29 日 | 0 …

AUTOSAR组织发布20周年纪念册,东软睿驰NeuSAR列入成功案例

近日&#xff0c;AUTOSAR组织在成立20周年之际发布20周年官方纪念册&#xff08;20th Anniversary Brochure&#xff09;&#xff0c;记录了AUTOSAR组织从成立到今天的故事、汽车行业当前和未来的发展以及AUTOSAR 伙伴关系和合作在重塑汽车方面的作用。东软睿驰提报的基于AUTOS…

行情分析——加密货币市场大盘走势(10.16)

目前大饼再次止稳&#xff0c;并开始向上攀升&#xff0c;目前MACD来看也是进入了多头趋势。重新调整了蓝色上涨趋势线&#xff0c;目前来看这次的低点并没有跌破上一个低点&#xff0c;可以认为是上涨的中继。注意白天的下跌回调。 以太目前也是走了四连阳线&#xff0c;而MAC…

关于Skywalking Agent customize-enhance-trace对应用复杂参数类型取值

对于Skywalking Agent customize-enhance-trace 大家应该不陌生了&#xff0c;主要支持以非入侵的方式按用户自定义的Span跟踪对应的应用方法&#xff0c;并获取数据。 参考https://skywalking.apache.org/docs/skywalking-java/v9.0.0/en/setup/service-agent/java-agent/cust…