天天看点

UEFI原理与编程(二)

UEFI的基础服务

系统表

对UEFI应用程序和驱动程序开发人员来讲,系统表是最重要的数据结构之一,它是用户空间通往内核空间的通道。有了它,UEFI应用程序和驱动才可以访问UEFI内核、硬件资源和I/O设备。

  • 1 在应用程序和驱动中访问系统表

计算机系统进入DXE阶段后系统表被初始化,因而系统表只能用于DXE阶段以及以后的应用程序和驱动中。系统表是UEFI内核的一个全局结构体,其指针作为程序映像(Image)入口函数的参数传递到用户空间。程序映像(包括UEFI应用程序、DXE驱动程序以及UEFI驱动程序)的入口函数有统一的格式,其函数原型如下:

typedef
EFI_STATUS
(EFIAPI *EFI_IMAGE_ENTRY_POINT) (
    IN  EFI_HANDLE ImageHandle,        //程序映像(Image)的句柄
    IN  EFI_SYSTEM_TABLE *SystemTable  //系统表指针
);

           
  • 2 系统表指针从内核传递到用户空间的过程

通常,程序映像的入口函数是_ModuleEntryPoint(当一个Image被启动服务的StartImage服务启动时,执行的就是这个入口函数)。当应用程序或驱动加载到内存形成Image后(ImageHandle是这个Image的句柄),_ModuleEntryPoint函数地址被赋值给Image对象的EntryPoint,然后Image->EntryPoint(ImageHandle,SystemTable)会被执行,最终会从Image的入口函数_ModuleEntryPoint执行到模块的入口函数(模块的入口函数是通过.inf文件中ENTRY_POINT指定的那个函数)

1 系统表的组成

  • 系统表可分为以下6部分:

    表头:包括表的版本号、表的CRC校验码等。

    固件信息:包括固件开发商名字的字符串和固件的版本号。

    标准输入控制台、标准输出控制台、标准错误控制台。

    启动服务表

    运行时服务表

    系统配置表

//@file path:  MdePkg\Include\Uefi\UefiSpec.h

///
/// EFI System Table
///
typedef struct {
  ///
  /// The table header for the EFI System Table.
  ///
  EFI_TABLE_HEADER                  Hdr;
  ///
  /// A pointer to a null terminated string that identifies the vendor
  /// that produces the system firmware for the platform.
  ///
  CHAR16                            *FirmwareVendor;
  ///
  /// A firmware vendor specific value that identifies the revision
  /// of the system firmware for the platform.
  ///
  UINT32                            FirmwareRevision;
  ///
  /// The handle for the active console input device. This handle must support
  /// EFI_SIMPLE_TEXT_INPUT_PROTOCOL and EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
  ///
  EFI_HANDLE                        ConsoleInHandle;
  ///
  /// A pointer to the EFI_SIMPLE_TEXT_INPUT_PROTOCOL interface that is
  /// associated with ConsoleInHandle.
  ///
  EFI_SIMPLE_TEXT_INPUT_PROTOCOL    *ConIn;
  ///
  /// The handle for the active console output device.
  ///
  EFI_HANDLE                        ConsoleOutHandle;
  ///
  /// A pointer to the EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL interface
  /// that is associated with ConsoleOutHandle.
  ///
  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL   *ConOut;
  ///
  /// The handle for the active standard error console device.
  /// This handle must support the EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.
  ///
  EFI_HANDLE                        StandardErrorHandle;   
  ///
  /// A pointer to the EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL interface
  /// that is associated with StandardErrorHandle.
  ///
  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL   *StdErr;
  ///
  /// A pointer to the EFI Runtime Services Table.
  ///
  EFI_RUNTIME_SERVICES              *RuntimeServices;     // 运行时服务
  ///
  /// A pointer to the EFI Boot Services Table.
  ///
  EFI_BOOT_SERVICES                 *BootServices;       // 启动时服务
  ///
  /// The number of system configuration tables in the buffer ConfigurationTable.
  ///
  UINTN                             NumberOfTableEntries;  // CongratulationTable数组的大小
  ///
  /// A pointer to the system configuration tables.
  /// The number of entries in the table is NumberOfTableEntries.
  ///
  EFI_CONFIGURATION_TABLE           *ConfigurationTable;  //系统配置表数组
} EFI_SYSTEM_TABLE;

           

表头:

// file :  EdkCompatibilityPkg\Foundation\Efi\Include\EfiTypes.h
typedef struct {
  UINT64  Signature;  
  UINT32  Revision;
  UINT32  HeaderSize;   //是整个表的长度,对系统表来讲,就是sizeof(EFI_SYSTEM_TABLE)
  UINT32  CRC32;        
  UINT32  Reserved;
} EFI_TABLE_HEADER;

           

系统配置表:

//file : EdkCompatibilityPkg\Foundation\Efi\Include\EfiApi.h
//
// EFI Configuration Table
//
typedef struct {
  EFI_GUID  VendorGuid;     // 配置表标识符
  VOID      *VendorTable;   // 指向配置表的数据
} EFI_CONFIGURATION_TABLE;

           

启动服务

启动服务也称启动服务表,它由UEFI表头表项组成,表中每一项是一个函数指针,该函数用于提供一项服务。

启动服务是UEFI的核心数据结构,可以分为以下8类:

  • UEFI事件服务
  • 内存管理服务
  • Protocol管理服务
  • Protocol使用类服务
  • 驱动管理服务
  • Image 管理服务
  • ExitBootServices
  • 其他服务。

1 UEFI事件服务

事件是异步操作的基础,使得在 UEFI 系统内可以执行并发操作。UEFI 事件服务包含事件(Event)、定时器(Timer)、任务优先级(TPL)三类服务。

  • 事件服务用于产生、关闭、触发、等待事件和检查事件状态。
  • 定时器服务用于设置定时器属性。
  • 任务优先级服务用于提升、降低当前程序的优先级。

2 内存管理服务

内存管理服务主要提供内存的分配与释放服务、管理系统内存映射。主要包括:AllocatePages、FreePages、GetMemoryMap, AllocatePool、FreePool 5个服务。

3 Protocol管理服务

Protocol 管理服务提供安装与卸载 Protocol 的服务,以及注册 Protocol 通知函书(安装时调用)的服务(详见第八,九章)。

4 Protocol使用类服务

Protocol使用类服务包括 Protocol 的打开与关闭,查找支持 Protocol 的控制器,主要提供 Protocol 使用者使用(详见第四章)

5 驱动管理服务

驱动管理服务包括将驱动安装到控制器的 connect 服务和将驱动从控制器上卸载的 disconnect 服务(详见第九章)。

6 Image 管理服务

Image 管理服务包括加载、卸载、启动、退出 UEFI 应用程序或驱动.

Image 管理服务 作用
LoadImage 加载 .efi 文件至内存并生成 Image
StartImage 启动 Image,调用 Image 的入口函数
Exit 退出Image
UnloadImage 卸载Image

7 ExitBootServices

ExitBootService 用于结束启动服务,该服务成功返回后,系统进入 RT 期。操作系统加载器从启动服务接过对计算机系统的控制权后必须调用该服务

8 其他服务

启动服务中的其他服务

服务名 作用
InstallConfigurationTable 增加、更新、删除系统配置表项
GetNextMonotonicCount 获得系统单调计数器的下一个值
Stall 暂停 CPU 指定的微秒数
SetWatchdogTimer 设置看门狗定时器(指定的时间内若无系统反应,则重启)
CalculateCrc32 计算 CRC32 校验码
CopyMem 复制内存
SetMem 设置指定内存区域的值

运行时服务

从进入DXE阶段运行时服务被初始化,直到操作系统结束,运行时服务都一直存在并向上层(操作系统,操作系统加载器,UEFI应用程序或者UEFI驱动)提供服务。运行时服务主要包括:

  • 时间服务
  • 读写系统变量
  • 虚拟内存服务
  • 其他服务。

1 时间服务

时间服务包括:读取/设置硬件事件、读取/设置唤醒定时器。

GetTime/SetTime

计算机硬件时钟由单独的电池供电,操作系统启动时通过读取硬件时钟获得事件。

//file: MdePkg\Include\Uefi\UefiSpec.h
/**
  Returns the current time and date information, and the time-keeping capabilities
  of the hardware platform.

  @param[out]  Time             A pointer to storage to receive a snapshot of the current time.
  @param[out]  Capabilities     An optional pointer to a buffer to receive the real time clock
                                device's capabilities.

  @retval EFI_SUCCESS           The operation completed successfully.  
  @retval EFI_INVALID_PARAMETER Time is NULL.
  @retval EFI_DEVICE_ERROR      The time could not be retrieved due to hardware error.

**/
typedef
EFI_STATUS
(EFIAPI *EFI_GET_TIME)(
  OUT  EFI_TIME                    *Time,   //当前时间
  OUT  EFI_TIME_CAPABILITIES       *Capabilities OPTIONAL  // 时钟硬件的性能
  );

/**
  Sets the current local time and date information.

  @param[in]  Time              A pointer to the current time.

  @retval EFI_SUCCESS           The operation completed successfully.
  @retval EFI_INVALID_PARAMETER A time field is out of range.
  @retval EFI_DEVICE_ERROR      The time could not be set due due to hardware error.

**/
typedef
EFI_STATUS
(EFIAPI *EFI_SET_TIME)(
  IN  EFI_TIME                     *Time
  );