0%

UEFI_Intro.md

UEFI 组成与概念解释

UEFI 简介

UEFI(Unified Extensible Firmware Interface),由最初的 EFI(Extensible Firmware Interface)发展而来。
EFI 在 2000 年由 Intel 公开了 1.0 版本,后来经过 EFI 1.1 规范演进,2005 年成立了 UEFI 国际联盟,完善并制定了
UEFI 标准。

UEFIConcepts.png

UEFI 定义了操作系统与硬件之间的接口规范,即 UEFI 固件的接口规范。当 UEFI 固件启动至一定阶段时,可以选择进入 UEFI
命令行模式。此时 UEFI 环境可以视为一个卫星操作系统,有其自己的文件系统、内存管理、网络通信服务。在该模式下,可以装载
驱动程序、运行 UEFI 应用程序,bootloader 是一种 UEFI 应用程序。

PlatFormInitPhases.png

UEFI 驱动程序和应用程序:

  • UEFI 驱动程序:封装具体硬件的功能并提供接口给外部使用的程序
  • UEFI 应用程序:没有提供接口的程序

UEFI 协议

UEFI 以协议(Protocol)的形式规定了封装硬件的接口,每个协议由三部分组成:协议的 GUID(Global Unique ID),
协议的接口结构体、协议的接口结构体、协议的服务。其中,GUID 是长度 128 位的固定值,用于唯一标识该接口。协议的接口
结构体是 C 语言中的结构体,其域大部分是指针,小部分是关键变量。UEFI 规定了每个域的类型,指针的参数类型域返回值、
变量类型与意义。结构体中的每个函数指针是用于访问硬件的、封装了具体功能的接口。协议的服务则规定了每个接口的功能。
每个实现了 UEFI 协议的程序称之为 UEFI 驱动程序。

UEFI 系统调用

UEFI 系统调用是 UEFI 系统服务表(UEFI System Table)所提供的接口。系统调用提供的服务氛围多种,例如运行时服务、
启动服务等。协议句柄服务,驱动程序使用该服务向外部提供协议,应用程序使用该服务检索可用的协议。在加载驱动程序或者
执行应用程序时,系统服务表会作为入口函数的指针传递给程序,通过该指针可使用其提供的接口。

UEFI 以句柄(Handle)的形式将硬件与协议相绑定,并维持了全局的句柄双向连标,每个句柄上绑定了硬件的设备路径、访问
硬件的协议等内容。UEFI 驱动程序主要使用协议句柄服务进行协议的安装,如使用 InstallProtocolInterface。安装后,
其他应用程序可检索该协议,从而访问与其相绑定过得硬件,如使用 LocateProtocol 接口。由于驱动程序使用固定的接口
绑定协议,因此可以静态分析提取接口较为方便。

有源码情况下 UEFI 驱动程序自动化测试的基本思路

  1. 驱动程序接口提取
    1. 过滤冗余函数,避免对不必要的函数进行静态分析
    2. 在每个函数体的实现中匹配特定的抽象语法树结构,即调用 UEFI 系统调用进行协议绑定的代码段
    3. 从该函数调用中提取该协议的 GUID 标识符和具体类型
  2. 数据类型提取
    1. 静态数据类型提取
      1. 静态类型提取 void* 以外的数据类型:以协议的类型作为入口,提取协议中每个函数指针的类型以及其参数类型,
      2. 数据类型存在依赖关系还需要提取每个类型依赖的类型,需要递归地处理所有的参数类型直至基本数据类型。
    2. 动态数据类型提取
      1. 处理 void* 类型:在使用时转化为具体的数据类型,因此需要在函数实现中寻找类型的转换,从而提取 void* 可能的类型
      2. 函数实现中往往存在函数调用,将具有动态数据类型的参数传递给其它函数,因此需要对函数调用关系进行追踪,在自函数中提取动态数据类型,即控制流分析
      3. UEFI 驱动程序中存在多种函数指针调用,目前解决了调用其它协议接口的函数指针
  3. 参数构造