]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/Sec/SecMain.c
OvmfPkg: Update PlatformInitLib to process Tdx hoblist
[mirror_edk2.git] / OvmfPkg / Sec / SecMain.c
CommitLineData
bb4aa855
JJ
1/** @file\r
2 Main SEC phase code. Transitions to PEI.\r
3\r
f3e34b9d 4 Copyright (c) 2008 - 2015, Intel Corporation. All rights reserved.<BR>\r
5e443e37 5 (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>\r
b78de543 6 Copyright (c) 2020, Advanced Micro Devices, Inc. All rights reserved.<BR>\r
bb4aa855 7\r
b26f0cf9 8 SPDX-License-Identifier: BSD-2-Clause-Patent\r
bb4aa855
JJ
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
f3e34b9d 27#include <Library/LocalApicLib.h>\r
13e5492b 28#include <Library/CpuExceptionHandlerLib.h>\r
bb4aa855
JJ
29\r
30#include <Ppi/TemporaryRamSupport.h>\r
31\r
2ddacfb6
BS
32#include "AmdSev.h"\r
33\r
bb4aa855
JJ
34#define SEC_IDT_ENTRY_COUNT 34\r
35\r
36typedef struct _SEC_IDT_TABLE {\r
ac0a286f
MK
37 EFI_PEI_SERVICES *PeiService;\r
38 IA32_IDT_GATE_DESCRIPTOR IdtTable[SEC_IDT_ENTRY_COUNT];\r
bb4aa855
JJ
39} SEC_IDT_TABLE;\r
40\r
41VOID\r
42EFIAPI\r
43SecStartupPhase2 (\r
ac0a286f 44 IN VOID *Context\r
bb4aa855
JJ
45 );\r
46\r
47EFI_STATUS\r
48EFIAPI\r
49TemporaryRamMigration (\r
ac0a286f
MK
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
bb4aa855
JJ
54 );\r
55\r
56//\r
57//\r
4040754d 58//\r
ac0a286f 59EFI_PEI_TEMPORARY_RAM_SUPPORT_PPI mTemporaryRamSupportPpi = {\r
bb4aa855
JJ
60 TemporaryRamMigration\r
61};\r
62\r
ac0a286f 63EFI_PEI_PPI_DESCRIPTOR mPrivateDispatchTable[] = {\r
bb4aa855
JJ
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
4040754d 81 }\r
bb4aa855
JJ
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
ac0a286f 96 IN OUT EFI_FIRMWARE_VOLUME_HEADER **BootFv\r
bb4aa855
JJ
97 )\r
98{\r
99 EFI_FIRMWARE_VOLUME_HEADER *Fv;\r
100 UINTN Distance;\r
101\r
ac0a286f 102 ASSERT (((UINTN)*BootFv & EFI_PAGE_MASK) == 0);\r
bb4aa855 103\r
ac0a286f
MK
104 Fv = *BootFv;\r
105 Distance = (UINTN)(*BootFv)->FvLength;\r
bb4aa855 106 do {\r
ac0a286f 107 Fv = (EFI_FIRMWARE_VOLUME_HEADER *)((UINT8 *)Fv - EFI_PAGE_SIZE);\r
bb4aa855
JJ
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
ac0a286f 117 if ((UINTN)Fv->FvLength > Distance) {\r
bb4aa855
JJ
118 continue;\r
119 }\r
120\r
121 *BootFv = Fv;\r
122 return EFI_SUCCESS;\r
bb4aa855
JJ
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
4b4b783d
JJ
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
bb4aa855
JJ
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
4b4b783d 136 @param[in] Instance The section instance number\r
bb4aa855
JJ
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
4b4b783d 145FindFfsSectionInstance (\r
ac0a286f
MK
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
bb4aa855
JJ
151 )\r
152{\r
ac0a286f
MK
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
bb4aa855
JJ
158\r
159 //\r
160 // Loop through the FFS file sections within the PEI Core FFS file\r
161 //\r
ac0a286f 162 EndOfSection = (EFI_PHYSICAL_ADDRESS)(UINTN)Sections;\r
bb4aa855 163 EndOfSections = EndOfSection + SizeOfSections;\r
ac0a286f 164 for ( ; ;) {\r
bb4aa855
JJ
165 if (EndOfSection == EndOfSections) {\r
166 break;\r
167 }\r
ac0a286f 168\r
bb4aa855
JJ
169 CurrentAddress = (EndOfSection + 3) & ~(3ULL);\r
170 if (CurrentAddress >= EndOfSections) {\r
171 return EFI_VOLUME_CORRUPTED;\r
172 }\r
173\r
ac0a286f 174 Section = (EFI_COMMON_SECTION_HEADER *)(UINTN)CurrentAddress;\r
bb4aa855
JJ
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
4b4b783d
JJ
190 if (Instance == 0) {\r
191 *FoundSection = Section;\r
192 return EFI_SUCCESS;\r
193 } else {\r
194 Instance--;\r
195 }\r
bb4aa855 196 }\r
bb4aa855
JJ
197 }\r
198\r
199 return EFI_NOT_FOUND;\r
200}\r
201\r
4b4b783d
JJ
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
ac0a286f
MK
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
4b4b783d
JJ
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
bb4aa855
JJ
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
bb4aa855 248FindFfsFileAndSection (\r
ac0a286f
MK
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
bb4aa855
JJ
253 )\r
254{\r
ac0a286f
MK
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
bb4aa855
JJ
261\r
262 if (Fv->Signature != EFI_FVH_SIGNATURE) {\r
70d5086c 263 DEBUG ((DEBUG_ERROR, "FV at %p does not have FV header signature\n", Fv));\r
bb4aa855
JJ
264 return EFI_VOLUME_CORRUPTED;\r
265 }\r
266\r
ac0a286f 267 CurrentAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)Fv;\r
bb4aa855
JJ
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
bb4aa855
JJ
274 CurrentAddress = (EndOfFile + 7) & ~(7ULL);\r
275 if (CurrentAddress > EndOfFirmwareVolume) {\r
276 return EFI_VOLUME_CORRUPTED;\r
277 }\r
278\r
ac0a286f 279 File = (EFI_FFS_FILE_HEADER *)(UINTN)CurrentAddress;\r
b9d4847e 280 Size = FFS_FILE_SIZE (File);\r
bb4aa855
JJ
281 if (Size < (sizeof (*File) + sizeof (EFI_COMMON_SECTION_HEADER))) {\r
282 return EFI_VOLUME_CORRUPTED;\r
283 }\r
bb4aa855
JJ
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
bb4aa855
JJ
294 continue;\r
295 }\r
296\r
297 Status = FindFfsSectionInSections (\r
ac0a286f
MK
298 (VOID *)(File + 1),\r
299 (UINTN)EndOfFile - (UINTN)(File + 1),\r
bb4aa855
JJ
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
b36f701d 313 On output, the decompressed BOOT/PEI FV\r
bb4aa855
JJ
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
b36f701d 321DecompressMemFvs (\r
ac0a286f 322 IN OUT EFI_FIRMWARE_VOLUME_HEADER **Fv\r
bb4aa855
JJ
323 )\r
324{\r
ac0a286f
MK
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
bb4aa855
JJ
340\r
341 Status = FindFfsFileAndSection (\r
342 *Fv,\r
343 EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE,\r
344 EFI_SECTION_GUID_DEFINED,\r
ac0a286f 345 (EFI_COMMON_SECTION_HEADER **)&Section\r
bb4aa855
JJ
346 );\r
347 if (EFI_ERROR (Status)) {\r
70d5086c 348 DEBUG ((DEBUG_ERROR, "Unable to find GUID defined section\n"));\r
bb4aa855
JJ
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
70d5086c 359 DEBUG ((DEBUG_ERROR, "Unable to GetInfo for GUIDed section\n"));\r
bb4aa855
JJ
360 return Status;\r
361 }\r
362\r
ac0a286f
MK
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
9beac0d8 381\r
bb4aa855
JJ
382 Status = ExtractGuidedSectionDecode (\r
383 Section,\r
384 &OutputBuffer,\r
385 ScratchBuffer,\r
386 &AuthenticationStatus\r
387 );\r
388 if (EFI_ERROR (Status)) {\r
70d5086c 389 DEBUG ((DEBUG_ERROR, "Error during GUID section decode\n"));\r
bb4aa855
JJ
390 return Status;\r
391 }\r
392\r
b36f701d 393 Status = FindFfsSectionInstance (\r
bb4aa855
JJ
394 OutputBuffer,\r
395 OutputBufferSize,\r
396 EFI_SECTION_FIRMWARE_VOLUME_IMAGE,\r
b36f701d 397 0,\r
5e443e37 398 &FvSection\r
bb4aa855
JJ
399 );\r
400 if (EFI_ERROR (Status)) {\r
70d5086c 401 DEBUG ((DEBUG_ERROR, "Unable to find PEI FV section\n"));\r
bb4aa855
JJ
402 return Status;\r
403 }\r
404\r
ac0a286f
MK
405 ASSERT (\r
406 SECTION_SIZE (FvSection) ==\r
407 (PcdGet32 (PcdOvmfPeiMemFvSize) + sizeof (*FvSection))\r
408 );\r
b36f701d 409 ASSERT (FvSection->Type == EFI_SECTION_FIRMWARE_VOLUME_IMAGE);\r
bb4aa855 410\r
ac0a286f
MK
411 PeiMemFv = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)PcdGet32 (PcdOvmfPeiMemFvBase);\r
412 CopyMem (PeiMemFv, (VOID *)(FvSection + 1), PcdGet32 (PcdOvmfPeiMemFvSize));\r
b36f701d
JJ
413\r
414 if (PeiMemFv->Signature != EFI_FVH_SIGNATURE) {\r
70d5086c 415 DEBUG ((DEBUG_ERROR, "Extracted FV at %p does not have FV header signature\n", PeiMemFv));\r
b36f701d
JJ
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
5e443e37 425 &FvSection\r
b36f701d
JJ
426 );\r
427 if (EFI_ERROR (Status)) {\r
70d5086c 428 DEBUG ((DEBUG_ERROR, "Unable to find DXE FV section\n"));\r
b36f701d
JJ
429 return Status;\r
430 }\r
431\r
432 ASSERT (FvSection->Type == EFI_SECTION_FIRMWARE_VOLUME_IMAGE);\r
39dbc4d5
TP
433\r
434 if (IS_SECTION2 (FvSection)) {\r
435 FvSectionSize = SECTION2_SIZE (FvSection);\r
ac0a286f 436 FvHeaderSize = sizeof (EFI_COMMON_SECTION_HEADER2);\r
39dbc4d5
TP
437 } else {\r
438 FvSectionSize = SECTION_SIZE (FvSection);\r
ac0a286f 439 FvHeaderSize = sizeof (EFI_COMMON_SECTION_HEADER);\r
39dbc4d5
TP
440 }\r
441\r
442 ASSERT (FvSectionSize == (PcdGet32 (PcdOvmfDxeMemFvSize) + FvHeaderSize));\r
b36f701d 443\r
ac0a286f
MK
444 DxeMemFv = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)PcdGet32 (PcdOvmfDxeMemFvBase);\r
445 CopyMem (DxeMemFv, (VOID *)((UINTN)FvSection + FvHeaderSize), PcdGet32 (PcdOvmfDxeMemFvSize));\r
b36f701d
JJ
446\r
447 if (DxeMemFv->Signature != EFI_FVH_SIGNATURE) {\r
70d5086c 448 DEBUG ((DEBUG_ERROR, "Extracted FV at %p does not have FV header signature\n", DxeMemFv));\r
bb4aa855
JJ
449 CpuDeadLoop ();\r
450 return EFI_VOLUME_CORRUPTED;\r
451 }\r
452\r
b36f701d 453 *Fv = PeiMemFv;\r
bb4aa855
JJ
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
bb4aa855 469FindPeiCoreImageBaseInFv (\r
ac0a286f
MK
470 IN EFI_FIRMWARE_VOLUME_HEADER *Fv,\r
471 OUT EFI_PHYSICAL_ADDRESS *PeiCoreImageBase\r
bb4aa855
JJ
472 )\r
473{\r
ac0a286f
MK
474 EFI_STATUS Status;\r
475 EFI_COMMON_SECTION_HEADER *Section;\r
bb4aa855
JJ
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
70d5086c 491 DEBUG ((DEBUG_ERROR, "Unable to find PEI Core image\n"));\r
bb4aa855
JJ
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
a781f709
JJ
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
ac0a286f 514 IN UINTN Index\r
a781f709
JJ
515 )\r
516{\r
ac0a286f 517 IoWrite8 (0x70, (UINT8)Index);\r
a781f709
JJ
518 return IoRead8 (0x71);\r
519}\r
520\r
a781f709
JJ
521STATIC\r
522BOOLEAN\r
523IsS3Resume (\r
524 VOID\r
525 )\r
526{\r
527 return (CmosRead8 (0xF) == 0xFE);\r
528}\r
529\r
a781f709
JJ
530STATIC\r
531EFI_STATUS\r
532GetS3ResumePeiFv (\r
ac0a286f 533 IN OUT EFI_FIRMWARE_VOLUME_HEADER **PeiFv\r
a781f709
JJ
534 )\r
535{\r
ac0a286f 536 *PeiFv = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)PcdGet32 (PcdOvmfPeiMemFvBase);\r
a781f709
JJ
537 return EFI_SUCCESS;\r
538}\r
539\r
bb4aa855
JJ
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
bb4aa855 552FindPeiCoreImageBase (\r
ac0a286f
MK
553 IN OUT EFI_FIRMWARE_VOLUME_HEADER **BootFv,\r
554 OUT EFI_PHYSICAL_ADDRESS *PeiCoreImageBase\r
bb4aa855
JJ
555 )\r
556{\r
ac0a286f 557 BOOLEAN S3Resume;\r
efb0f16e 558\r
bb4aa855
JJ
559 *PeiCoreImageBase = 0;\r
560\r
efb0f16e
LE
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
70d5086c 567 DEBUG ((DEBUG_VERBOSE, "SEC: S3 resume\n"));\r
a781f709
JJ
568 GetS3ResumePeiFv (BootFv);\r
569 } else {\r
efb0f16e
LE
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
ac0a286f
MK
574 DEBUG ((\r
575 DEBUG_VERBOSE,\r
576 "SEC: %a\n",\r
577 S3Resume ? "S3 resume (with PEI decompression)" : "Normal boot"\r
578 ));\r
a781f709 579 FindMainFv (BootFv);\r
bb4aa855 580\r
a781f709
JJ
581 DecompressMemFvs (BootFv);\r
582 }\r
bb4aa855
JJ
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
bb4aa855 592FindImageBase (\r
ac0a286f
MK
593 IN EFI_FIRMWARE_VOLUME_HEADER *BootFirmwareVolumePtr,\r
594 OUT EFI_PHYSICAL_ADDRESS *SecCoreImageBase\r
bb4aa855
JJ
595 )\r
596{\r
ac0a286f
MK
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
bb4aa855
JJ
604\r
605 *SecCoreImageBase = 0;\r
606\r
ac0a286f 607 CurrentAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)BootFirmwareVolumePtr;\r
bb4aa855
JJ
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
bb4aa855
JJ
614 CurrentAddress = (EndOfFile + 7) & 0xfffffffffffffff8ULL;\r
615 if (CurrentAddress > EndOfFirmwareVolume) {\r
616 return EFI_NOT_FOUND;\r
617 }\r
618\r
ac0a286f 619 File = (EFI_FFS_FILE_HEADER *)(UINTN)CurrentAddress;\r
b9d4847e 620 Size = FFS_FILE_SIZE (File);\r
bb4aa855
JJ
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
ac0a286f
MK
640 EndOfSection = (EFI_PHYSICAL_ADDRESS)(UINTN)(File + 1);\r
641 for ( ; ;) {\r
bb4aa855 642 CurrentAddress = (EndOfSection + 3) & 0xfffffffffffffffcULL;\r
ac0a286f 643 Section = (EFI_COMMON_SECTION_HEADER *)(UINTN)CurrentAddress;\r
bb4aa855 644\r
b9d4847e 645 Size = SECTION_SIZE (Section);\r
bb4aa855
JJ
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
ac0a286f 658 if ((Section->Type == EFI_SECTION_PE32) || (Section->Type == EFI_SECTION_TE)) {\r
bb4aa855 659 if (File->Type == EFI_FV_FILETYPE_SECURITY_CORE) {\r
ac0a286f 660 *SecCoreImageBase = (PHYSICAL_ADDRESS)(UINTN)(Section + 1);\r
bb4aa855 661 }\r
ac0a286f 662\r
bb4aa855
JJ
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
f17c0ab6 679 It also find SEC and PEI Core file debug information. It will report them if\r
bb4aa855
JJ
680 remote debug is enabled.\r
681\r
682**/\r
683VOID\r
bb4aa855 684FindAndReportEntryPoints (\r
ac0a286f
MK
685 IN EFI_FIRMWARE_VOLUME_HEADER **BootFirmwareVolumePtr,\r
686 OUT EFI_PEI_CORE_ENTRY_POINT *PeiCoreEntryPoint\r
bb4aa855
JJ
687 )\r
688{\r
ac0a286f
MK
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
bb4aa855
JJ
693\r
694 //\r
695 // Find SEC Core and PEI Core image base\r
ac0a286f 696 //\r
bb4aa855
JJ
697 Status = FindImageBase (*BootFirmwareVolumePtr, &SecCoreImageBase);\r
698 ASSERT_EFI_ERROR (Status);\r
699\r
700 FindPeiCoreImageBase (BootFirmwareVolumePtr, &PeiCoreImageBase);\r
4040754d 701\r
ac0a286f 702 ZeroMem ((VOID *)&ImageContext, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT));\r
bb4aa855
JJ
703 //\r
704 // Report SEC Core debug information when remote debug is enabled\r
705 //\r
706 ImageContext.ImageAddress = SecCoreImageBase;\r
ac0a286f 707 ImageContext.PdbPointer = PeCoffLoaderGetPdbPointer ((VOID *)(UINTN)ImageContext.ImageAddress);\r
bb4aa855
JJ
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
ac0a286f 714 ImageContext.PdbPointer = PeCoffLoaderGetPdbPointer ((VOID *)(UINTN)ImageContext.ImageAddress);\r
bb4aa855
JJ
715 PeCoffLoaderRelocateImageExtraAction (&ImageContext);\r
716\r
717 //\r
718 // Find PEI Core entry point\r
719 //\r
ac0a286f 720 Status = PeCoffLoaderGetEntryPoint ((VOID *)(UINTN)PeiCoreImageBase, (VOID **)PeiCoreEntryPoint);\r
bb4aa855
JJ
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
ac0a286f
MK
731 IN EFI_FIRMWARE_VOLUME_HEADER *BootFv,\r
732 IN VOID *TopOfCurrentStack\r
bb4aa855
JJ
733 )\r
734{\r
ac0a286f
MK
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
320b4f08
LE
740\r
741 //\r
742 // To ensure SMM can't be compromised on S3 resume, we must force re-init of\r
743 // the BaseExtractGuidedSectionLib. Since this is before library contructors\r
744 // are called, we must use a loop rather than SetMem.\r
745 //\r
ac0a286f 746 Table = (UINT8 *)(UINTN)FixedPcdGet64 (PcdGuidedExtractHandlerTableAddress);\r
320b4f08
LE
747 for (Index = 0;\r
748 Index < FixedPcdGet32 (PcdGuidedExtractHandlerTableSize);\r
ac0a286f
MK
749 ++Index)\r
750 {\r
320b4f08
LE
751 Table[Index] = 0;\r
752 }\r
bb4aa855 753\r
13e5492b
TL
754 //\r
755 // Initialize IDT - Since this is before library constructors are called,\r
756 // we use a loop rather than CopyMem.\r
757 //\r
758 IdtTableInStack.PeiService = NULL;\r
ac0a286f 759 for (Index = 0; Index < SEC_IDT_ENTRY_COUNT; Index++) {\r
13e5492b
TL
760 UINT8 *Src;\r
761 UINT8 *Dst;\r
762 UINTN Byte;\r
763\r
ac0a286f
MK
764 Src = (UINT8 *)&mIdtEntryTemplate;\r
765 Dst = (UINT8 *)&IdtTableInStack.IdtTable[Index];\r
13e5492b
TL
766 for (Byte = 0; Byte < sizeof (mIdtEntryTemplate); Byte++) {\r
767 Dst[Byte] = Src[Byte];\r
768 }\r
769 }\r
770\r
771 IdtDescriptor.Base = (UINTN)&IdtTableInStack.IdtTable;\r
772 IdtDescriptor.Limit = (UINT16)(sizeof (IdtTableInStack.IdtTable) - 1);\r
773\r
774 if (SevEsIsEnabled ()) {\r
775 SevEsProtocolCheck ();\r
776\r
777 //\r
778 // For SEV-ES guests, the exception handler is needed before calling\r
779 // ProcessLibraryConstructorList() because some of the library constructors\r
780 // perform some functions that result in #VC exceptions being generated.\r
781 //\r
782 // Due to this code executing before library constructors, *all* library\r
783 // API calls are theoretically interface contract violations. However,\r
784 // because this is SEC (executing in flash), those constructors cannot\r
785 // write variables with static storage duration anyway. Furthermore, only\r
786 // a small, restricted set of APIs, such as AsmWriteIdtr() and\r
787 // InitializeCpuExceptionHandlers(), are called, where we require that the\r
788 // underlying library not require constructors to have been invoked and\r
789 // that the library instance not trigger any #VC exceptions.\r
790 //\r
791 AsmWriteIdtr (&IdtDescriptor);\r
792 InitializeCpuExceptionHandlers (NULL);\r
793 }\r
794\r
bb4aa855
JJ
795 ProcessLibraryConstructorList (NULL, NULL);\r
796\r
13e5492b
TL
797 if (!SevEsIsEnabled ()) {\r
798 //\r
799 // For non SEV-ES guests, just load the IDTR.\r
800 //\r
801 AsmWriteIdtr (&IdtDescriptor);\r
e2db781f
TL
802 } else {\r
803 //\r
804 // Under SEV-ES, the hypervisor can't modify CR0 and so can't enable\r
805 // caching in order to speed up the boot. Enable caching early for\r
806 // an SEV-ES guest.\r
807 //\r
808 AsmEnableCache ();\r
13e5492b
TL
809 }\r
810\r
ac0a286f
MK
811 DEBUG ((\r
812 DEBUG_INFO,\r
bb4aa855
JJ
813 "SecCoreStartupWithStack(0x%x, 0x%x)\n",\r
814 (UINT32)(UINTN)BootFv,\r
815 (UINT32)(UINTN)TopOfCurrentStack\r
816 ));\r
817\r
818 //\r
819 // Initialize floating point operating environment\r
820 // to be compliant with UEFI spec.\r
821 //\r
822 InitializeFloatingPointUnits ();\r
823\r
ac0a286f 824 #if defined (MDE_CPU_X64)\r
b382ede3
JJ
825 //\r
826 // ASSERT that the Page Tables were set by the reset vector code to\r
827 // the address we expect.\r
828 //\r
ac0a286f
MK
829 ASSERT (AsmReadCr3 () == (UINTN)PcdGet32 (PcdOvmfSecPageTablesBase));\r
830 #endif\r
b382ede3 831\r
bb4aa855
JJ
832 //\r
833 // |-------------| <-- TopOfCurrentStack\r
834 // | Stack | 32k\r
835 // |-------------|\r
836 // | Heap | 32k\r
837 // |-------------| <-- SecCoreData.TemporaryRamBase\r
838 //\r
839\r
ac0a286f
MK
840 ASSERT (\r
841 (UINTN)(PcdGet32 (PcdOvmfSecPeiTempRamBase) +\r
842 PcdGet32 (PcdOvmfSecPeiTempRamSize)) ==\r
843 (UINTN)TopOfCurrentStack\r
844 );\r
7cb6b0e0 845\r
bb4aa855
JJ
846 //\r
847 // Initialize SEC hand-off state\r
848 //\r
ac0a286f 849 SecCoreData.DataSize = sizeof (EFI_SEC_PEI_HAND_OFF);\r
bb4aa855 850\r
ac0a286f
MK
851 SecCoreData.TemporaryRamSize = (UINTN)PcdGet32 (PcdOvmfSecPeiTempRamSize);\r
852 SecCoreData.TemporaryRamBase = (VOID *)((UINT8 *)TopOfCurrentStack - SecCoreData.TemporaryRamSize);\r
bb4aa855 853\r
ac0a286f
MK
854 SecCoreData.PeiTemporaryRamBase = SecCoreData.TemporaryRamBase;\r
855 SecCoreData.PeiTemporaryRamSize = SecCoreData.TemporaryRamSize >> 1;\r
bb4aa855 856\r
ac0a286f
MK
857 SecCoreData.StackBase = (UINT8 *)SecCoreData.TemporaryRamBase + SecCoreData.PeiTemporaryRamSize;\r
858 SecCoreData.StackSize = SecCoreData.TemporaryRamSize >> 1;\r
bb4aa855
JJ
859\r
860 SecCoreData.BootFirmwareVolumeBase = BootFv;\r
ac0a286f 861 SecCoreData.BootFirmwareVolumeSize = (UINTN)BootFv->FvLength;\r
bb4aa855 862\r
202fb22b
BS
863 //\r
864 // Validate the System RAM used in the SEC Phase\r
865 //\r
866 SecValidateSystemRam ();\r
867\r
bb4aa855
JJ
868 //\r
869 // Make sure the 8259 is masked before initializing the Debug Agent and the debug timer is enabled\r
870 //\r
871 IoWrite8 (0x21, 0xff);\r
872 IoWrite8 (0xA1, 0xff);\r
f3e34b9d
MK
873\r
874 //\r
875 // Initialize Local APIC Timer hardware and disable Local APIC Timer\r
876 // interrupts before initializing the Debug Agent and the debug timer is\r
877 // enabled.\r
878 //\r
879 InitializeApicTimer (0, MAX_UINT32, TRUE, 5);\r
880 DisableApicTimerInterrupt ();\r
4040754d 881\r
bb4aa855
JJ
882 //\r
883 // Initialize Debug Agent to support source level debug in SEC/PEI phases before memory ready.\r
884 //\r
885 InitializeDebugAgent (DEBUG_AGENT_INIT_PREMEM_SEC, &SecCoreData, SecStartupPhase2);\r
886}\r
4040754d 887\r
bb4aa855
JJ
888/**\r
889 Caller provided function to be invoked at the end of InitializeDebugAgent().\r
890\r
891 Entry point to the C language phase of SEC. After the SEC assembly\r
892 code has initialized some temporary memory and set up the stack,\r
893 the control is transferred to this function.\r
894\r
895 @param[in] Context The first input parameter of InitializeDebugAgent().\r
896\r
897**/\r
898VOID\r
899EFIAPI\r
ac0a286f
MK
900SecStartupPhase2 (\r
901 IN VOID *Context\r
bb4aa855
JJ
902 )\r
903{\r
904 EFI_SEC_PEI_HAND_OFF *SecCoreData;\r
905 EFI_FIRMWARE_VOLUME_HEADER *BootFv;\r
906 EFI_PEI_CORE_ENTRY_POINT PeiCoreEntryPoint;\r
4040754d 907\r
ac0a286f 908 SecCoreData = (EFI_SEC_PEI_HAND_OFF *)Context;\r
4040754d 909\r
bb4aa855
JJ
910 //\r
911 // Find PEI Core entry point. It will report SEC and Pei Core debug information if remote debug\r
912 // is enabled.\r
913 //\r
914 BootFv = (EFI_FIRMWARE_VOLUME_HEADER *)SecCoreData->BootFirmwareVolumeBase;\r
915 FindAndReportEntryPoints (&BootFv, &PeiCoreEntryPoint);\r
916 SecCoreData->BootFirmwareVolumeBase = BootFv;\r
ac0a286f 917 SecCoreData->BootFirmwareVolumeSize = (UINTN)BootFv->FvLength;\r
bb4aa855
JJ
918\r
919 //\r
920 // Transfer the control to the PEI core\r
921 //\r
ac0a286f 922 (*PeiCoreEntryPoint)(SecCoreData, (EFI_PEI_PPI_DESCRIPTOR *)&mPrivateDispatchTable);\r
4040754d 923\r
bb4aa855
JJ
924 //\r
925 // If we get here then the PEI Core returned, which is not recoverable.\r
926 //\r
927 ASSERT (FALSE);\r
928 CpuDeadLoop ();\r
929}\r
930\r
931EFI_STATUS\r
932EFIAPI\r
933TemporaryRamMigration (\r
ac0a286f
MK
934 IN CONST EFI_PEI_SERVICES **PeiServices,\r
935 IN EFI_PHYSICAL_ADDRESS TemporaryMemoryBase,\r
936 IN EFI_PHYSICAL_ADDRESS PermanentMemoryBase,\r
937 IN UINTN CopySize\r
bb4aa855
JJ
938 )\r
939{\r
940 IA32_DESCRIPTOR IdtDescriptor;\r
941 VOID *OldHeap;\r
942 VOID *NewHeap;\r
943 VOID *OldStack;\r
944 VOID *NewStack;\r
945 DEBUG_AGENT_CONTEXT_POSTMEM_SEC DebugAgentContext;\r
946 BOOLEAN OldStatus;\r
947 BASE_LIBRARY_JUMP_BUFFER JumpBuffer;\r
4040754d 948\r
ac0a286f
MK
949 DEBUG ((\r
950 DEBUG_INFO,\r
6394c35a
LE
951 "TemporaryRamMigration(0x%Lx, 0x%Lx, 0x%Lx)\n",\r
952 TemporaryMemoryBase,\r
953 PermanentMemoryBase,\r
954 (UINT64)CopySize\r
c67178b7 955 ));\r
4040754d 956\r
ac0a286f
MK
957 OldHeap = (VOID *)(UINTN)TemporaryMemoryBase;\r
958 NewHeap = (VOID *)((UINTN)PermanentMemoryBase + (CopySize >> 1));\r
4040754d 959\r
ac0a286f
MK
960 OldStack = (VOID *)((UINTN)TemporaryMemoryBase + (CopySize >> 1));\r
961 NewStack = (VOID *)(UINTN)PermanentMemoryBase;\r
bb4aa855 962\r
ac0a286f 963 DebugAgentContext.HeapMigrateOffset = (UINTN)NewHeap - (UINTN)OldHeap;\r
bb4aa855 964 DebugAgentContext.StackMigrateOffset = (UINTN)NewStack - (UINTN)OldStack;\r
4040754d 965\r
bb4aa855 966 OldStatus = SaveAndSetDebugTimerInterrupt (FALSE);\r
ac0a286f 967 InitializeDebugAgent (DEBUG_AGENT_INIT_POSTMEM_SEC, (VOID *)&DebugAgentContext, NULL);\r
bb4aa855
JJ
968\r
969 //\r
970 // Migrate Heap\r
971 //\r
972 CopyMem (NewHeap, OldHeap, CopySize >> 1);\r
973\r
974 //\r
975 // Migrate Stack\r
976 //\r
977 CopyMem (NewStack, OldStack, CopySize >> 1);\r
4040754d 978\r
bb4aa855
JJ
979 //\r
980 // Rebase IDT table in permanent memory\r
981 //\r
982 AsmReadIdtr (&IdtDescriptor);\r
983 IdtDescriptor.Base = IdtDescriptor.Base - (UINTN)OldStack + (UINTN)NewStack;\r
984\r
985 AsmWriteIdtr (&IdtDescriptor);\r
986\r
987 //\r
988 // Use SetJump()/LongJump() to switch to a new stack.\r
4040754d 989 //\r
bb4aa855 990 if (SetJump (&JumpBuffer) == 0) {\r
ac0a286f 991 #if defined (MDE_CPU_IA32)\r
bb4aa855 992 JumpBuffer.Esp = JumpBuffer.Esp + DebugAgentContext.StackMigrateOffset;\r
89796c69 993 JumpBuffer.Ebp = JumpBuffer.Ebp + DebugAgentContext.StackMigrateOffset;\r
ac0a286f
MK
994 #endif\r
995 #if defined (MDE_CPU_X64)\r
bb4aa855 996 JumpBuffer.Rsp = JumpBuffer.Rsp + DebugAgentContext.StackMigrateOffset;\r
89796c69 997 JumpBuffer.Rbp = JumpBuffer.Rbp + DebugAgentContext.StackMigrateOffset;\r
ac0a286f 998 #endif\r
bb4aa855
JJ
999 LongJump (&JumpBuffer, (UINTN)-1);\r
1000 }\r
1001\r
1002 SaveAndSetDebugTimerInterrupt (OldStatus);\r
1003\r
1004 return EFI_SUCCESS;\r
1005}\r