没有合适的资源?快使用搜索试试~ 我知道了~
首页《UEFI内核导读》-样章20211105.pdf
《UEFI内核导读》-样章2021/11/05更新 第23篇Secure Boot简介 133 第24篇Open source UEFI BIOS开发实战简介 139 第25篇 How to rotate Screen 143 第26篇Platform Environment Control Interface简介 146
资源详情
资源推荐
UEFI 内核导读
16
Source8 = (CHAR8 *) ((UINTN) FileHandle + FileOffset);
if (Destination8 != Source8) {
CopyMem (Destination8, Source8, *ReadSize);
}
return EFI_SUCCESS;
}
综上述代码可见:
1. PEI Core 及部分 PEIM 在 PEI 第一阶段被复制到 RAM 当中,PEI 第二阶段代码在 RAM 中被执行。
2. 使用内存拷贝的方法,在 X86 架构中使用的是 MOV 类指令,而不是 IN/OUT 类似的 IO 指令。
3. PEI Core 的 Image service 基于 PeiImageRead()从 flash 的读取 BFV 内的 FFS 文件并从中查
找 PE/TE 格式可执行文件,relocates 到永久 DDR RAM 当中以备 PEI 第二阶段执行,或读取查找
其他类型文件。
参考代码实现:
\MdeModulePkg\Core\Pei\Image\Image.c
\MdeModulePkg\Core\Dxe\Image\Image.c
UEFI 内核导读
17
第 1.2 篇 PEI Notify
在 UEFI 当中的 PEI 阶段我们经常使用一个叫做 Notify 的工具来进行不同的 PEIM 模块通信和交换数
据(callback 函数的入口参数为 PPI 指针,可以指向数据,也可以指向 PPI 描述符),这里来简单介绍
下 Notify。
PI SPC 定义了 PEIM 能都调用的系统服务,其中对 Notify 是这样定义 Notify 的:NotifyPpi
() Installs the notification service to be called back upon the installation or
reinstallation of a given interface. 可见当我们 install 一个 PPI 或者 reinstall 一个 PPI 的时候
PEICore 就会帮助我们自动的调用我们在之前注册的 callback 服务。PPI descriptor 有两种分是
EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH 和 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,从下图可以
看出二者的差别,这种差别会在 PEICore 当中体现出来。
下面从代码的角度来简要分析下 Notiry 的实现。
1.PPI 描述符,这个将会被 install 到 PPI 的数据库当中去。
typedef struct {
/// This field is a set of flags describing the characteristics of this imported
table entry.
/// All flags are defined as EFI_PEI_PPI_DESCRIPTOR_***, which can also be
combined into one.
UINTN Flags;
/// The address of the EFI_GUID that names the interface.
EFI_GUID *Guid;
/// A pointer to the PPI. It contains the information necessary to install a
service.
VOID *Ppi;
} EFI_PEI_PPI_DESCRIPTOR;
2.Notify 描述符,最终也会被注册到 PPI 数据库当中去,当对应的 PPI 被 install 的时候就会被调用。
UEFI 内核导读
18
struct _EFI_PEI_NOTIFY_DESCRIPTOR {
/// Details if the type of notification are callback or dispatch.
UINTN Flags;
/// The address of the EFI_GUID that names the interface.
EFI_GUID *Guid;
/// Address of the notification callback function itself within the PEIM.
EFI_PEIM_NOTIFY_ENTRY_POINT Notify;
};
3.当某个 Notify 触发的时候这个服务会被自动调用。
typedef
EFI_STATUS
(EFIAPI *EFI_PEIM_NOTIFY_ENTRY_POINT)(
IN EFI_PEI_SERVICES **PeiServices,
IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
IN VOID *Ppi
);
4.以下是 PPI 数据库的实现,基本上就是一个包含了 PPI 描述符和 Notify 描述符指针的数组,PPI 和和
Notify 分别处于数组的两端,数组的长度可以在编译阶段通过 PCD 服务来控制和调整,PCICore 会使用
PEI_PPI_DATABASE 来定义一个实例,用来管理全局的 PPI 和 Notify。
typedef union {
EFI_PEI_PPI_DESCRIPTOR *Ppi;
EFI_PEI_NOTIFY_DESCRIPTOR *Notify;
VOID *Raw;
} PEI_PPI_LIST_POINTERS; //共同体在 PpiListPtrs 里面可以根据数据类型灵活的调用空指针*Raw。
/// PPI database structure which contains two link: PpiList and NotifyList. PpiList
/// is in head of PpiListPtrs array and notify is in end of PpiListPtrs.
typedef struct {
/// index of end of PpiList link list.
INTN PpiListEnd;
/// index of end of notify link list.
INTN NotifyListEnd;
/// index of the dispatched notify list.
INTN DispatchListEnd;
/// index of last installed Ppi description in PpiList link list.
INTN LastDispatchedInstall;
/// index of last dispatched notify in Notify link list.
INTN LastDispatchedNotify;
/// Ppi database.
PEI_PPI_LIST_POINTERS PpiListPtrs[FixedPcdGet32 (PcdPeiCoreMaxPpiSupported)];
UEFI 内核导读
19
} PEI_PPI_DATABASE;
5.来看下 PPI 服务是如何实现的。
a.从下面可以看到我们在初始的时候,NotifyListEnd,DispatchListEnd ,LastDispatchedNotify 都
指向 PPI 数组 PpiListPtrs 的尾端,而 PpiListPtrs 的内容则为空。
这里我们 还要注意的一个东西就是他的传入参数,PrivateDate,其实这个就是 PEICore 的核心数据结
构,我们的 PPI 数据库就存在于这个里面,使用 PrivateData->PpiData 就能访问到 PPI 数据库。它开始
存在于 CAR 的当中,之后当内存被初始化之后就存在于内存中。
Initialize PPI services.
@param PrivateData Pointer to the PEI Core data.
@param OldCoreData Pointer to old PEI Core data.
NULL if being run in non-permament memory mode.
**/
VOID
InitializePpiServices (
IN PEI_CORE_INSTANCE *PrivateData,
IN PEI_CORE_INSTANCE *OldCoreData
)
{
if (OldCoreData == NULL) {
PrivateData->PpiData.NotifyListEnd = FixedPcdGet32 (PcdPeiCoreMaxPpiSupported)-1;
PrivateData->PpiData.DispatchListEnd = FixedPcdGet32 (PcdPeiCoreMaxPpiSupported)-1;
PrivateData->PpiData.LastDispatchedNotify = FixedPcdGet32 (PcdPeiCoreMaxPpiSupported)-
1;
}
}
b.再看下怎么 installPPI 就知道 PPI 数据库是如何添加数据进去的,当然这里的数据就是 PPI。
/**
This function installs an interface in the PEI PPI database by GUID.
The purpose of the service is to publish an interface that other parties
can use to call additional PEIMs.
@param PeiServices An indirect pointer to the EFI_PEI_SERVICES
table published by the PEI Foundation.
@param PpiList Pointer to a list of PEI PPI Descriptors.
@retval EFI_SUCCESS if all PPIs in PpiList are successfully
installed.
@retval EFI_INVALID_PARAMETER if PpiList is NULL pointer
if any PPI in PpiList is not valid
@retval EFI_OUT_OF_RESOURCES if there is no more memory resource to install PPI
**/
UEFI 内核导读
20
EFI_STATUS
EFIAPI
PeiInstallPpi (
IN CONST EFI_PEI_SERVICES **PeiServices,
IN CONST EFI_PEI_PPI_DESCRIPTOR *PpiList
)
{
PEI_CORE_INSTANCE *PrivateData;
INTN Index;
INTN LastCallbackInstall;
if (PpiList == NULL) { //判断服务的前置条件,是否合法
return EFI_INVALID_PARAMETER;
}
PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS(PeiServices);
//通过 PS 指针来获取核心的 PEICore 数据结构
Index = PrivateData->PpiData.PpiListEnd;
//获取 PPI 数据库中最后一个 PPI+1【从 0~(Index-1)个已经被占用,第 Index 个是空闲】,注
意 PPI 数据库是一个线性的数组。下标从【0,1,........PcdPeiCoreMaxPpiSupported-1】
LastCallbackInstall = Index;//先缓存起来
// This is loop installs all PPI descriptors in the PpiList. It is terminated
// by the EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST being set in the last
// EFI_PEI_PPI_DESCRIPTOR in the list.
for (;;) {
// Since PpiData is used for NotifyList and PpiList, max resource
// is reached if the Install reaches the NotifyList
// PcdPeiCoreMaxPpiSupported can be set to a larger value in DSC to satisfy more PPI
requirement.
//
if (Index == PrivateData->PpiData.NotifyListEnd + 1) {
//查看是否 PPI 数据库已经满了,如果满了的话就溢出错误,然后返回。
return EFI_OUT_OF_RESOURCES;
}
// Check if it is a valid PPI.
// If not, rollback list to exclude all in this list.
// Try to indicate which item failed.
//
if ((PpiList->Flags & EFI_PEI_PPI_DESCRIPTOR_PPI) == 0) {
PrivateData->PpiData.PpiListEnd = LastCallbackInstall;
剩余150页未读,继续阅读
Cstyle_0x007
- 粉丝: 471
- 资源: 7
上传资源 快速赚钱
- 我的内容管理 收起
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
会员权益专享
最新资源
- 电力电子系统建模与控制入门
- SQL数据库基础入门:发展历程与关键概念
- DC/DC变换器动态建模与控制方法解析
- 市***专有云IaaS服务:云主机与数据库解决方案
- 紫鸟数据魔方:跨境电商选品神器,助力爆款打造
- 电力电子技术:DC-DC变换器动态模型与控制
- 视觉与实用并重:跨境电商产品开发的六重价值策略
- VB.NET三层架构下的数据库应用程序开发
- 跨境电商产品开发:关键词策略与用户痛点挖掘
- VC-MFC数据库编程技巧与实现
- 亚马逊新品开发策略:选品与市场研究
- 数据库基础知识:从数据到Visual FoxPro应用
- 计算机专业实习经验与项目总结
- Sparkle家族轻量级加密与哈希:提升IoT设备数据安全性
- SQL数据库期末考试精选题与答案解析
- H3C规模数据融合:技术探讨与应用案例解析
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功