至强服务器BIOS/UEFI驱动开发笔记

news2024/11/17 6:46:20

至强服务器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 = 0x00010005
    BASE_NAME=HelloWorldDxe
    FILE_GUID = de296c9d-8bac-08bc-ac6d-db2998aff781
    MODULE_TYPE = UEFI_DRIVER
    VERSION_STRING = 0.1
    ENTRY_POINT = DriverMain

[Sources]
    HelloWorldDxe.c

[Packages]
    MdePkg/MdePkg.dec
    MdeModulePkg/MdeModulePkg.dec

[LibraryClasses]
    BaseLib
    BaseMemoryLib
    DebugLib
    MemoryAllocationLib
    PrintLib
    UefiDriverEntryPoint
    UefiLib

驱动程序入口和基本功能

新建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 0x10

EFI_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.coloradmin.cn/o/1082653.html

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

相关文章

统计子岛屿的数量

统计子岛屿 题目描述 给你两个 m x n 的二进制矩阵 grid1 和 grid2 &#xff0c;它们只包含 0 &#xff08;表示水域&#xff09;和 1 &#xff08;表示陆地&#xff09;。一个 岛屿 是由 四个方向 &#xff08;水平或者竖直&#xff09;上相邻的 1 组成的区域。任何矩阵以外…

基于SpringBoot的在线试题库系统设计与实现

目录 前言 一、技术栈 二、系统功能介绍 学生管理 教师管理 专业管理 试卷管理 试题管理 考试管理 错题本 考试记录 三、核心代码 1、登录模块 2、文件上传模块 3、代码封装 前言 使用旧方法对作业管理信息进行系统化管理已经不再让人们信赖了&#xff0c;把现在的…

iPhone 如何强制重启

参考iPhone的官方使用手册 传送门 尤其当 iPhone 未响应&#xff0c;也无法将其关机再开机&#xff0c;此方法最有效&#xff1a; 按住调高音量按钮&#xff0c;然后快速松开。按住调低音量按钮&#xff0c;然后快速松开。按住侧边按钮。当 Apple 标志出现时&#xff0c;松开侧…

ODrive移植keil(五)—— 开环控制和电流变换

目录 一、开环控制1.1、控制原理1.2、硬件接线1.3、代码说明1.4、程序演示1.5、程序架构的体现 二、电流变换2.1、理论说明2.2、代码说明 ODrive、VESC和SimpleFOC 教程链接汇总&#xff1a;请点击 一、开环控制 在SimpleFOC系列中有开环控制的教程&#xff0c;SimpleFOC移植S…

Android 免杀教程

免杀练习两年半 目录 msfvenom 自动生成 自带免杀 工具免杀 Thefatrat venom 工具小记 加壳 源码免杀 加壳 源码混淆 数据通信 对抗反编译 反编译工具崩溃 ZIP文件格式对抗 AndroidManifest.xml 对抗反编译小结 VT检测 https://www.virustotal.com/gui/home/up…

Webpack 解决:Error: error:0308010C:digital envelope routines::unsupported 的问题

1、问题描述&#xff1a; 其一、报错为&#xff1a; Error: error:0308010C:digital envelope routines::unsupported 中文为&#xff1a; 错误&#xff1a;错误&#xff1a;0308010C&#xff1a;数字信封例程::不支持 其二、问题描述为&#xff1a; 在项目打包的时候 np…

Mysql-一条查询sql时如何执行的

TOC一条sql是如何执行的 Mysql的基本架构 如图所示&#xff0c;mysql可以分为server层和存储引擎两部分 server层&#xff1a;涵盖着MySQL的大多数核心服务功能&#xff0c;内置函数&#xff0c;存储过程、触发器、视图等存储引擎&#xff1a;数据的存储和提取&#xff1b;支…

K8s Kubernetes Namespave Pod Label Deployment Service 实战

本章节将介绍如何在kubernetes集群中部署一个nginx服务&#xff0c;并且能够对其进行访问。 Namespace Namespace是kubernetes系统中的一种非常重要资源&#xff0c;它的主要作用是用来实现多套环境的资源隔离或者多租户的资源隔离。 默认情况下&#xff0c;kubernetes集群中…

LODOP打印条形码WEB不预览直接打印

一&#xff1a;安装CLodop_Setup_for_Win32NT.exe 二&#xff1a;页面上引用<script src"/JS/LodopFuncs.js"></script> 三&#xff1a;body里加上控件&#xff0c; <body><object id"LODOP1" classid"clsid:2105C259-1E0C-4…

MATLAB算法实战应用案例精讲-【优化算法】树木生长算法(TGA)(附MATLAB代码实现)

前言 Armin Cheraghalipour 根据树木生长的特点于2017 年提出了一种新的元启发式优化算法TGA该算将始定量的群按照解的适应度从高到低排序,分成4组具有不同功能的种群。每次迭代分别进行处理。 算法原理 算法流程图 代码实现 MATLAB TGA.m % "Tree growth algorithm…

STM32:GPIO模拟SPI驱动ADS8361

ADS8361是TI公司开发的一款模拟量输入芯片。ADS8361有四种工作模式&#xff0c;本文主要针对模式三进行通信驱动。官方方案使用两路SPI来通信&#xff0c;一路SPI Master&#xff0c;一路SPI Slave。我在使用STM32主控芯片的两路SPI进行通信的时候&#xff0c;发现只有SPI Mast…

Vuex基础使用存取值+异步请求

一.Vuex简介 vuex是什么&#xff1f; Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态&#xff0c;并以相应的规则保证状态以一种可预测的方式发生变化。 什么情况使用 Vuex&#xff1f; Vuex 可以帮助我们管理共享状态&#…

如何正确的关闭Redis服务器

Redis官方原生版本是在Linux平台上开发和测试的&#xff0c;但是大多数初学者都是使用Windows系统来学习如何开发的。因此&#xff0c;官方提供了一个叫做“Microsoft Open Tech Redis”的项目&#xff0c;该项目专门为Windows平台提供了一个官方支持的Redis版本&#xff0c;但…

第一天商城项目

复盘 1.maven高级部分聚合和继承 maven聚合工程(深度剖析)_一宿君的博客-CSDN博客 2.yml配置文件 mybatis mybatis: mapper-locations: classpath:mappers/*mapper.xml mapper-locations&#xff1a;这是一个子键&#xff0c;用于指定MyBatis映射文件&#xff08;Mapper XML…

单片机课程设计(Integrate就医服务平台/医院信息化平台)

目录 摘要 改善现有门诊流程的对策 一、设计任务 二、整机方案和论证 三、系统各模块设计与理论分析 3.1.1、触摸屏及LCD显示的工作原理 3.1.2、语音对讲模块设计 3.1.3、语音/文本转化模块设计 3.1.4、按键模组设计 3.1.5、存储模块设计 3.1.6、USB模组设计 3.1.7…

Seata入门系列【4】undo_log、global_table、branch_table、lock_table字段及作用详解

1 客户端 1.1 undo_log 在AT模式中&#xff0c;需要在参与全局事务的数据库中&#xff0c;添加一个undo_log表&#xff0c;建表语句如下&#xff1a; SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS 0;-- ---------------------------- -- Table structure for undo_log -- --…

20比较类的一种内在逻辑

我们平时会直接在idle里面去写类似于 10>6,但是其实仔细思考一下&#xff0c;10和6是int的实例对象&#xff0c;感觉学逻辑真的比单纯学代码有用&#xff0c;参照之前的那个图&#xff0c;多去想一下逻辑其实真的很好&#xff01; python3其实是这样不支持的~&#xff08;…

2023年9月Web3行业月度发展报告区块链篇 | 陀螺科技会员专享

9月是加密市场的活动月&#xff0c;斯坦福区块链周、Token2049等大型活动相继举办&#xff0c;后者更是创下超过1万人的历史最高纪录&#xff0c;成为了全球最大的Web3活动。在本次Token2049上&#xff0c;RWA、支付以及出入金成为了讨论度最多的活动。尽管活动如火如荼&#x…

Ps:画布大小

Ps菜单&#xff1a;图像/画布大小 Image/Canvas Size 快捷键&#xff1a;Ctrl Alt C 画布 Canvas是存放图像的容器&#xff0c;所以改变画布大小对原来的图像大小不会造成影响。除了画布大小 Canvas Size命令&#xff0c;画板工具、裁剪工具等也可以改变画布的大小&#xff…

金和OA C6任意文件读取漏洞 复现[附POC]

文章目录 金和OA C6任意文件读取漏洞 复现[附POC]0x01 前言0x02 漏洞描述0x03 影响版本0x04 漏洞环境0x05 漏洞复现1.访问漏洞环境2.构造POC3.复现 0x06 修复建议 金和OA C6任意文件读取漏洞 复现[附POC] 0x01 前言 免责声明&#xff1a;请勿利用文章内的相关技术从事非法测试…