当前位置: 代码迷 >> 综合 >> variable Architecture protocol 的安装
  详细解决方案

variable Architecture protocol 的安装

热度:82   发布时间:2024-02-23 05:00:48.0

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 等。

 

  相关解决方案