继续我们的研究。从Log中可以看到,加载了ReportStatusCodeRouterPei.efi:
Loading PEIM A3610442-E69F-4DF3-82CA-2360C4031A23
Loading PEIM at 0x000008470A0 EntryPoint=0x000008475A0 ReportStatusCodeRouterPei.efi
对应代码位于\MdeModulePkg\Universal\ReportStatusCodeRouter\Pei目录下:
/**
Entry point of Status Code PEIM.
This function is the entry point of this Status Code Router PEIM.
It produces Report Stataus Code Handler PPI and Status Code PPI.
@param FileHandle Handle of the file being invoked.
@param PeiServices Describes the list of possible PEI Services.
@retval EFI_SUCESS The entry point of DXE IPL PEIM executes successfully.
**/
EFI_STATUS
EFIAPI
GenericStatusCodePeiEntry (
IN EFI_PEI_FILE_HANDLE FileHandle,
IN CONST EFI_PEI_SERVICES **PeiServices
)
接下来Log 如下:
Install PPI: 0065D394-9951-4144-82A3-0AFC8579C251
Install PPI: 229832D3-7A30-4B36-B827-F40CB7D45436
这两个 GUID 在 \MdePkg\MdePkg.dec 有定义:
## Include/Ppi/ReportStatusCodeHandler.h
gEfiPeiRscHandlerPpiGuid = { 0x65d394, 0x9951, 0x4144, {0x82, 0xa3, 0xa, 0xfc, 0x85, 0x79, 0xc2, 0x51 }}
## Include/Ppi/StatusCode.h
gEfiPeiStatusCodePpiGuid = { 0x229832d3, 0x7a30, 0x4b36, {0xb8, 0x27, 0xf4, 0xc, 0xb7, 0xd4, 0x54, 0x36 } }
这个里面比较有意思的是这里面注册了2个Ppi,其中一个是 ReportStatusCode的Ppi,另外一个是用来给ReportStatusCode 注册实际工作的函数,接下来的模块会调用这个Ppi能够让我们理解实际动作。
继续查看 Log 有如下:
Loading PEIM 9D225237-FA01-464C-A949-BAABC02D31D0
Loading PEIM at 0x0000084BFA0 EntryPoint=0x0000084C4A0 StatusCodeHandlerPei.efi
StatusCodeHandlerPei对应的代码位于 \MdeModulePkg\Universal\StatusCodeHandler\Pei目录
/**
Entry point of Status Code PEIM.
This function is the entry point of this Status Code PEIM.
It initializes supported status code devices according to PCD settings,
and installs Status Code PPI.
@param FileHandle Handle of the file being invoked.
@param PeiServices Describes the list of possible PEI Services.
@retval EFI_SUCESS The entry point of DXE IPL PEIM executes successfully.
**/
EFI_STATUS
EFIAPI
StatusCodeHandlerPeiEntry (
IN EFI_PEI_FILE_HANDLE FileHandle,
IN CONST EFI_PEI_SERVICES **PeiServices
)
{
EFI_STATUS Status;
EFI_PEI_RSC_HANDLER_PPI *RscHandlerPpi;
Status = PeiServicesLocatePpi (
&gEfiPeiRscHandlerPpiGuid,
0,
NULL,
(VOID **) &RscHandlerPpi
);
ASSERT_EFI_ERROR (Status);
//
// Dispatch initialization request to sub-statuscode-devices.
// If enable UseSerial, then initialize serial port.
// if enable UseMemory, then initialize memory status code worker.
//
if (PcdGetBool (PcdStatusCodeUseSerial)) {
Status = SerialPortInitialize();
ASSERT_EFI_ERROR (Status);
Status = RscHandlerPpi->Register (SerialStatusCodeReportWorker);
ASSERT_EFI_ERROR (Status);
}
if (PcdGetBool (PcdStatusCodeUseMemory)) {
Status = MemoryStatusCodeInitializeWorker ();
ASSERT_EFI_ERROR (Status);
Status = RscHandlerPpi->Register (MemoryStatusCodeReportWorker);
ASSERT_EFI_ERROR (Status);
}
return EFI_SUCCESS;
}
就是说通过 RscHandlerPpi 注册了2个Callback函数SerialStatusCodeReportWorker 和MemoryStatusCodeReportWorker。当有人使用 ReportStatusCode时,会先后进入 SerialStatusCodeReportWorker() 和MemoryStatusCodeReportWorker()。
再进一步检查,在\OvmfPkg\OvmfPkgX64.dsc 有如下定义:
gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseSerial|FALSE
gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseMemory|TRUE
从 PCD可以看到在 OVMF 中,没有使用 SerialStatusCodeReportWorker。当代码使用了ReportStatusCode时,会执行MemoryStatusCodeReportWorker()。
这是一种非常巧妙的实现,有兴趣的朋友可以研究 \MdeModulePkg\Universal\ReportStatusCodeRouter\Pei\ReportStatusCodeRouterPei.c 这个文件。
博主,您好,请问这种巧妙的设计有什么作用呢?
我觉得这样的设计是为了方便扩展,用户很容易实现将调试信息发送到自定义的设备上。