看图粗略说一下:
SEC:
安全验证阶段,这个阶段,需要用Assembly做一些 C 无法处理的工作,C语言无法处理CPU的特殊寄存器。让CPU进入Protected Mode(Flat Mode)的环境,会使用到CPU内部的临时ram,其实也就是缓存,这个阶段主要还是使用的汇编,也就是说为后面的阶段建立一个C语言和硬件通信的编译环境,最后将控制权交给PEI Phase。
PEI:
很基本的Chipset 初始化、 Memory Sizing、 BIOS Recovery、 ACPI S3 Resume 、切换Stack to Memory、启动DxeIpl。这个阶段就是开始一些CPU、主板、芯片的初始化了,也就是EFI前期初始化,这个阶段后期才是内存的初始化,知道内存初始化的地方可以便于debug。PEI阶段对系统的初始化主要是PEIM完成的,PEIM之间的通信又是通过PPI完成,进入DXE阶段需要HOB列表。
HOB : Hand off Block
有些 information 要从 PEI Phase 传到 DXE Phase 组成 ,每一个Block有自己的GUID & Structure 。HOB的Block List是动态的,没有顺序要求。
DXE:
遍历固件中的所有的DXE driver,也就是驱动执行环境,当然了,DXE阶段也有DXE派遣器,通信通过protocol,也就是协议。当所有的 dxe driver加载完成后,系统完成初始化,DXE通过EFI_BDS_ARCH_PROTOCOL找到BDS并调用BDS的入口函数,从而进入BDS阶段,从本质上讲,BDS是一种特殊的DXE阶段的应用程序。
BDS:
BDS:Boot Device Selection,启动必要的驱动程序,启动设备选择。BDS策略通过全局NVRAM变量配置,通过修改变量值修改启动顺序(bootorder),这个修改启动顺序在工厂需要经常用到的,工厂都是批量生产,因此需要写个工具给产线TE,批量修改启动顺序。
TSL:
操作系统加载器执行的第一阶段,在这一阶段OS Loader作为一个UEFI应用程序运行,系统资源仍然由UEFI内核控制。
RT:
Run Time,系统控制权从UEFI内核转交到OS Loader手中。
上述是很久之前写的,直接copy了,现在回过头来看,其实这样写是很笼统的,这次,咱们就追踪一下代码,看它到底是怎么跑的吧:
代码追踪
由于目前手上使用的是made in china cpu(ARM)的,所以仅针对这个平台做一下代码追踪,
首先SEC,这里面的汇编代码就不细说了,就说一下SEC跑完了,会进入C,汇编load的就是这个c入口的地址,进入PEI阶段后,这里有个前期和后期的区分,看下代码:
VOID
CEntryPoint (
IN UINTN MpId,
IN EFI_PEI_CORE_ENTRY_POINT PeiCoreEntryPoint
)
{
CHAR8 Char;
// Data Cache enabled on Primary core when MMU is enabled.
//ArmDisableDataCache ();
// Invalidate Data cache
//ArmInvalidateDataCache ();
// Invalidate instruction cache
//ArmInvalidateInstructionCache ();
// Enable Instruction Caches on all cores.
Char = 'A';
SerialPortWrite ((UINT8 *)&Char, 1);
ArmEnableInstructionCache ();
Char = 'B';
SerialPortWrite ((UINT8 *)&Char, 1);
该代码在ArmPlatformPkg/PrePeiCore/PrePeiCore.c,跑啊跑,最后跑到
// Goto primary Main.
PrimaryMain (PeiCoreEntryPoint);
// Jump to PEI core entry point
DEBUG((EFI_D_INFO, "%a() Line=%d \n", __FUNCTION__, __LINE__));
(PeiCoreEntryPoint)(&SecCoreData, PpiList);
这个PeiCoreEntryPoint不就是_ModuleEntryPoint,PEI image的入口函数,_ModuleEntryPoint最终又调用MdeModulePkg\Core\Pei\PeiMain.c中的函数PeiCore,进入PeiCore后,先根据SEC传入的信息设置PEI CORE services
//
// Initialize PEI Core Services
//
InitializeMemoryServices (&PrivateData, SecCoreData, OldCoreData);
然后调用PeiDispatcher执行系统中的PEIM,这个过程需要用到PPI协议,调度系统中的PEIM的过程中就有提供CPU相关功能,例如Cache设置、主频设置,有内存初始化、IO控制器,内存控制器等等,这一部分在PlatformPei.efi中实现,通过拉取PBF中的内容,拉取后再运行MemoryInit.efi,当内存初始化后,系统会重新发生栈切换并第二次进入PeiCore,重新进入后使用的内存就是我们熟悉的内存,然后再运行CpuPei.efi,最终准备HOB列表,利用DXE IPL PPI找到DXE image的入口函数,执行入口函数并将hob列表传递给DXE,这里主要在DxeIpl.efi中运行,运行完了,就进入DxeCore.efi里面并最终通过gBds->Entry (gBds)进入BdsDxe。
之所以写这么多,主要是因为本人想自己重新做一个postcode,写在这里也是笔记,特别是在启动界面挂了,还能发现问题,我觉得这个idea非常不错
UINT32
EFIAPI
PostCode (
IN UINT32 Value
)
{
Value &= 0xFFF;
//Get the StatusCode set using GetPhaseStatusCode
Value |= GetPhaseStatusCode();
IoWrite32 (0x80, Value);
DEBUG ((DEBUG_INFO, "POSTCODE=<%08x>\n", Value));
return Value;
}
ok,启动流程就先写到这里。。。。