BIOS的全局变量gST gBS gDS

gST

gST全称为global system table (在 uEFIL 里面,全面变量都会有个小写字母 g 在变量的前面,表征 global 的意思。) 是UEFI的基础服务之一的系统表。系统表是最重要的数据结构之一,它是用户空间通往内核空间的通道。有了它,UEFI应用程序和驱动才可以访问UEFI内核、硬件资源和I/O设备。

系统表构成

系统表可分为如下6部分:

  • 表头:包括表的版本号、表的CRC校验码等。
  • 固件信息:包括固件开发商名字的字符串和固件的版本号。
  • 标准输入控制台、标准输出控制台、标准错误控制台。
  • 启动服务表
  • 运行时服务表
  • 系统配置表
    结构体定义如下:
///
/// EFI System Table
///
typedef struct {
 ///EFI系统表的表头。
  EFI_TABLE_HEADER                  Hdr;

  /// 指向空终止字符串的指针,固件提供商
  CHAR16                            *FirmwareVendor;
  
  /// 固件版本号
  UINT32                            FirmwareRevision;

  /// 活动控制台输入设备的句柄。该句柄必须支持EFI_SIMPLE_TEXT_INPUT_PROTOCOL和EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL。
  EFI_HANDLE                        ConsoleInHandle;

  /// 指向与ConsoleInHandle关联的EFI_SIMPLE_TEXT_INPUT_PROTOCOL接口的指针。
  EFI_SIMPLE_TEXT_INPUT_PROTOCOL    *ConIn;
  
  /// 活动控制台输出设备的句柄。
  EFI_HANDLE                        ConsoleOutHandle;
  
  ///指向与ConsoleOutHandle关联的EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL接口的指针。
  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL   *ConOut;

  ///活动的标准错误控制台设备的句柄。该句柄必须支持EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL。
  EFI_HANDLE                        StandardErrorHandle;
 
  /// 一个指向与standderrorhandle关联的EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL接口的指针。
  /// 这三个控制台设备以及ConIn、ConOut、stdErr三个Protocol在驱动ConSplitterDxe中被初始化。
  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL   *StdErr;
 
  /// 指向EFI运行时服务表的指针。
  EFI_RUNTIME_SERVICES              *RuntimeServices;

  /// 指向引导服务表的指针
  EFI_BOOT_SERVICES                 *BootServices;
 
  /// 缓冲区ConfigurationTable中的系统配置表的数量。
  UINTN                             NumberOfTableEntries;
 
  /// 指向系统配置表的指针。ConfigurationTable是系统配置表,它指向EFI_CONFIGURATION_TABLE数组,数组中的每一项是一个表。
  /// 例如,ConfigurationTable通常会包含APCI(Advance Configuration and Power Interface)表,
  /// ACPI在系统配置表中可以表示为:{gEfiAcpiTableGuid,EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER*}

  EFI_CONFIGURATION_TABLE           *ConfigurationTable;
} EFI_SYSTEM_TABLE;

(1) 表头 EFI_TABLE_HEADER , UEFI中的表通常都是以EFI_TABLE_HEADER开头,EFI_TABLE_HEADER的数据结构如下:

typedef struct {

    /// Signature为64位的无符号整数,EDK2提供了宏SIGNATURE_64(A,B,C,D,E,F,G,H),它用于将ASCII码串转化为64位的无符号整数。
    //例如,EFI_SYSTEM_TABLE的Signature为SIGNATURE_64(‘I’,’B’,’I’,’ ‘,’S’,’Y’,’S’,’T’)。
    UINT64 Signature;

    /// 该表所符合的EFI规范的修订。该字段的上16位为主要修订值,下16位为次要修订值。
    UINT32 Revision;

    /// HeaderSize是整个表的长度,对系统表来讲,就是sizeof(EFI_SYSTEM_TABLE)。 
    UINT32 HeaderSize;

   /// CRC32是标的校验码。计算CRC32校验码时,首先将数据结构中CRC32域清零,
   /// 然后计算整张表(表大小为HeaderSize)的CRC32码,计算后将校验码填充到CRC32域。
    UINT32 CRC32;
    
    /// 保留字段,必须设置为0。
    UINT32 Reserved;
} EFI_TABLE_HEADER;

系统表的使用

在UEFI中只有一个地址空间,所有的程序都运行在RING0优先级,应用程序地址空间占用UEFI地址空间的一部分。既然用户空间和内核空间是一个整体,在应用程序内也就可以直接使用内核空间的任何地址了,那么在应用程序内,只要得到了系统表的地址,就可以使用系统表。系统表的地址可以通过模块的入口函数的参数得到。

既可以通过模块入口函数UefiMain中使用传入参数SystemTable访问系统表,也可以使用gST变量访问,gST变量定义在用户空间,变量在函数UefiBootServicesTableLibConstructor中被初始化,这个函数是库UefiBootServicesTableLib的构造函数,在AutoGen.c中的ProcessLibraryConstructorList被调用。它指向的系统表定义在UEFI内核中,但需要在应用程序或驱动工程文件的[LibraryClasses]里引用UefiBootServicesTableLib。以下面的键盘事件为例:

#include<Uefi.h>
#include<Library/UefiBootServicesTableLib.h>//使用gST需要添加
EFI_Status
UefiMain(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE *SystemTable)
{
    EFI_STATUS Status;
    UINTN Index;
    EFI_INPUT_KEY Key;
    CHAR16 StrBuffer[4] = {0};

    /// 直接使用SystemTable 
    SystemTable->BootServices->WaitForEvent(1,&SystemTable->ConIn->WaitForKey,&Index);
    Status = SystemTable->ConIn->ReadKeyStroke(SystemTable->ConIn,&Key);
    
    /// 使用gST
    gST -> ConOut -> OutputString(gST -> ConOut,L"Please enter any key\n");
    gBS->WaitForEvent(1,&gST->ConIn->WaitForKey,&Index);
    Status = gST->ConIn->ReadKeyStroke(gST->ConIn,&Key);
    
    StrBuffer[0] = Key.UnicodeChar;
    StrBuffer[1] = '\n';
    
    SystemTable->ConOut->OutputString(SystemTable->ConOut,StrBuffer);
    gST->ConOut->OutputString(gST->ConOut,StrBuffer);
    return EFI_SUCCESS;
}

差异似乎只是使用gST和gBS替换掉SystemTable和SystemTable -> BootServices。

gBS

gBS指的是系统表下的SystemTable->BootService,这个被称为启动服务。系统进人DXE阶段时启动服务表被初始化,最终通过SystemTable指针将启动服务(BS)表传递给UEFI应用程序或驱动程序。UEFI应用程序和驱动程序可以通过gST->BootServices或gBS访问启动服务表。
Boot Service Table是一个结构体, 包含了所有Boot Service阶段可用的函数创建好之后,在UEFI环境下可以一直被使用,直到UEFI将控制权交给OS,并且OS调用了ExitBootService()。Boot Service是对整个系统资源的直接使用,当控制权交给OS后,OS就掌握了系统的完全控制权,这时就不再允许其它服务在未经OS允许的情况下直接对系统进行操作。

  • 事件触发函数
  • Memory Allocation Services
  • Protocol Handle Services
  • Image Services
    启动服务是UEFI的核心数据结构,通过它可以使用计算机系统内的资源。它提供的服务可以分为以下几类:
  • UEFI事件服务:事件是异步操作的基础。有了事件的支持,才可以在UEFI系统内执行并发操作。
  • 内存管理服务:主要提供内存的分配与释放服务,管理系统内存映射。
  • Protocol管理服务:提供了安装Protocol与卸载Protocol的服务,以及注册Protocol通知函数(该函数在Protocol安装时调用)的服务。
  • Protocol使用类服务:包括Protocol的打开与关闭,查找支持Protocol的控制器。
  • 驱动管理服务:包括用于将驱动安装到控制器的connect服务,以及将驱动从控制器上卸载的disconnect服务。
  • Image管理服务:此类服务包括加载、卸载、启动和退出UEFI应用程序或驱动。
  • ExitBootServices:用于结束启动服务,此服务成功返回后系统进人RT期。
  • 其他服务。

启动服务表的结构

启动服务也称启动服务表,它由UEFI表头和表项组成。表中每一项是一个函数指针,这个函数用于提供一项服务。开发UEFI应用和驱动离不开启动服务,深人理解启动服务提供的每一个服务是开发者一项必不可少的任务。上文提到过,启动服务中的服务大致可以分为8类:UEFI事件服务、内存管理服务、Protocol管理服务、Protocol使用类服务、驱动管理服务、Image管理服务、ExitBootServices及其他服务。

typedef struct {
  
  EFI_TABLE_HEADER                Hdr;

  // 任务优先级服务:用于提升、降低当前程序的优先级
  EFI_RAISE_TPL                   RaiseTPL;
  EFI_RESTORE_TPL                 RestoreTPL;

  //内存管理服务主要提供内存的分配与释放服务、管理系统内存映射。
  EFI_ALLOCATE_PAGES              AllocatePages;//分配内存
  EFI_FREE_PAGES                  FreePages;//释放内存
  EFI_GET_MEMORY_MAP              GetMemoryMap;//获得当前内存映射(物理地址<->虚地址)
  EFI_ALLOCATE_POOL               AllocatePool;//分配内存页
  EFI_FREE_POOL                   FreePool;//释放内存页

  // 事件服务专指BS中函数名以Event结尾的6个服务。UEFI事件服务是事件服务、定时器服务和任务优先级服务的统称。
  // 事件服务用于产生、关闭、触发、等待事件和检査事件状态。
  // 定时器服务用于设置定时器属性。
  EFI_CREATE_EVENT                  CreateEvent;//生成一个事件对象
  EFI_SET_TIMER                     SetTimer;//设置定时器属性
  EFI_WAIT_FOR_EVENT                WaitForEvent;//等待事件组中的任一事件被触发
  EFI_SIGNAL_EVENT                  SignalEvent;//触发事件对象
  EFI_CLOSE_EVENT                   CloseEvent;//关闭事件对象
  EFI_CHECK_EVENT                   CheckEvent;//检查事件状态

  // Protocol管理服务 UEFI提供了安装和卸载Protocol的服务,以及注册Protocol通知函数(该函数在Protocol安装时调用)的服务。
  EFI_INSTALL_PROTOCOL_INTERFACE    InstallProtocolInterface;//安装Protocol到设备上
  EFI_REINSTALL_PROTOCOL_INTERFACE  ReinstallProtocolInterface;//重新安装Protocol
  EFI_UNINSTALL_PROTOCOL_INTERFACE  UninstallProtocolInterface;//从设备上卸载Protocol
  EFI_REGISTER_PROTOCOL_NOTIFY      RegisterProtocolNotify;//为指定的Protocol注册通知事件,当这个Protocol安装时,该事件触发
  // 以下相关为Protocol使用类服务
  EFI_HANDLE_PROTOCOL               HandleProtocol;//打开 Protocol, OpenProtocol 的简化版
  VOID                              *Reserved;
  EFI_LOCATE_HANDLE                 LocateHandle;//找出支持指定Protocol的所有Handle,调用者负责分配和释放内存
  EFI_LOCATE_DEVICE_PATH            LocateDevicePath;  // 在指定的设备路径下找出支持给定Protocol的设备,并返回离指定的设备路径最近的设备
  EFI_INSTALL_CONFIGURATION_TABLE   InstallConfigurationTable;//从EFI系统表中添加、更新或删除配置表项。

  // Image管理服务,此类服务包括加载、卸载、启动和退出UEFI应用程序或驱动。
  EFI_IMAGE_LOAD                    LoadImage;//加载.efi文件至内存并生成Image
  EFI_IMAGE_START                   StartImage;//启动Image,也就是调用Image的人口函数
  EFI_EXIT                          Exit;//退出Image
  EFI_IMAGE_UNLOAD                  UnloadImage;//卸载Image
  //ExitBootServices用于结束启动服务,此服务成功返回后,系统进人RT期。操作系统加载器从启动服务接过对计算机系统的控制权后必须调用此服务。
  EFI_EXIT_BOOT_SERVICES            ExitBootServices;//结束启动服务

  // 其他服务
  EFI_GET_NEXT_MONOTONIC_COUNT      GetNextMonotonicCount;//获得系统单调计数器的下一个值
  EFI_STALL                         Stall;//暂停CPU指定的微秒数
  EFI_SET_WATCHDOG_TIMER            SetWatchdogTimer;//设置“看门狗”定时器,即在指定的时间内若系统无反应,则重启系统

  // 驱动管理服务 此类服务包括用于将驱动安装到控制器的connect服务,以及将驱动从控制器上卸载的disconnect服务。
  EFI_CONNECT_CONTROLLER            ConnectController;// 将驱动安装到指定的设备控制器
  EFI_DISCONNECT_CONTROLLER         DisconnectController;// 将驱动从指定的设备控制器卸载

  //Protocol使用类服务 该服务包括Protocol的打开与关闭、査找支持Protocol的控制器。
  EFI_OPEN_PROTOCOL                 OpenProtocol; // 打开 Protocol
  EFI_CLOSE_PROTOCOL                CloseProtocol; // 关闭 Protocol
  EFI_OPEN_PROTOCOL_INFORMATION     OpenProtocolInformation;// 返回指定Protocol的打开信息

  // Library Services
  EFI_PROTOCOLS_PER_HANDLE          ProtocolsPerHandle;//(Protocol使用)找出指定Handle上安装的所有Protocol
  EFI_LOCATE_HANDLE_BUFFER          LocateHandleBuffer;//(Protocol使用)找出支持指定Protocol的所有Handleo系统负责分配内存,调用者负责释放内存
  EFI_LOCATE_PROTOCOL               LocateProtocol;//(Protocol使用)找出系统中指定Protocol的第一个实例
  EFI_INSTALL_MULTIPLE_PROTOCOL_INTERFACES    InstallMultipleProtocolInterfaces;///(Protocol管理)安装多个Protocol到设备上
  EFI_UNINSTALL_MULTIPLE_PROTOCOL_INTERFACES  UninstallMultipleProtocolInterfaces;///(Protocol管理)从设备上卸载多个Protocol

  // 32-bit CRC Services
  EFI_CALCULATE_CRC32               CalculateCrc32;//计算CRC32校验码

  // Miscellaneous Services
  EFI_COPY_MEM                      CopyMem;//复制内存
  EFI_SET_MEM                       SetMem;//设置指定内存区域的值
  EFI_CREATE_EVENT_EX               CreateEventEx;//(事件服务)生成一个事件对象并将该事件加人到一个组内
} EFI_BOOT_SERVICES;

从启动服务可以看出其功能之强大,通过它可以完全掌控整个计算机系统,其功能与操作系统提供的功能有很多重叠之处。同时它也占用了大量的计算机系统资源。设计启动服务的主要目的是帮助操作系统加载器初始化计算机系统,当操作系统加载器彻底取得对计算机系统的控制权之后,启动服务也就完成了它的使命,启动服务占用的系统资源也需要转交给操作系统加载器。此时需要调用gBS->ExitBootServices,其作用正是结束启动服务、释放启动服务占用的资源以及使用启动服务分配到的启动期资源,将控制权交给操作系统加载器。也就是说,启动服务的生存期在DxeMain与gBS->ExitBootServices之间。

gDS

gDS指的是EFI_DXE_SERVICES,是一个结构体, 包含了只在DXE阶段可用的函数, 一般是DXE Core内部使用

  • Firmware Volume driver用于从BIOS芯片中读取DXE Driver并复制到内存中。
  • Decompress driver用于将压缩打包形式的DXE Driver解压缩
    在这里插入图片描述
typedef struct {
  EFI_TABLE_HEADER                Hdr;

  //
  // Global Coherency Domain Services
  EFI_ADD_MEMORY_SPACE            AddMemorySpace;//添加预留内存、系统内存或内存映射I/O资源到处理器的全局相干域。
  EFI_ALLOCATE_MEMORY_SPACE       AllocateMemorySpace;//分配不存在的内存,预留内存,系统内存,或内存映射I/O资源从处理器的全局一致性域。
  EFI_FREE_MEMORY_SPACE           FreeMemorySpace; //释放不存在的内存、预留内存、系统内存或内存映射来自处理器全局一致性域的I/O资源。
  EFI_REMOVE_MEMORY_SPACE         RemoveMemorySpace;  //释放不存在的内存,保留内存,系统内存,或内存映射I/O资源从处理器的全局相干域。
  EFI_GET_MEMORY_SPACE_DESCRIPTOR GetMemorySpaceDescriptor;  //检索包含指定地址的内存区域的描述符。
  EFI_SET_MEMORY_SPACE_ATTRIBUTES SetMemorySpaceAttributes;  //修改处理器全局一致性域内内存区域的属性。
  EFI_GET_MEMORY_SPACE_MAP        GetMemorySpaceMap; //返回处理器全局一致性域中的内存资源的映射。
  EFI_ADD_IO_SPACE                AddIoSpace;  //添加预留I/O或I/O资源到处理器的全局一致性域。
  EFI_ALLOCATE_IO_SPACE           AllocateIoSpace;  //分配不存在的I/O,保留的I/O,或I/O资源从处理器的全局一致性域。
  EFI_FREE_IO_SPACE               FreeIoSpace;  //释放不存在的I/O,保留的I/O,或I/O资源从处理器的全局一致性域。
  EFI_REMOVE_IO_SPACE             RemoveIoSpace;  //从处理器的全局一致性域移除保留的I/O或I/O资源。
  EFI_GET_IO_SPACE_DESCRIPTOR     GetIoSpaceDescriptor;  //检索包含指定地址的I/O区域的描述符。
  EFI_GET_IO_SPACE_MAP            GetIoSpaceMap;  //返回处理器全局一致性域中的I/O资源的映射。

  //
  // Dispatcher Services
  //
  EFI_DISPATCH                    Dispatch;//从固件卷加载和执行DXE驱动程序。
  EFI_SCHEDULE                    Schedule;//清除存储在固件卷中的组件的SOR (Schedule on Request)标志。
  EFI_TRUST                       Trust;//将存储在固件卷中的文件从不受信任状态提升到受信任状态。
  //
  // Service to process a single firmware volume found in a capsule
  //
  EFI_PROCESS_FIRMWARE_VOLUME     ProcessFirmwareVolume;//为系统内存中的固件卷创建一个固件卷句柄。
} EFI_DXE_SERVICES;
  • 7
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值