PEIM到底具体做什么事情 以PcdPeim为例

            做为一个BIOS工程师,在去找工作的时候,必然会被问到 pei是什么, dxe 是什么, 大家必然会回答 做各种初始化,那具体到一支PEIM, 或者一个DXE 驱动,它到底做了啥,又是怎么做的呢?

           今天就以PcdPeim 为例,详细说说一支PEIM的工作原理。

PCD 翻译成中文叫平台配置数据信息, Platform  Configuration Database, 这个在ami 代码里面叫token位于skl 文件里面,对于oem里面的工程师大部分时间

都是改这些token的值,所以某种程度上,BIOS 工程师也叫token 工程师。

        书归正转,具体干了什么,还得看代码:

/**
  Main entry for PCD PEIM driver.
  
  This routine initialize the PCD database for PEI phase and install PCD_PPI/EFI_PEI_PCD_PPI.

  @param  FileHandle  Handle of the file being invoked.
  @param  PeiServices Describes the list of possible PEI Services.

  @return Status of install PCD_PPI

**/
EFI_STATUS
EFIAPI
PcdPeimInit (
  IN       EFI_PEI_FILE_HANDLE  FileHandle,
  IN CONST EFI_PEI_SERVICES     **PeiServices
  )
{
  EFI_STATUS Status;

  BuildPcdDatabase (FileHandle);

  //
  // Install PCD_PPI and EFI_PEI_PCD_PPI.
  //
  Status = PeiServicesInstallPpi (&mPpiList[0]);
  ASSERT_EFI_ERROR (Status);

  //
  // Install GET_PCD_INFO_PPI and EFI_GET_PCD_INFO_PPI.
  //
  Status = PeiServicesInstallPpi (&mPpiList2[0]);
  ASSERT_EFI_ERROR (Status);

  return Status;
}


首先它构建了pcd database

其次它安装了两个PPI. 用于支持动态PCD在运行时被设置和访问

这两个Ppi 具体是什么,我们只需要在同名文件里去搜索mPpiList 就行了,

然后它的第三个参数就是PPI实例

///
/// Instance of PCD_PPI protocol is EDKII native implementation.
/// This protocol instance support dynamic and dynamicEx type PCDs.
///
PCD_PPI mPcdPpiInstance = {
  PeiPcdSetSku,

  PeiPcdGet8,
  PeiPcdGet16,          
  PeiPcdGet32,          
  PeiPcdGet64,          
  PeiPcdGetPtr,         
  PeiPcdGetBool,     
  PeiPcdGetSize,

  PeiPcdGet8Ex,
  PeiPcdGet16Ex,          
  PeiPcdGet32Ex,          
  PeiPcdGet64Ex,          
  PeiPcdGetPtrEx,         
  PeiPcdGetBoolEx,     
  PeiPcdGetSizeEx,
  
  PeiPcdSet8,
  PeiPcdSet16,          
  PeiPcdSet32,          
  PeiPcdSet64,          
  PeiPcdSetPtr,         
  PeiPcdSetBool,     

  PeiPcdSet8Ex,
  PeiPcdSet16Ex,          
  PeiPcdSet32Ex,          
  PeiPcdSet64Ex,          
  PeiPcdSetPtrEx,         
  PeiPcdSetBoolEx,

  PeiRegisterCallBackOnSet,
  PcdUnRegisterCallBackOnSet,
  PeiPcdGetNextToken,
  PeiPcdGetNextTokenSpace
};

可以很清楚的看到,就是对各种类型(长度)数据的get 和set.

重要数据结构的说明:

第一个当然是对DATABASE的说明:

//
// PEI and DXE Pcd driver use the same PCD database
//
typedef PCD_DATABASE_INIT  PEI_PCD_DATABASE;
typedef PCD_DATABASE_INIT  DXE_PCD_DATABASE;


在PEI 阶段和DXE 阶段,用的是同一个数据库

typedef struct {
    GUID                  Signature;            // PcdDataBaseGuid.
    UINT32                BuildVersion;
    UINT32                Length;
    UINT32                UninitDataBaseSize;   // Total size for PCD those default value with 0.
    TABLE_OFFSET          LocalTokenNumberTableOffset;
    TABLE_OFFSET          ExMapTableOffset;
    TABLE_OFFSET          GuidTableOffset;
    TABLE_OFFSET          StringTableOffset;
    TABLE_OFFSET          SizeTableOffset;
    TABLE_OFFSET          SkuIdTableOffset;
    TABLE_OFFSET          PcdNameTableOffset;
    UINT16                LocalTokenCount;      // LOCAL_TOKEN_NUMBER for all.
    UINT16                ExTokenCount;         // EX_TOKEN_NUMBER for DynamicEx.
    UINT16                GuidTableCount;       // The Number of Guid in GuidTable.
    SKU_ID                SystemSkuId;          // Current SkuId value.
    UINT8                 Pad;                  // Pad bytes to satisfy the alignment.

    //
    // Default initialized external PCD database binary structure
    //
    // Padding is needed to keep necessary alignment
    //
    //UINT64                         ValueUint64[];
    //UINT32                         ValueUint32[];
    //VPD_HEAD                       VpdHead[];               // VPD Offset
    //DYNAMICEX_MAPPING              ExMapTable[];            // DynamicEx PCD mapped to LocalIndex in LocalTokenNumberTable. It can be accessed by the ExMapTableOffset.
    //UINT32                         LocalTokenNumberTable[]; // Offset | DataType | PCD Type. It can be accessed by LocalTokenNumberTableOffset.
    //GUID                           GuidTable[];             // GUID for DynamicEx and HII PCD variable Guid. It can be accessed by the GuidTableOffset.
    //STRING_HEAD                    StringHead[];            // String PCD
    //PCD_NAME_INDEX                 PcdNameTable[];          // PCD name index info. It can be accessed by the PcdNameTableOffset.
    //VARIABLE_HEAD                  VariableHead[];          // HII PCD
    //SKU_HEAD                       SkuHead[];               // Store SKU info for each PCD with SKU enable.
    //UINT8                          StringTable[];           // String for String PCD value and HII PCD Variable Name. It can be accessed by StringTableOffset.
    //SIZE_INFO                      SizeTable[];             // MaxSize and CurSize for String PCD. It can be accessed by SizeTableOffset.
    //UINT16                         ValueUint16[];
    //UINT8                          ValueUint8[];
    //BOOLEAN                        ValueBoolean[];
    //UINT8                          SkuIdTable[];            // SkuIds system supports.
    //UINT8                          SkuIndexTable[];         // SkuIds for each PCD with SKU enable.

} PCD_DATABASE_INIT;

这个结构体用于描述动态PCD的各种信息,Init 成员记录扩展PCD 的成员,GUID 数组,String 类型的数据及skuId



关键内部函数

在实现PcdPpi服务时,许多相关的内部函数被使用。他们是:GetPcdDatabase(), GetWorker(), GetPtrTypeSize(), GetExPcdTokenNumber(),

ExGetWorker(). 其中Get相关的函数是负责读取动态PCD的信息,Set相关的函数是负责更新动态PCD的值,注册回调函数是负责注册或者注销

回调函数。现在对这些主要的内部函数做进一步的介绍。


GetPcdDatabase() 函数,实现Pcd\Service.c

/**
  Get PCD database from GUID HOB in PEI phase.

  @return Pointer to PCD database.

**/
PEI_PCD_DATABASE *
GetPcdDatabase (
  VOID
  )
{
  EFI_HOB_GUID_TYPE *GuidHob;

  GuidHob = GetFirstGuidHob (&gPcdDataBaseHobGuid);
  ASSERT (GuidHob != NULL);
  
  return (PEI_PCD_DATABASE *) GET_GUID_HOB_DATA (GuidHob);
}


通过GUID 查找GUID类型的HOB数据块,并返回找到动态PCD的数据库。


PcdPei 入口函数

PcdPeimInit() 函数,实现在Pcd\Pcd.c 。 创建数据库用于维护PEI 阶段使用的动态PCD, 同时安装两个

PcdPpi支持动态PCD 在运行时被设置和访问。注意只有动态(dynamic) 类型的PCD ,才有数据库这个概念,

说明数据库,大家也不要想复杂了,就是一个结构体,然后搞一个数组,里面挨个放着Pcd。


安装的Ppi, 既然是处于pei 阶段,就要安装ppi, 要不然,别人(别的模块)没法调用,在pei 阶段的描述符典型的就两个:

EFI_PEI_PPI_DESCRIPTOR  mPpiList[] = {
  {
    EFI_PEI_PPI_DESCRIPTOR_PPI,
    &gPcdPpiGuid,
    &mPcdPpiInstance
  },
  {
    (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
    &gEfiPeiPcdPpiGuid,
    &mEfiPcdPpiInstance
  }
};

EFI_PEI_PPI_DESCRIPTOR  mPpiList2[] = {
  {
    EFI_PEI_PPI_DESCRIPTOR_PPI,
    &gGetPcdInfoPpiGuid,
    &mGetPcdInfoInstance
  },
  {
    (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
    &gEfiGetPcdInfoPpiGuid,
    &mEfiGetPcdInfoInstance
  }
};





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值