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