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