variable Architecture protocol 的安装

variable architecture protocol 是pi 规范中定义的架构协议。安装此协议的驱动是运行时驱动。

它负责注册variable 的运行时服务(variable Runtime Service). UEFI 规范定义了4个variable 运行时服务:

GetVariable, GetNextVariableName, SetVariable 和QueryVariableInfo.

 

  SystemTable->RuntimeServices->GetVariable         = VariableServiceGetVariable;
  SystemTable->RuntimeServices->GetNextVariableName = VariableServiceGetNextVariableName;
  SystemTable->RuntimeServices->SetVariable         = VariableServiceSetVariable;
  SystemTable->RuntimeServices->QueryVariableInfo   = VariableServiceQueryVariableInfo;

  //
  // Now install the Variable Runtime Architectural protocol on a new handle.
  //
  Status = gBS->InstallProtocolInterface (
                  &mHandle,
                  &gEfiVariableArchProtocolGuid,
                  EFI_NATIVE_INTERFACE,
                  NULL
                  );
  ASSERT_EFI_ERROR (Status);

Variable Write Architecture Protocol 也是pi 规范中定义的架构协议。该协议的安装意味着非易失性变量(

non-volative variable) 读定的操作已经就绪。跟易失性变量(non - volative variable ) 读写的操作不同, non-volatile variable 读写需要借助于底层接口来操作非易失性存储人质, 如flash 芯片。

MdeModulePkg\Universal\Variable\RuntimeDxe\VariableDxe.c

  //
  // Now install the Variable Runtime Architectural protocol on a new handle.
  //
  Status = gBS->InstallProtocolInterface (
                  &mHandle,
                  &gEfiVariableArchProtocolGuid,
                  EFI_NATIVE_INTERFACE,
                  NULL
                  );
  ASSERT_EFI_ERROR (Status);

  //
  // Register FtwNotificationEvent () notify function.
  //
  EfiCreateProtocolNotifyEvent (
    &gEfiFaultTolerantWriteProtocolGuid,
    TPL_CALLBACK,
    FtwNotificationEvent,
    (VOID *)SystemTable,
    &mFtwRegistration
    );

注册Notify 函数FtwNotificationEvent(), 当gEfiFaultTolerantWriteProtocolGuid 安装,执行该函数。该函数通过对应的FVB Protocol 来封装底层非易失性存储介质的读写操作,最后,该函数安装Variable Write Architecture Protocol 来表示对Non volatile variable 的读写已经读绪。

 

Variable 相关关键数据结构

typedef struct {
  EFI_PHYSICAL_ADDRESS  HobVariableBase;
  EFI_PHYSICAL_ADDRESS  VolatileVariableBase;
  EFI_PHYSICAL_ADDRESS  NonVolatileVariableBase;
  EFI_LOCK              VariableServicesLock;
  UINT32                ReentrantState;
  BOOLEAN               AuthFormat;
  BOOLEAN               AuthSupport;
  BOOLEAN               EmuNvMode;
} VARIABLE_GLOBAL;

typedef struct {
  VARIABLE_GLOBAL VariableGlobal;
  UINTN           VolatileLastVariableOffset;
  UINTN           NonVolatileLastVariableOffset;
  UINTN           CommonVariableSpace;
  UINTN           CommonMaxUserVariableSpace;
  UINTN           CommonRuntimeVariableSpace;
  UINTN           CommonVariableTotalSize;
  UINTN           CommonUserVariableTotalSize;
  UINTN           HwErrVariableTotalSize;
  UINTN           MaxVariableSize;
  UINTN           MaxAuthVariableSize;
  UINTN           MaxVolatileVariableSize;
  UINTN           ScratchBufferSize;
  CHAR8           *PlatformLangCodes;
  CHAR8           *LangCodes;
  CHAR8           *PlatformLang;
  CHAR8           Lang[ISO_639_2_ENTRY_SIZE + 1];
  EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbInstance;
} VARIABLE_MODULE_GLOBAL;

VARIABLE_MODULE_GLOBAL 结构描述了全局分配的资源。其中, VARIABLE_GLOBAL结构的VolatileVariableBase

指向系统为易失性变量分配的内存空间;NonVolatileVariableBase 则是指向非易失性变量存储空间。 VolatileLastVariableOffset ,NonVolatileLastVariableOffset 分别用来记录各自空间中最后一个Variable 距离起始地址的偏移量。

VARIABLE_STORE_HEADER 数据结构

///
/// Variable Store region header.
///
typedef struct {
  ///
  /// Variable store region signature.
  ///
  EFI_GUID  Signature;
  ///
  /// Size of entire variable store,
  /// including size of variable store header but not including the size of FvHeader.
  ///
  UINT32  Size;
  ///
  /// Variable region format state.
  ///
  UINT8   Format;
  ///
  /// Variable region healthy state.
  ///
  UINT8   State;
  UINT16  Reserved;
  UINT32  Reserved1;
} VARIABLE_STORE_HEADER;

整个变量存储空间是以VARIABLE_STORE_HEADER 结构开始,该结构记录整个存储空间的特性。其中Signature 域为存储格式签名,size 域为存储空间的大小, VARIABLE_STORE_HEADER 结构之后,依次存放着各个变量。

MdeModulePkg\Universal\Variable\RuntimeDxe\Variable.c

  //
  // Initialize Variable Specific Data.
  //
  mVariableModuleGlobal->VariableGlobal.VolatileVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VolatileVariableStore;
  mVariableModuleGlobal->VolatileLastVariableOffset = (UINTN) GetStartPointer (VolatileVariableStore) - (UINTN) VolatileVariableStore;

  CopyGuid (&VolatileVariableStore->Signature, VariableGuid);
  VolatileVariableStore->Size        = PcdGet32 (PcdVariableStoreSize);
  VolatileVariableStore->Format      = VARIABLE_STORE_FORMATTED;
  VolatileVariableStore->State       = VARIABLE_STORE_HEALTHY;
  VolatileVariableStore->Reserved    = 0;
  VolatileVariableStore->Reserved1   = 0;

Volatile 类型存储空间的VARIABLE_STORE_HEADER 的初始化。

 

VARIABLE_HEADER 数据结构

///
/// Single Variable Data Header Structure.
///
typedef struct {
  ///
  /// Variable Data Start Flag.
  ///
  UINT16      StartId;
  ///
  /// Variable State defined above.
  ///
  UINT8       State;
  UINT8       Reserved;
  ///
  /// Attributes of variable defined in UEFI specification.
  ///
  UINT32      Attributes;
  ///
  /// Size of variable null-terminated Unicode string name.
  ///
  UINT32      NameSize;
  ///
  /// Size of the variable data without this header.
  ///
  UINT32      DataSize;
  ///
  /// A unique identifier for the vendor that produces and consumes this varaible.
  ///
  EFI_GUID    VendorGuid;
} VARIABLE_HEADER;

每个变量的存储是以VARIABLE_HEADER 结构开始的,该结构描述了该变量的特性。每个变量都具有Name, Data 和Guid 成员,其中VARIABLE_HEADER 结构中NameSize 记录了该变量Name 的大小, DataSize 记录变变量的Data 的大小, VendorGuid 记录了该变量的guid 内容。

 

Variable 关键函数解析

MdeModulePkg\Universal\Variable\RuntimeDxe\Variable.c

EFI_STATUS
EFIAPI
VariableServiceSetVariable (
  IN CHAR16                  *VariableName,
  IN EFI_GUID                *VendorGuid,
  IN UINT32                  Attributes,
  IN UINTN                   DataSize,
  IN VOID                    *Data
  )

1. 创建一个新的varibale 时,会将该Variable 的heade.State 设置成var_add;

2 .删除一个已经存在的variable 时,仅仅将该Variable 的Header.State 域与上VAR_DELETED;

3. 更新一个已经存在的variable 时,会将该Variable 的Header.State 域与上var_in_deleted_transition & var_deleted. 同时创建一个新的variable. 它的header.state 设置成var_added;

EFI_STATUS
EFIAPI
VariableServiceGetVariable (
  IN      CHAR16            *VariableName,
  IN      EFI_GUID          *VendorGuid,
  OUT     UINT32            *Attributes OPTIONAL,
  IN OUT  UINTN             *DataSize,
  OUT     VOID              *Data OPTIONAL
  )

VariableServiceGetVariable 用来查找某一变量。

EFI_STATUS
EFIAPI
VariableServiceGetNextVariableName (
  IN OUT  UINTN             *VariableNameSize,
  IN OUT  CHAR16            *VariableName,
  IN OUT  EFI_GUID          *VendorGuid
  )

VariableServiceGetNextVariableName  用来返回下一个变量。

EFI_STATUS
Reclaim (
  IN     EFI_PHYSICAL_ADDRESS         VariableBase,
  OUT    UINTN                        *LastVariableOffset,
  IN     BOOLEAN                      IsVolatile,
  IN OUT VARIABLE_POINTER_TRACK       *UpdatingPtrTrack,
  IN     VARIABLE_HEADER              *NewVariable,
  IN     UINTN                        NewVariableSize
  )

通常,删除或更新一个已经存在的variable 时,将该variable 标识成DELETE 状态,但是它所占用的存储空间并没有释放出来,这样就会造成空间的浪费,因此此类Variable 被视为垃圾。

Reclaim 负责对variable 存储空间进行垃圾整理。

Reclaim 会遍历整个variable 存储空间,依次将所有有效的variable, 即header.State 域为var_added 或者var_in_deleted_transition & var_added. 读到内存中进行整理,然后再写回到variable 存储空间。

 

Runtime 相关的处理

作为运行时的服务,Variable Service 的API 需要能在OS 环境下被调用。因此,相关的全局指针需要在EVENT_SIGNAL_VIRTUAL_ADDRESS_CHANGE 时刻转化为虚拟地址。

  Status = gBS->CreateEventEx (
                  EVT_NOTIFY_SIGNAL,
                  TPL_NOTIFY,
                  VariableClassAddressChangeEvent,
                  NULL,
                  &gEfiEventVirtualAddressChangeGuid,
                  &mVirtualAddressChangeEvent
                  );
  ASSERT_EFI_ERROR (Status);

  //
  // Register the event handling function to reclaim variable for OS usage.
  //
  Status = EfiCreateEventReadyToBootEx (
             TPL_NOTIFY,
             OnReadyToBoot,
             NULL,
             &ReadyToBootEvent
             );
  ASSERT_EFI_ERROR (Status);

注册一个Notify 函数,将运行时所用到的指针转化成虚拟地址。

在ReadyToBoot 的时候,将非易失性变量存储空间垃圾进行整理,为os 环境下提供更多的存储空间。

 

Capsule Runtime Service

Capsule Runtime Service 介绍

应用程序或操作系统可以利用Capsule Service 与EFI 系统进行灵活的数据通信。典型的应用如: 调用者可以利用capsule service 进行固件升级(flash update); 操作系统可以利用capsule service 进行系统全面诊断。

 

Capsule Architecture Protocol 的安装

Capsule Architecture Protocol 是PI 规范中定义的架构协议。安装此协议的驱动是个运行时驱动(runtime Driver) , 它负责capsule 的运行时服务。 uefi 规范定义了2个capsule 运行时服务。 updateCapsule 和QueryCapsuleCapabilities 。

 

MdeModulePkg\Universal\CapsuleRuntimeDxe\CapsuleService.c

EFI_STATUS
EFIAPI
CapsuleServiceInitialize (
  IN EFI_HANDLE         ImageHandle,
  IN EFI_SYSTEM_TABLE   *SystemTable
  )
{
  EFI_STATUS  Status;

  mMaxSizePopulateCapsule = PcdGet32(PcdMaxSizePopulateCapsule);
  mMaxSizeNonPopulateCapsule = PcdGet32(PcdMaxSizeNonPopulateCapsule);

  //
  // When PEI phase is IA32, DXE phase is X64, it is possible that capsule data are
  // put above 4GB, so capsule PEI will transfer to long mode to get capsule data.
  // The page table and stack is used to transfer processor mode from IA32 to long mode.
  // Create the base address of page table and stack, and save them into variable.
  // This is not needed when capsule with reset type is not supported.
  //
  SaveLongModeContext ();

  //
  // Install capsule runtime services into UEFI runtime service tables.
  //
  gRT->UpdateCapsule                    = UpdateCapsule;
  gRT->QueryCapsuleCapabilities         = QueryCapsuleCapabilities;

  //
  // Install the Capsule Architectural Protocol on a new handle
  // to signify the capsule runtime services are ready.
  //
  Status = gBS->InstallMultipleProtocolInterfaces (
                  &mNewHandle,
                  &gEfiCapsuleArchProtocolGuid,
                  NULL,
                  NULL
                  );
  ASSERT_EFI_ERROR (Status);

  return Status;
}

 

2个Capsule 服务接口的注册。

Capsule Architecture Protocol 的安装。

 

Capsule 相关关键数据结构

EFI_CAPSULE_HEADER数据结构

MdePkg\Include\Uefi\UefiSpec.h

///
/// EFI Capsule Header.
///
typedef struct {
  ///
  /// A GUID that defines the contents of a capsule.
  ///
  EFI_GUID          CapsuleGuid;
  ///
  /// The size of the capsule header. This may be larger than the size of
  /// the EFI_CAPSULE_HEADER since CapsuleGuid may imply
  /// extended header entries
  ///
  UINT32            HeaderSize;
  ///
  /// Bit-mapped list describing the capsule attributes. The Flag values
  /// of 0x0000 - 0xFFFF are defined by CapsuleGuid. Flag values
  /// of 0x10000 - 0xFFFFFFFF are defined by this specification
  ///
  UINT32            Flags;
  ///
  /// Size in bytes of the capsule.
  ///
  UINT32            CapsuleImageSize;
} EFI_CAPSULE_HEADER;

每个capsule 都是capsule header 和capsule body 两部分组成。 capsule header 遵循EFI_CAPSULE_HEADER结构。 

capsule body 则是平台相关的, uefi 规范并未对此定义,通常实现为FV(Firmware Volume). EFI_CAPSULE_HEADER 结构描述了capsule 的特性, 其中capsuleGuid 用于标识capsule 身份,每个平台都可以通过该域来识别各自支持的capsule. Flags

域标识capsule 类型,该域说明capsule 需要什么样的处理, Flags 有如下定义:

#define CAPSULE_FLAGS_PERSIST_ACROSS_RESET          0x00010000
#define CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE         0x00020000
#define CAPSULE_FLAGS_INITIATE_RESET                0x00040000

CAPSULE_FLAGS_PERSIST_ACROSS_RESET 表明Capsule 需要在系统重启后得到处理。

CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE 表时capsule 需要系统在重启后将数据碎片(虚拟地址连续面物理地址可能不连续)整理成物理地址连续的内存,并安装在EFI SYSTEM TABLE 中,以供操作系统访问。一般该特性可被操作系统用用全面的系统诊断。

CAPSULE_FLAGS_INITIATE_RESET 表明Capsule 需要系统在系统重启后得到处理,并且由系统主动重启。

此外,如果Flags 为0 则表明Capsule 需要系统立即执行,无需系统重启。

注: 对于Capsule 而言,系统重启是指那些能保留内存数据不丢失的重启方式,如S3 等。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值