• BIOS Boot Flow 之SEC


    SEC

    作为BIOS ren,大家都知道BIOS Boot flow 的主要四个流程就是SEC,PEI,DXE,BDS

    那按顺序就先来讲讲SEC的东西,虽然作为ODM 基本也不会动这些,但折腾折腾总不是什么坏事

    在主板上电时序跑完之后,CPU完成自己的初始化后,指针则会指向 FFFF FFF0 这个地址,也就是从这,开始CPU的奇妙BIOS之旅~

    注:FFFF FFF0这个地址是基于4G寻址向下拓展实现(远古时期还有1M寻址向下拓展,也就是这个000F FFF0地址 )

    在早期认知当中,FFFF FFF0这个地址是一条跳转语句,但后续在研究这方面发现稍微有所不同,我们可以使用FlexHex 打开任一一个BIOS bin 文件,拉到最后面,会发现,实际执行的第一条的指令为0x90 0x90

    也就是Nop 指令,Trace Code后,在reset vector,前两条指令确实为Nop,第三条指令才是跳转(以下Code 均来自于EDK2,后续博文Code 也会基于EDK2)

    后基于百度的力量得知Nop指令是单纯历史原因,留下两条无意义的指令

    跳完之后继续跳,在CPU早期上电处于一个特殊的模式下,类似于real mode而不完全是,这些跳转的指令改变了CPU CS 指针,使其进入正常的real mode/flat mode

    继续跳转

    1. Main16:
    2. OneTimeCall EarlyInit16
    3. ;
    4. ; Transition the processor from 16-bit real mode to 32-bit flat mode
    5. ;
    6. OneTimeCall TransitionFromReal16To32BitFlat
    7. BITS 32
    8. ;
    9. ; Search for the Boot Firmware Volume (BFV)
    10. ;
    11. OneTimeCall Flat32SearchForBfvBase
    12. ;
    13. ; EBP - Start of BFV
    14. ;
    15. ;
    16. ; Search for the SEC entry point
    17. ;
    18. OneTimeCall Flat32SearchForSecEntryPoint
    19. ;
    20. ; ESI - SEC Core entry point
    21. ; EBP - Start of BFV
    22. ;

    Flat32SearchForBfvBase后就可以找到BFV,也就是我们的Boot firmware volume

    后续的指令跳转就不在一一枚举~

    下面聊一些SEC 中的东西

    早期上电阶段,没用Memory资源可以使用,SEC就做了CAR 功能,可以先让一些Code有堆栈跑起来,SEC主要做一些信任根,传递一些参数

    1.记录中断号与调用函数链接关系的IDT table

    2.EFI_SEC_PEI_HAND_OFF,这个数据结构含有 SEC-PEI  Core 握手交接控制权时所需的各种信息,如temp RAM 的地址和大小,栈的地址和 Boot Firmware Volume 的地址等

    IDT table如下:

    当Car后,IDT table也就有机会实现初始化,也就是SecCoreStartupWithStack函数实现

    另外除了IDT,这个函数也完成了Debug功能的初始化,我们的源代码调试自此之后就可以正常进行了

    EFI_SEC_PEI_HAND_OFF结构体的数据也在这个函数下完成了基本信息交互

    1. VOID
    2. EFIAPI
    3. SecCoreStartupWithStack (
    4. IN EFI_FIRMWARE_VOLUME_HEADER *BootFv,
    5. IN VOID *TopOfCurrentStack
    6. )
    7. {
    8. EFI_SEC_PEI_HAND_OFF SecCoreData;
    9. SEC_IDT_TABLE IdtTableInStack;
    10. IA32_DESCRIPTOR IdtDescriptor;
    11. UINT32 Index;
    12. volatile UINT8 *Table;
    13. //
    14. // To ensure SMM can't be compromised on S3 resume, we must force re-init of
    15. // the BaseExtractGuidedSectionLib. Since this is before library contructors
    16. // are called, we must use a loop rather than SetMem.
    17. //
    18. Table = (UINT8 *)(UINTN)FixedPcdGet64 (PcdGuidedExtractHandlerTableAddress);
    19. for (Index = 0;
    20. Index < FixedPcdGet32 (PcdGuidedExtractHandlerTableSize);
    21. ++Index)
    22. {
    23. Table[Index] = 0;
    24. }
    25. //
    26. // Initialize IDT - Since this is before library constructors are called,
    27. // we use a loop rather than CopyMem.
    28. //
    29. IdtTableInStack.PeiService = NULL;
    30. for (Index = 0; Index < SEC_IDT_ENTRY_COUNT; Index++) {
    31. UINT8 *Src;
    32. UINT8 *Dst;
    33. UINTN Byte;
    34. Src = (UINT8 *)&mIdtEntryTemplate;
    35. Dst = (UINT8 *)&IdtTableInStack.IdtTable[Index];
    36. for (Byte = 0; Byte < sizeof (mIdtEntryTemplate); Byte++) {
    37. Dst[Byte] = Src[Byte];
    38. }
    39. }
    40. IdtDescriptor.Base = (UINTN)&IdtTableInStack.IdtTable;
    41. IdtDescriptor.Limit = (UINT16)(sizeof (IdtTableInStack.IdtTable) - 1);
    42. if (SevEsIsEnabled ()) {
    43. SevEsProtocolCheck ();
    44. //
    45. // For SEV-ES guests, the exception handler is needed before calling
    46. // ProcessLibraryConstructorList() because some of the library constructors
    47. // perform some functions that result in #VC exceptions being generated.
    48. //
    49. // Due to this code executing before library constructors, *all* library
    50. // API calls are theoretically interface contract violations. However,
    51. // because this is SEC (executing in flash), those constructors cannot
    52. // write variables with static storage duration anyway. Furthermore, only
    53. // a small, restricted set of APIs, such as AsmWriteIdtr() and
    54. // InitializeCpuExceptionHandlers(), are called, where we require that the
    55. // underlying library not require constructors to have been invoked and
    56. // that the library instance not trigger any #VC exceptions.
    57. //
    58. AsmWriteIdtr (&IdtDescriptor);
    59. InitializeCpuExceptionHandlers (NULL);
    60. }
    61. ProcessLibraryConstructorList (NULL, NULL);
    62. if (!SevEsIsEnabled ()) {
    63. //
    64. // For non SEV-ES guests, just load the IDTR.
    65. //
    66. AsmWriteIdtr (&IdtDescriptor);
    67. } else {
    68. //
    69. // Under SEV-ES, the hypervisor can't modify CR0 and so can't enable
    70. // caching in order to speed up the boot. Enable caching early for
    71. // an SEV-ES guest.
    72. //
    73. AsmEnableCache ();
    74. }
    75. DEBUG ((
    76. DEBUG_INFO,
    77. "SecCoreStartupWithStack(0x%x, 0x%x)\n",
    78. (UINT32)(UINTN)BootFv,
    79. (UINT32)(UINTN)TopOfCurrentStack
    80. ));
    81. //
    82. // Initialize floating point operating environment
    83. // to be compliant with UEFI spec.
    84. //
    85. InitializeFloatingPointUnits ();
    86. #if defined (MDE_CPU_X64)
    87. //
    88. // ASSERT that the Page Tables were set by the reset vector code to
    89. // the address we expect.
    90. //
    91. ASSERT (AsmReadCr3 () == (UINTN)PcdGet32 (PcdOvmfSecPageTablesBase));
    92. #endif
    93. //
    94. // |-------------| <-- TopOfCurrentStack
    95. // | Stack | 32k
    96. // |-------------|
    97. // | Heap | 32k
    98. // |-------------| <-- SecCoreData.TemporaryRamBase
    99. //
    100. ASSERT (
    101. (UINTN)(PcdGet32 (PcdOvmfSecPeiTempRamBase) +
    102. PcdGet32 (PcdOvmfSecPeiTempRamSize)) ==
    103. (UINTN)TopOfCurrentStack
    104. );
    105. //
    106. // Initialize SEC hand-off state
    107. //
    108. SecCoreData.DataSize = sizeof (EFI_SEC_PEI_HAND_OFF);
    109. SecCoreData.TemporaryRamSize = (UINTN)PcdGet32 (PcdOvmfSecPeiTempRamSize);
    110. SecCoreData.TemporaryRamBase = (VOID *)((UINT8 *)TopOfCurrentStack - SecCoreData.TemporaryRamSize);
    111. SecCoreData.PeiTemporaryRamBase = SecCoreData.TemporaryRamBase;
    112. SecCoreData.PeiTemporaryRamSize = SecCoreData.TemporaryRamSize >> 1;
    113. SecCoreData.StackBase = (UINT8 *)SecCoreData.TemporaryRamBase + SecCoreData.PeiTemporaryRamSize;
    114. SecCoreData.StackSize = SecCoreData.TemporaryRamSize >> 1;
    115. SecCoreData.BootFirmwareVolumeBase = BootFv;
    116. SecCoreData.BootFirmwareVolumeSize = (UINTN)BootFv->FvLength;
    117. //
    118. // Make sure the 8259 is masked before initializing the Debug Agent and the debug timer is enabled
    119. //
    120. IoWrite8 (0x21, 0xff);
    121. IoWrite8 (0xA1, 0xff);
    122. //
    123. // Initialize Local APIC Timer hardware and disable Local APIC Timer
    124. // interrupts before initializing the Debug Agent and the debug timer is
    125. // enabled.
    126. //
    127. InitializeApicTimer (0, MAX_UINT32, TRUE, 5);
    128. DisableApicTimerInterrupt ();
    129. //
    130. // Initialize Debug Agent to support source level debug in SEC/PEI phases before memory ready.
    131. //
    132. InitializeDebugAgent (DEBUG_AGENT_INIT_PREMEM_SEC, &SecCoreData, SecStartupPhase2);
    133. }

     SEC剩下的就是call PEI,通过SecStartupPhase2函数寻找Pei 入口函数~

    1. VOID
    2. EFIAPI
    3. SecStartupPhase2 (
    4. IN VOID *Context
    5. )
    6. {
    7. EFI_SEC_PEI_HAND_OFF *SecCoreData;
    8. EFI_FIRMWARE_VOLUME_HEADER *BootFv;
    9. EFI_PEI_CORE_ENTRY_POINT PeiCoreEntryPoint;
    10. SecCoreData = (EFI_SEC_PEI_HAND_OFF *)Context;
    11. //
    12. // Find PEI Core entry point. It will report SEC and Pei Core debug information if remote debug
    13. // is enabled.
    14. //
    15. BootFv = (EFI_FIRMWARE_VOLUME_HEADER *)SecCoreData->BootFirmwareVolumeBase;
    16. FindAndReportEntryPoints (&BootFv, &PeiCoreEntryPoint);
    17. SecCoreData->BootFirmwareVolumeBase = BootFv;
    18. SecCoreData->BootFirmwareVolumeSize = (UINTN)BootFv->FvLength;
    19. //
    20. // Transfer the control to the PEI core
    21. //
    22. (*PeiCoreEntryPoint)(SecCoreData, (EFI_PEI_PPI_DESCRIPTOR *)&mPrivateDispatchTable);
    23. //
    24. // If we get here then the PEI Core returned, which is not recoverable.
    25. //
    26. ASSERT (FALSE);
    27. CpuDeadLoop ();
    28. }

  • 相关阅读:
    含文档+PPT+源码等]精品微信小程序校园论坛+后台管理系统|前后分离VUE[包运行成功]
    Vue 实例实战之 Vue webpack 仿去哪儿网App页面开发(应用中的几个页面简单实现)
    Linux入门学习指南
    【目标检测】图像裁剪/标签可视化/图像拼接处理脚本
    详解:到底什么是GPS北斗授时服务器?
    window wsl2的ubuntu如何配置代理获取docker image
    【LeetCode:2760. 最长奇偶子数组 | 模拟 & 双指针】
    Vue生命周期
    Java-基于SSM的智能仓储管理系统
    PG物理备份与恢复之pg_basebackup
  • 原文地址:https://blog.csdn.net/vito_bin/article/details/126601786