SecMain.c 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005
  1. /** @file
  2. Main SEC phase code. Transitions to PEI.
  3. Copyright (c) 2008 - 2015, Intel Corporation. All rights reserved.<BR>
  4. (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
  5. Copyright (c) 2020, Advanced Micro Devices, Inc. All rights reserved.<BR>
  6. SPDX-License-Identifier: BSD-2-Clause-Patent
  7. **/
  8. #include <PiPei.h>
  9. #include <Library/PeimEntryPoint.h>
  10. #include <Library/BaseLib.h>
  11. #include <Library/DebugLib.h>
  12. #include <Library/BaseMemoryLib.h>
  13. #include <Library/PeiServicesLib.h>
  14. #include <Library/PcdLib.h>
  15. #include <Library/UefiCpuLib.h>
  16. #include <Library/DebugAgentLib.h>
  17. #include <Library/IoLib.h>
  18. #include <Library/PeCoffLib.h>
  19. #include <Library/PeCoffGetEntryPointLib.h>
  20. #include <Library/PeCoffExtraActionLib.h>
  21. #include <Library/ExtractGuidedSectionLib.h>
  22. #include <Library/LocalApicLib.h>
  23. #include <Library/CpuExceptionHandlerLib.h>
  24. #include <Ppi/TemporaryRamSupport.h>
  25. #include "AmdSev.h"
  26. #define SEC_IDT_ENTRY_COUNT 34
  27. typedef struct _SEC_IDT_TABLE {
  28. EFI_PEI_SERVICES *PeiService;
  29. IA32_IDT_GATE_DESCRIPTOR IdtTable[SEC_IDT_ENTRY_COUNT];
  30. } SEC_IDT_TABLE;
  31. VOID
  32. EFIAPI
  33. SecStartupPhase2 (
  34. IN VOID *Context
  35. );
  36. EFI_STATUS
  37. EFIAPI
  38. TemporaryRamMigration (
  39. IN CONST EFI_PEI_SERVICES **PeiServices,
  40. IN EFI_PHYSICAL_ADDRESS TemporaryMemoryBase,
  41. IN EFI_PHYSICAL_ADDRESS PermanentMemoryBase,
  42. IN UINTN CopySize
  43. );
  44. //
  45. //
  46. //
  47. EFI_PEI_TEMPORARY_RAM_SUPPORT_PPI mTemporaryRamSupportPpi = {
  48. TemporaryRamMigration
  49. };
  50. EFI_PEI_PPI_DESCRIPTOR mPrivateDispatchTable[] = {
  51. {
  52. (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
  53. &gEfiTemporaryRamSupportPpiGuid,
  54. &mTemporaryRamSupportPpi
  55. },
  56. };
  57. //
  58. // Template of an IDT entry pointing to 10:FFFFFFE4h.
  59. //
  60. IA32_IDT_GATE_DESCRIPTOR mIdtEntryTemplate = {
  61. { // Bits
  62. 0xffe4, // OffsetLow
  63. 0x10, // Selector
  64. 0x0, // Reserved_0
  65. IA32_IDT_GATE_TYPE_INTERRUPT_32, // GateType
  66. 0xffff // OffsetHigh
  67. }
  68. };
  69. /**
  70. Locates the main boot firmware volume.
  71. @param[in,out] BootFv On input, the base of the BootFv
  72. On output, the decompressed main firmware volume
  73. @retval EFI_SUCCESS The main firmware volume was located and decompressed
  74. @retval EFI_NOT_FOUND The main firmware volume was not found
  75. **/
  76. EFI_STATUS
  77. FindMainFv (
  78. IN OUT EFI_FIRMWARE_VOLUME_HEADER **BootFv
  79. )
  80. {
  81. EFI_FIRMWARE_VOLUME_HEADER *Fv;
  82. UINTN Distance;
  83. ASSERT (((UINTN)*BootFv & EFI_PAGE_MASK) == 0);
  84. Fv = *BootFv;
  85. Distance = (UINTN)(*BootFv)->FvLength;
  86. do {
  87. Fv = (EFI_FIRMWARE_VOLUME_HEADER *)((UINT8 *)Fv - EFI_PAGE_SIZE);
  88. Distance += EFI_PAGE_SIZE;
  89. if (Distance > SIZE_32MB) {
  90. return EFI_NOT_FOUND;
  91. }
  92. if (Fv->Signature != EFI_FVH_SIGNATURE) {
  93. continue;
  94. }
  95. if ((UINTN)Fv->FvLength > Distance) {
  96. continue;
  97. }
  98. *BootFv = Fv;
  99. return EFI_SUCCESS;
  100. } while (TRUE);
  101. }
  102. /**
  103. Locates a section within a series of sections
  104. with the specified section type.
  105. The Instance parameter indicates which instance of the section
  106. type to return. (0 is first instance, 1 is second...)
  107. @param[in] Sections The sections to search
  108. @param[in] SizeOfSections Total size of all sections
  109. @param[in] SectionType The section type to locate
  110. @param[in] Instance The section instance number
  111. @param[out] FoundSection The FFS section if found
  112. @retval EFI_SUCCESS The file and section was found
  113. @retval EFI_NOT_FOUND The file and section was not found
  114. @retval EFI_VOLUME_CORRUPTED The firmware volume was corrupted
  115. **/
  116. EFI_STATUS
  117. FindFfsSectionInstance (
  118. IN VOID *Sections,
  119. IN UINTN SizeOfSections,
  120. IN EFI_SECTION_TYPE SectionType,
  121. IN UINTN Instance,
  122. OUT EFI_COMMON_SECTION_HEADER **FoundSection
  123. )
  124. {
  125. EFI_PHYSICAL_ADDRESS CurrentAddress;
  126. UINT32 Size;
  127. EFI_PHYSICAL_ADDRESS EndOfSections;
  128. EFI_COMMON_SECTION_HEADER *Section;
  129. EFI_PHYSICAL_ADDRESS EndOfSection;
  130. //
  131. // Loop through the FFS file sections within the PEI Core FFS file
  132. //
  133. EndOfSection = (EFI_PHYSICAL_ADDRESS)(UINTN)Sections;
  134. EndOfSections = EndOfSection + SizeOfSections;
  135. for ( ; ;) {
  136. if (EndOfSection == EndOfSections) {
  137. break;
  138. }
  139. CurrentAddress = (EndOfSection + 3) & ~(3ULL);
  140. if (CurrentAddress >= EndOfSections) {
  141. return EFI_VOLUME_CORRUPTED;
  142. }
  143. Section = (EFI_COMMON_SECTION_HEADER *)(UINTN)CurrentAddress;
  144. Size = SECTION_SIZE (Section);
  145. if (Size < sizeof (*Section)) {
  146. return EFI_VOLUME_CORRUPTED;
  147. }
  148. EndOfSection = CurrentAddress + Size;
  149. if (EndOfSection > EndOfSections) {
  150. return EFI_VOLUME_CORRUPTED;
  151. }
  152. //
  153. // Look for the requested section type
  154. //
  155. if (Section->Type == SectionType) {
  156. if (Instance == 0) {
  157. *FoundSection = Section;
  158. return EFI_SUCCESS;
  159. } else {
  160. Instance--;
  161. }
  162. }
  163. }
  164. return EFI_NOT_FOUND;
  165. }
  166. /**
  167. Locates a section within a series of sections
  168. with the specified section type.
  169. @param[in] Sections The sections to search
  170. @param[in] SizeOfSections Total size of all sections
  171. @param[in] SectionType The section type to locate
  172. @param[out] FoundSection The FFS section if found
  173. @retval EFI_SUCCESS The file and section was found
  174. @retval EFI_NOT_FOUND The file and section was not found
  175. @retval EFI_VOLUME_CORRUPTED The firmware volume was corrupted
  176. **/
  177. EFI_STATUS
  178. FindFfsSectionInSections (
  179. IN VOID *Sections,
  180. IN UINTN SizeOfSections,
  181. IN EFI_SECTION_TYPE SectionType,
  182. OUT EFI_COMMON_SECTION_HEADER **FoundSection
  183. )
  184. {
  185. return FindFfsSectionInstance (
  186. Sections,
  187. SizeOfSections,
  188. SectionType,
  189. 0,
  190. FoundSection
  191. );
  192. }
  193. /**
  194. Locates a FFS file with the specified file type and a section
  195. within that file with the specified section type.
  196. @param[in] Fv The firmware volume to search
  197. @param[in] FileType The file type to locate
  198. @param[in] SectionType The section type to locate
  199. @param[out] FoundSection The FFS section if found
  200. @retval EFI_SUCCESS The file and section was found
  201. @retval EFI_NOT_FOUND The file and section was not found
  202. @retval EFI_VOLUME_CORRUPTED The firmware volume was corrupted
  203. **/
  204. EFI_STATUS
  205. FindFfsFileAndSection (
  206. IN EFI_FIRMWARE_VOLUME_HEADER *Fv,
  207. IN EFI_FV_FILETYPE FileType,
  208. IN EFI_SECTION_TYPE SectionType,
  209. OUT EFI_COMMON_SECTION_HEADER **FoundSection
  210. )
  211. {
  212. EFI_STATUS Status;
  213. EFI_PHYSICAL_ADDRESS CurrentAddress;
  214. EFI_PHYSICAL_ADDRESS EndOfFirmwareVolume;
  215. EFI_FFS_FILE_HEADER *File;
  216. UINT32 Size;
  217. EFI_PHYSICAL_ADDRESS EndOfFile;
  218. if (Fv->Signature != EFI_FVH_SIGNATURE) {
  219. DEBUG ((DEBUG_ERROR, "FV at %p does not have FV header signature\n", Fv));
  220. return EFI_VOLUME_CORRUPTED;
  221. }
  222. CurrentAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)Fv;
  223. EndOfFirmwareVolume = CurrentAddress + Fv->FvLength;
  224. //
  225. // Loop through the FFS files in the Boot Firmware Volume
  226. //
  227. for (EndOfFile = CurrentAddress + Fv->HeaderLength; ; ) {
  228. CurrentAddress = (EndOfFile + 7) & ~(7ULL);
  229. if (CurrentAddress > EndOfFirmwareVolume) {
  230. return EFI_VOLUME_CORRUPTED;
  231. }
  232. File = (EFI_FFS_FILE_HEADER *)(UINTN)CurrentAddress;
  233. Size = FFS_FILE_SIZE (File);
  234. if (Size < (sizeof (*File) + sizeof (EFI_COMMON_SECTION_HEADER))) {
  235. return EFI_VOLUME_CORRUPTED;
  236. }
  237. EndOfFile = CurrentAddress + Size;
  238. if (EndOfFile > EndOfFirmwareVolume) {
  239. return EFI_VOLUME_CORRUPTED;
  240. }
  241. //
  242. // Look for the request file type
  243. //
  244. if (File->Type != FileType) {
  245. continue;
  246. }
  247. Status = FindFfsSectionInSections (
  248. (VOID *)(File + 1),
  249. (UINTN)EndOfFile - (UINTN)(File + 1),
  250. SectionType,
  251. FoundSection
  252. );
  253. if (!EFI_ERROR (Status) || (Status == EFI_VOLUME_CORRUPTED)) {
  254. return Status;
  255. }
  256. }
  257. }
  258. /**
  259. Locates the compressed main firmware volume and decompresses it.
  260. @param[in,out] Fv On input, the firmware volume to search
  261. On output, the decompressed BOOT/PEI FV
  262. @retval EFI_SUCCESS The file and section was found
  263. @retval EFI_NOT_FOUND The file and section was not found
  264. @retval EFI_VOLUME_CORRUPTED The firmware volume was corrupted
  265. **/
  266. EFI_STATUS
  267. DecompressMemFvs (
  268. IN OUT EFI_FIRMWARE_VOLUME_HEADER **Fv
  269. )
  270. {
  271. EFI_STATUS Status;
  272. EFI_GUID_DEFINED_SECTION *Section;
  273. UINT32 OutputBufferSize;
  274. UINT32 ScratchBufferSize;
  275. UINT16 SectionAttribute;
  276. UINT32 AuthenticationStatus;
  277. VOID *OutputBuffer;
  278. VOID *ScratchBuffer;
  279. EFI_COMMON_SECTION_HEADER *FvSection;
  280. EFI_FIRMWARE_VOLUME_HEADER *PeiMemFv;
  281. EFI_FIRMWARE_VOLUME_HEADER *DxeMemFv;
  282. UINT32 FvHeaderSize;
  283. UINT32 FvSectionSize;
  284. FvSection = (EFI_COMMON_SECTION_HEADER *)NULL;
  285. Status = FindFfsFileAndSection (
  286. *Fv,
  287. EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE,
  288. EFI_SECTION_GUID_DEFINED,
  289. (EFI_COMMON_SECTION_HEADER **)&Section
  290. );
  291. if (EFI_ERROR (Status)) {
  292. DEBUG ((DEBUG_ERROR, "Unable to find GUID defined section\n"));
  293. return Status;
  294. }
  295. Status = ExtractGuidedSectionGetInfo (
  296. Section,
  297. &OutputBufferSize,
  298. &ScratchBufferSize,
  299. &SectionAttribute
  300. );
  301. if (EFI_ERROR (Status)) {
  302. DEBUG ((DEBUG_ERROR, "Unable to GetInfo for GUIDed section\n"));
  303. return Status;
  304. }
  305. OutputBuffer = (VOID *)((UINT8 *)(UINTN)PcdGet32 (PcdOvmfDxeMemFvBase) + SIZE_1MB);
  306. ScratchBuffer = ALIGN_POINTER ((UINT8 *)OutputBuffer + OutputBufferSize, SIZE_1MB);
  307. DEBUG ((
  308. DEBUG_VERBOSE,
  309. "%a: OutputBuffer@%p+0x%x ScratchBuffer@%p+0x%x "
  310. "PcdOvmfDecompressionScratchEnd=0x%x\n",
  311. __FUNCTION__,
  312. OutputBuffer,
  313. OutputBufferSize,
  314. ScratchBuffer,
  315. ScratchBufferSize,
  316. PcdGet32 (PcdOvmfDecompressionScratchEnd)
  317. ));
  318. ASSERT (
  319. (UINTN)ScratchBuffer + ScratchBufferSize ==
  320. PcdGet32 (PcdOvmfDecompressionScratchEnd)
  321. );
  322. Status = ExtractGuidedSectionDecode (
  323. Section,
  324. &OutputBuffer,
  325. ScratchBuffer,
  326. &AuthenticationStatus
  327. );
  328. if (EFI_ERROR (Status)) {
  329. DEBUG ((DEBUG_ERROR, "Error during GUID section decode\n"));
  330. return Status;
  331. }
  332. Status = FindFfsSectionInstance (
  333. OutputBuffer,
  334. OutputBufferSize,
  335. EFI_SECTION_FIRMWARE_VOLUME_IMAGE,
  336. 0,
  337. &FvSection
  338. );
  339. if (EFI_ERROR (Status)) {
  340. DEBUG ((DEBUG_ERROR, "Unable to find PEI FV section\n"));
  341. return Status;
  342. }
  343. ASSERT (
  344. SECTION_SIZE (FvSection) ==
  345. (PcdGet32 (PcdOvmfPeiMemFvSize) + sizeof (*FvSection))
  346. );
  347. ASSERT (FvSection->Type == EFI_SECTION_FIRMWARE_VOLUME_IMAGE);
  348. PeiMemFv = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)PcdGet32 (PcdOvmfPeiMemFvBase);
  349. CopyMem (PeiMemFv, (VOID *)(FvSection + 1), PcdGet32 (PcdOvmfPeiMemFvSize));
  350. if (PeiMemFv->Signature != EFI_FVH_SIGNATURE) {
  351. DEBUG ((DEBUG_ERROR, "Extracted FV at %p does not have FV header signature\n", PeiMemFv));
  352. CpuDeadLoop ();
  353. return EFI_VOLUME_CORRUPTED;
  354. }
  355. Status = FindFfsSectionInstance (
  356. OutputBuffer,
  357. OutputBufferSize,
  358. EFI_SECTION_FIRMWARE_VOLUME_IMAGE,
  359. 1,
  360. &FvSection
  361. );
  362. if (EFI_ERROR (Status)) {
  363. DEBUG ((DEBUG_ERROR, "Unable to find DXE FV section\n"));
  364. return Status;
  365. }
  366. ASSERT (FvSection->Type == EFI_SECTION_FIRMWARE_VOLUME_IMAGE);
  367. if (IS_SECTION2 (FvSection)) {
  368. FvSectionSize = SECTION2_SIZE (FvSection);
  369. FvHeaderSize = sizeof (EFI_COMMON_SECTION_HEADER2);
  370. } else {
  371. FvSectionSize = SECTION_SIZE (FvSection);
  372. FvHeaderSize = sizeof (EFI_COMMON_SECTION_HEADER);
  373. }
  374. ASSERT (FvSectionSize == (PcdGet32 (PcdOvmfDxeMemFvSize) + FvHeaderSize));
  375. DxeMemFv = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)PcdGet32 (PcdOvmfDxeMemFvBase);
  376. CopyMem (DxeMemFv, (VOID *)((UINTN)FvSection + FvHeaderSize), PcdGet32 (PcdOvmfDxeMemFvSize));
  377. if (DxeMemFv->Signature != EFI_FVH_SIGNATURE) {
  378. DEBUG ((DEBUG_ERROR, "Extracted FV at %p does not have FV header signature\n", DxeMemFv));
  379. CpuDeadLoop ();
  380. return EFI_VOLUME_CORRUPTED;
  381. }
  382. *Fv = PeiMemFv;
  383. return EFI_SUCCESS;
  384. }
  385. /**
  386. Locates the PEI Core entry point address
  387. @param[in] Fv The firmware volume to search
  388. @param[out] PeiCoreEntryPoint The entry point of the PEI Core image
  389. @retval EFI_SUCCESS The file and section was found
  390. @retval EFI_NOT_FOUND The file and section was not found
  391. @retval EFI_VOLUME_CORRUPTED The firmware volume was corrupted
  392. **/
  393. EFI_STATUS
  394. FindPeiCoreImageBaseInFv (
  395. IN EFI_FIRMWARE_VOLUME_HEADER *Fv,
  396. OUT EFI_PHYSICAL_ADDRESS *PeiCoreImageBase
  397. )
  398. {
  399. EFI_STATUS Status;
  400. EFI_COMMON_SECTION_HEADER *Section;
  401. Status = FindFfsFileAndSection (
  402. Fv,
  403. EFI_FV_FILETYPE_PEI_CORE,
  404. EFI_SECTION_PE32,
  405. &Section
  406. );
  407. if (EFI_ERROR (Status)) {
  408. Status = FindFfsFileAndSection (
  409. Fv,
  410. EFI_FV_FILETYPE_PEI_CORE,
  411. EFI_SECTION_TE,
  412. &Section
  413. );
  414. if (EFI_ERROR (Status)) {
  415. DEBUG ((DEBUG_ERROR, "Unable to find PEI Core image\n"));
  416. return Status;
  417. }
  418. }
  419. *PeiCoreImageBase = (EFI_PHYSICAL_ADDRESS)(UINTN)(Section + 1);
  420. return EFI_SUCCESS;
  421. }
  422. /**
  423. Reads 8-bits of CMOS data.
  424. Reads the 8-bits of CMOS data at the location specified by Index.
  425. The 8-bit read value is returned.
  426. @param Index The CMOS location to read.
  427. @return The value read.
  428. **/
  429. STATIC
  430. UINT8
  431. CmosRead8 (
  432. IN UINTN Index
  433. )
  434. {
  435. IoWrite8 (0x70, (UINT8)Index);
  436. return IoRead8 (0x71);
  437. }
  438. STATIC
  439. BOOLEAN
  440. IsS3Resume (
  441. VOID
  442. )
  443. {
  444. return (CmosRead8 (0xF) == 0xFE);
  445. }
  446. STATIC
  447. EFI_STATUS
  448. GetS3ResumePeiFv (
  449. IN OUT EFI_FIRMWARE_VOLUME_HEADER **PeiFv
  450. )
  451. {
  452. *PeiFv = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)PcdGet32 (PcdOvmfPeiMemFvBase);
  453. return EFI_SUCCESS;
  454. }
  455. /**
  456. Locates the PEI Core entry point address
  457. @param[in,out] Fv The firmware volume to search
  458. @param[out] PeiCoreEntryPoint The entry point of the PEI Core image
  459. @retval EFI_SUCCESS The file and section was found
  460. @retval EFI_NOT_FOUND The file and section was not found
  461. @retval EFI_VOLUME_CORRUPTED The firmware volume was corrupted
  462. **/
  463. VOID
  464. FindPeiCoreImageBase (
  465. IN OUT EFI_FIRMWARE_VOLUME_HEADER **BootFv,
  466. OUT EFI_PHYSICAL_ADDRESS *PeiCoreImageBase
  467. )
  468. {
  469. BOOLEAN S3Resume;
  470. *PeiCoreImageBase = 0;
  471. S3Resume = IsS3Resume ();
  472. if (S3Resume && !FeaturePcdGet (PcdSmmSmramRequire)) {
  473. //
  474. // A malicious runtime OS may have injected something into our previously
  475. // decoded PEI FV, but we don't care about that unless SMM/SMRAM is required.
  476. //
  477. DEBUG ((DEBUG_VERBOSE, "SEC: S3 resume\n"));
  478. GetS3ResumePeiFv (BootFv);
  479. } else {
  480. //
  481. // We're either not resuming, or resuming "securely" -- we'll decompress
  482. // both PEI FV and DXE FV from pristine flash.
  483. //
  484. DEBUG ((
  485. DEBUG_VERBOSE,
  486. "SEC: %a\n",
  487. S3Resume ? "S3 resume (with PEI decompression)" : "Normal boot"
  488. ));
  489. FindMainFv (BootFv);
  490. DecompressMemFvs (BootFv);
  491. }
  492. FindPeiCoreImageBaseInFv (*BootFv, PeiCoreImageBase);
  493. }
  494. /**
  495. Find core image base.
  496. **/
  497. EFI_STATUS
  498. FindImageBase (
  499. IN EFI_FIRMWARE_VOLUME_HEADER *BootFirmwareVolumePtr,
  500. OUT EFI_PHYSICAL_ADDRESS *SecCoreImageBase
  501. )
  502. {
  503. EFI_PHYSICAL_ADDRESS CurrentAddress;
  504. EFI_PHYSICAL_ADDRESS EndOfFirmwareVolume;
  505. EFI_FFS_FILE_HEADER *File;
  506. UINT32 Size;
  507. EFI_PHYSICAL_ADDRESS EndOfFile;
  508. EFI_COMMON_SECTION_HEADER *Section;
  509. EFI_PHYSICAL_ADDRESS EndOfSection;
  510. *SecCoreImageBase = 0;
  511. CurrentAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)BootFirmwareVolumePtr;
  512. EndOfFirmwareVolume = CurrentAddress + BootFirmwareVolumePtr->FvLength;
  513. //
  514. // Loop through the FFS files in the Boot Firmware Volume
  515. //
  516. for (EndOfFile = CurrentAddress + BootFirmwareVolumePtr->HeaderLength; ; ) {
  517. CurrentAddress = (EndOfFile + 7) & 0xfffffffffffffff8ULL;
  518. if (CurrentAddress > EndOfFirmwareVolume) {
  519. return EFI_NOT_FOUND;
  520. }
  521. File = (EFI_FFS_FILE_HEADER *)(UINTN)CurrentAddress;
  522. Size = FFS_FILE_SIZE (File);
  523. if (Size < sizeof (*File)) {
  524. return EFI_NOT_FOUND;
  525. }
  526. EndOfFile = CurrentAddress + Size;
  527. if (EndOfFile > EndOfFirmwareVolume) {
  528. return EFI_NOT_FOUND;
  529. }
  530. //
  531. // Look for SEC Core
  532. //
  533. if (File->Type != EFI_FV_FILETYPE_SECURITY_CORE) {
  534. continue;
  535. }
  536. //
  537. // Loop through the FFS file sections within the FFS file
  538. //
  539. EndOfSection = (EFI_PHYSICAL_ADDRESS)(UINTN)(File + 1);
  540. for ( ; ;) {
  541. CurrentAddress = (EndOfSection + 3) & 0xfffffffffffffffcULL;
  542. Section = (EFI_COMMON_SECTION_HEADER *)(UINTN)CurrentAddress;
  543. Size = SECTION_SIZE (Section);
  544. if (Size < sizeof (*Section)) {
  545. return EFI_NOT_FOUND;
  546. }
  547. EndOfSection = CurrentAddress + Size;
  548. if (EndOfSection > EndOfFile) {
  549. return EFI_NOT_FOUND;
  550. }
  551. //
  552. // Look for executable sections
  553. //
  554. if ((Section->Type == EFI_SECTION_PE32) || (Section->Type == EFI_SECTION_TE)) {
  555. if (File->Type == EFI_FV_FILETYPE_SECURITY_CORE) {
  556. *SecCoreImageBase = (PHYSICAL_ADDRESS)(UINTN)(Section + 1);
  557. }
  558. break;
  559. }
  560. }
  561. //
  562. // SEC Core image found
  563. //
  564. if (*SecCoreImageBase != 0) {
  565. return EFI_SUCCESS;
  566. }
  567. }
  568. }
  569. /*
  570. Find and return Pei Core entry point.
  571. It also find SEC and PEI Core file debug information. It will report them if
  572. remote debug is enabled.
  573. **/
  574. VOID
  575. FindAndReportEntryPoints (
  576. IN EFI_FIRMWARE_VOLUME_HEADER **BootFirmwareVolumePtr,
  577. OUT EFI_PEI_CORE_ENTRY_POINT *PeiCoreEntryPoint
  578. )
  579. {
  580. EFI_STATUS Status;
  581. EFI_PHYSICAL_ADDRESS SecCoreImageBase;
  582. EFI_PHYSICAL_ADDRESS PeiCoreImageBase;
  583. PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
  584. //
  585. // Find SEC Core and PEI Core image base
  586. //
  587. Status = FindImageBase (*BootFirmwareVolumePtr, &SecCoreImageBase);
  588. ASSERT_EFI_ERROR (Status);
  589. FindPeiCoreImageBase (BootFirmwareVolumePtr, &PeiCoreImageBase);
  590. ZeroMem ((VOID *)&ImageContext, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT));
  591. //
  592. // Report SEC Core debug information when remote debug is enabled
  593. //
  594. ImageContext.ImageAddress = SecCoreImageBase;
  595. ImageContext.PdbPointer = PeCoffLoaderGetPdbPointer ((VOID *)(UINTN)ImageContext.ImageAddress);
  596. PeCoffLoaderRelocateImageExtraAction (&ImageContext);
  597. //
  598. // Report PEI Core debug information when remote debug is enabled
  599. //
  600. ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)PeiCoreImageBase;
  601. ImageContext.PdbPointer = PeCoffLoaderGetPdbPointer ((VOID *)(UINTN)ImageContext.ImageAddress);
  602. PeCoffLoaderRelocateImageExtraAction (&ImageContext);
  603. //
  604. // Find PEI Core entry point
  605. //
  606. Status = PeCoffLoaderGetEntryPoint ((VOID *)(UINTN)PeiCoreImageBase, (VOID **)PeiCoreEntryPoint);
  607. if (EFI_ERROR (Status)) {
  608. *PeiCoreEntryPoint = 0;
  609. }
  610. return;
  611. }
  612. VOID
  613. EFIAPI
  614. SecCoreStartupWithStack (
  615. IN EFI_FIRMWARE_VOLUME_HEADER *BootFv,
  616. IN VOID *TopOfCurrentStack
  617. )
  618. {
  619. EFI_SEC_PEI_HAND_OFF SecCoreData;
  620. SEC_IDT_TABLE IdtTableInStack;
  621. IA32_DESCRIPTOR IdtDescriptor;
  622. UINT32 Index;
  623. volatile UINT8 *Table;
  624. //
  625. // To ensure SMM can't be compromised on S3 resume, we must force re-init of
  626. // the BaseExtractGuidedSectionLib. Since this is before library contructors
  627. // are called, we must use a loop rather than SetMem.
  628. //
  629. Table = (UINT8 *)(UINTN)FixedPcdGet64 (PcdGuidedExtractHandlerTableAddress);
  630. for (Index = 0;
  631. Index < FixedPcdGet32 (PcdGuidedExtractHandlerTableSize);
  632. ++Index)
  633. {
  634. Table[Index] = 0;
  635. }
  636. //
  637. // Initialize IDT - Since this is before library constructors are called,
  638. // we use a loop rather than CopyMem.
  639. //
  640. IdtTableInStack.PeiService = NULL;
  641. for (Index = 0; Index < SEC_IDT_ENTRY_COUNT; Index++) {
  642. UINT8 *Src;
  643. UINT8 *Dst;
  644. UINTN Byte;
  645. Src = (UINT8 *)&mIdtEntryTemplate;
  646. Dst = (UINT8 *)&IdtTableInStack.IdtTable[Index];
  647. for (Byte = 0; Byte < sizeof (mIdtEntryTemplate); Byte++) {
  648. Dst[Byte] = Src[Byte];
  649. }
  650. }
  651. IdtDescriptor.Base = (UINTN)&IdtTableInStack.IdtTable;
  652. IdtDescriptor.Limit = (UINT16)(sizeof (IdtTableInStack.IdtTable) - 1);
  653. if (SevEsIsEnabled ()) {
  654. SevEsProtocolCheck ();
  655. //
  656. // For SEV-ES guests, the exception handler is needed before calling
  657. // ProcessLibraryConstructorList() because some of the library constructors
  658. // perform some functions that result in #VC exceptions being generated.
  659. //
  660. // Due to this code executing before library constructors, *all* library
  661. // API calls are theoretically interface contract violations. However,
  662. // because this is SEC (executing in flash), those constructors cannot
  663. // write variables with static storage duration anyway. Furthermore, only
  664. // a small, restricted set of APIs, such as AsmWriteIdtr() and
  665. // InitializeCpuExceptionHandlers(), are called, where we require that the
  666. // underlying library not require constructors to have been invoked and
  667. // that the library instance not trigger any #VC exceptions.
  668. //
  669. AsmWriteIdtr (&IdtDescriptor);
  670. InitializeCpuExceptionHandlers (NULL);
  671. }
  672. ProcessLibraryConstructorList (NULL, NULL);
  673. if (!SevEsIsEnabled ()) {
  674. //
  675. // For non SEV-ES guests, just load the IDTR.
  676. //
  677. AsmWriteIdtr (&IdtDescriptor);
  678. } else {
  679. //
  680. // Under SEV-ES, the hypervisor can't modify CR0 and so can't enable
  681. // caching in order to speed up the boot. Enable caching early for
  682. // an SEV-ES guest.
  683. //
  684. AsmEnableCache ();
  685. }
  686. DEBUG ((
  687. DEBUG_INFO,
  688. "SecCoreStartupWithStack(0x%x, 0x%x)\n",
  689. (UINT32)(UINTN)BootFv,
  690. (UINT32)(UINTN)TopOfCurrentStack
  691. ));
  692. //
  693. // Initialize floating point operating environment
  694. // to be compliant with UEFI spec.
  695. //
  696. InitializeFloatingPointUnits ();
  697. #if defined (MDE_CPU_X64)
  698. //
  699. // ASSERT that the Page Tables were set by the reset vector code to
  700. // the address we expect.
  701. //
  702. ASSERT (AsmReadCr3 () == (UINTN)PcdGet32 (PcdOvmfSecPageTablesBase));
  703. #endif
  704. //
  705. // |-------------| <-- TopOfCurrentStack
  706. // | Stack | 32k
  707. // |-------------|
  708. // | Heap | 32k
  709. // |-------------| <-- SecCoreData.TemporaryRamBase
  710. //
  711. ASSERT (
  712. (UINTN)(PcdGet32 (PcdOvmfSecPeiTempRamBase) +
  713. PcdGet32 (PcdOvmfSecPeiTempRamSize)) ==
  714. (UINTN)TopOfCurrentStack
  715. );
  716. //
  717. // Initialize SEC hand-off state
  718. //
  719. SecCoreData.DataSize = sizeof (EFI_SEC_PEI_HAND_OFF);
  720. SecCoreData.TemporaryRamSize = (UINTN)PcdGet32 (PcdOvmfSecPeiTempRamSize);
  721. SecCoreData.TemporaryRamBase = (VOID *)((UINT8 *)TopOfCurrentStack - SecCoreData.TemporaryRamSize);
  722. SecCoreData.PeiTemporaryRamBase = SecCoreData.TemporaryRamBase;
  723. SecCoreData.PeiTemporaryRamSize = SecCoreData.TemporaryRamSize >> 1;
  724. SecCoreData.StackBase = (UINT8 *)SecCoreData.TemporaryRamBase + SecCoreData.PeiTemporaryRamSize;
  725. SecCoreData.StackSize = SecCoreData.TemporaryRamSize >> 1;
  726. SecCoreData.BootFirmwareVolumeBase = BootFv;
  727. SecCoreData.BootFirmwareVolumeSize = (UINTN)BootFv->FvLength;
  728. //
  729. // Validate the System RAM used in the SEC Phase
  730. //
  731. SecValidateSystemRam ();
  732. //
  733. // Make sure the 8259 is masked before initializing the Debug Agent and the debug timer is enabled
  734. //
  735. IoWrite8 (0x21, 0xff);
  736. IoWrite8 (0xA1, 0xff);
  737. //
  738. // Initialize Local APIC Timer hardware and disable Local APIC Timer
  739. // interrupts before initializing the Debug Agent and the debug timer is
  740. // enabled.
  741. //
  742. InitializeApicTimer (0, MAX_UINT32, TRUE, 5);
  743. DisableApicTimerInterrupt ();
  744. //
  745. // Initialize Debug Agent to support source level debug in SEC/PEI phases before memory ready.
  746. //
  747. InitializeDebugAgent (DEBUG_AGENT_INIT_PREMEM_SEC, &SecCoreData, SecStartupPhase2);
  748. }
  749. /**
  750. Caller provided function to be invoked at the end of InitializeDebugAgent().
  751. Entry point to the C language phase of SEC. After the SEC assembly
  752. code has initialized some temporary memory and set up the stack,
  753. the control is transferred to this function.
  754. @param[in] Context The first input parameter of InitializeDebugAgent().
  755. **/
  756. VOID
  757. EFIAPI
  758. SecStartupPhase2 (
  759. IN VOID *Context
  760. )
  761. {
  762. EFI_SEC_PEI_HAND_OFF *SecCoreData;
  763. EFI_FIRMWARE_VOLUME_HEADER *BootFv;
  764. EFI_PEI_CORE_ENTRY_POINT PeiCoreEntryPoint;
  765. SecCoreData = (EFI_SEC_PEI_HAND_OFF *)Context;
  766. //
  767. // Find PEI Core entry point. It will report SEC and Pei Core debug information if remote debug
  768. // is enabled.
  769. //
  770. BootFv = (EFI_FIRMWARE_VOLUME_HEADER *)SecCoreData->BootFirmwareVolumeBase;
  771. FindAndReportEntryPoints (&BootFv, &PeiCoreEntryPoint);
  772. SecCoreData->BootFirmwareVolumeBase = BootFv;
  773. SecCoreData->BootFirmwareVolumeSize = (UINTN)BootFv->FvLength;
  774. //
  775. // Transfer the control to the PEI core
  776. //
  777. (*PeiCoreEntryPoint)(SecCoreData, (EFI_PEI_PPI_DESCRIPTOR *)&mPrivateDispatchTable);
  778. //
  779. // If we get here then the PEI Core returned, which is not recoverable.
  780. //
  781. ASSERT (FALSE);
  782. CpuDeadLoop ();
  783. }
  784. EFI_STATUS
  785. EFIAPI
  786. TemporaryRamMigration (
  787. IN CONST EFI_PEI_SERVICES **PeiServices,
  788. IN EFI_PHYSICAL_ADDRESS TemporaryMemoryBase,
  789. IN EFI_PHYSICAL_ADDRESS PermanentMemoryBase,
  790. IN UINTN CopySize
  791. )
  792. {
  793. IA32_DESCRIPTOR IdtDescriptor;
  794. VOID *OldHeap;
  795. VOID *NewHeap;
  796. VOID *OldStack;
  797. VOID *NewStack;
  798. DEBUG_AGENT_CONTEXT_POSTMEM_SEC DebugAgentContext;
  799. BOOLEAN OldStatus;
  800. BASE_LIBRARY_JUMP_BUFFER JumpBuffer;
  801. DEBUG ((
  802. DEBUG_INFO,
  803. "TemporaryRamMigration(0x%Lx, 0x%Lx, 0x%Lx)\n",
  804. TemporaryMemoryBase,
  805. PermanentMemoryBase,
  806. (UINT64)CopySize
  807. ));
  808. OldHeap = (VOID *)(UINTN)TemporaryMemoryBase;
  809. NewHeap = (VOID *)((UINTN)PermanentMemoryBase + (CopySize >> 1));
  810. OldStack = (VOID *)((UINTN)TemporaryMemoryBase + (CopySize >> 1));
  811. NewStack = (VOID *)(UINTN)PermanentMemoryBase;
  812. DebugAgentContext.HeapMigrateOffset = (UINTN)NewHeap - (UINTN)OldHeap;
  813. DebugAgentContext.StackMigrateOffset = (UINTN)NewStack - (UINTN)OldStack;
  814. OldStatus = SaveAndSetDebugTimerInterrupt (FALSE);
  815. InitializeDebugAgent (DEBUG_AGENT_INIT_POSTMEM_SEC, (VOID *)&DebugAgentContext, NULL);
  816. //
  817. // Migrate Heap
  818. //
  819. CopyMem (NewHeap, OldHeap, CopySize >> 1);
  820. //
  821. // Migrate Stack
  822. //
  823. CopyMem (NewStack, OldStack, CopySize >> 1);
  824. //
  825. // Rebase IDT table in permanent memory
  826. //
  827. AsmReadIdtr (&IdtDescriptor);
  828. IdtDescriptor.Base = IdtDescriptor.Base - (UINTN)OldStack + (UINTN)NewStack;
  829. AsmWriteIdtr (&IdtDescriptor);
  830. //
  831. // Use SetJump()/LongJump() to switch to a new stack.
  832. //
  833. if (SetJump (&JumpBuffer) == 0) {
  834. #if defined (MDE_CPU_IA32)
  835. JumpBuffer.Esp = JumpBuffer.Esp + DebugAgentContext.StackMigrateOffset;
  836. JumpBuffer.Ebp = JumpBuffer.Ebp + DebugAgentContext.StackMigrateOffset;
  837. #endif
  838. #if defined (MDE_CPU_X64)
  839. JumpBuffer.Rsp = JumpBuffer.Rsp + DebugAgentContext.StackMigrateOffset;
  840. JumpBuffer.Rbp = JumpBuffer.Rbp + DebugAgentContext.StackMigrateOffset;
  841. #endif
  842. LongJump (&JumpBuffer, (UINTN)-1);
  843. }
  844. SaveAndSetDebugTimerInterrupt (OldStatus);
  845. return EFI_SUCCESS;
  846. }