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