2 Main SEC phase code. Transitions to PEI.
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>
8 SPDX-License-Identifier: BSD-2-Clause-Patent
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>
33 #include <Ppi/TemporaryRamSupport.h>
35 #define SEC_IDT_ENTRY_COUNT 34
37 typedef struct _SEC_IDT_TABLE
{
38 EFI_PEI_SERVICES
*PeiService
;
39 IA32_IDT_GATE_DESCRIPTOR IdtTable
[SEC_IDT_ENTRY_COUNT
];
50 TemporaryRamMigration (
51 IN CONST EFI_PEI_SERVICES
**PeiServices
,
52 IN EFI_PHYSICAL_ADDRESS TemporaryMemoryBase
,
53 IN EFI_PHYSICAL_ADDRESS PermanentMemoryBase
,
60 EFI_PEI_TEMPORARY_RAM_SUPPORT_PPI mTemporaryRamSupportPpi
= {
64 EFI_PEI_PPI_DESCRIPTOR mPrivateDispatchTable
[] = {
66 (EFI_PEI_PPI_DESCRIPTOR_PPI
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
),
67 &gEfiTemporaryRamSupportPpiGuid
,
68 &mTemporaryRamSupportPpi
73 // Template of an IDT entry pointing to 10:FFFFFFE4h.
75 IA32_IDT_GATE_DESCRIPTOR mIdtEntryTemplate
= {
80 IA32_IDT_GATE_TYPE_INTERRUPT_32
, // GateType
86 Locates the main boot firmware volume.
88 @param[in,out] BootFv On input, the base of the BootFv
89 On output, the decompressed main firmware volume
91 @retval EFI_SUCCESS The main firmware volume was located and decompressed
92 @retval EFI_NOT_FOUND The main firmware volume was not found
97 IN OUT EFI_FIRMWARE_VOLUME_HEADER
**BootFv
100 EFI_FIRMWARE_VOLUME_HEADER
*Fv
;
103 ASSERT (((UINTN
)*BootFv
& EFI_PAGE_MASK
) == 0);
106 Distance
= (UINTN
)(*BootFv
)->FvLength
;
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
;
114 if (Fv
->Signature
!= EFI_FVH_SIGNATURE
) {
118 if ((UINTN
)Fv
->FvLength
> Distance
) {
128 Locates a section within a series of sections
129 with the specified section type.
131 The Instance parameter indicates which instance of the section
132 type to return. (0 is first instance, 1 is second...)
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
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
146 FindFfsSectionInstance (
148 IN UINTN SizeOfSections
,
149 IN EFI_SECTION_TYPE SectionType
,
151 OUT EFI_COMMON_SECTION_HEADER
**FoundSection
154 EFI_PHYSICAL_ADDRESS CurrentAddress
;
156 EFI_PHYSICAL_ADDRESS EndOfSections
;
157 EFI_COMMON_SECTION_HEADER
*Section
;
158 EFI_PHYSICAL_ADDRESS EndOfSection
;
161 // Loop through the FFS file sections within the PEI Core FFS file
163 EndOfSection
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)Sections
;
164 EndOfSections
= EndOfSection
+ SizeOfSections
;
166 if (EndOfSection
== EndOfSections
) {
170 CurrentAddress
= (EndOfSection
+ 3) & ~(3ULL);
171 if (CurrentAddress
>= EndOfSections
) {
172 return EFI_VOLUME_CORRUPTED
;
175 Section
= (EFI_COMMON_SECTION_HEADER
*)(UINTN
)CurrentAddress
;
177 Size
= SECTION_SIZE (Section
);
178 if (Size
< sizeof (*Section
)) {
179 return EFI_VOLUME_CORRUPTED
;
182 EndOfSection
= CurrentAddress
+ Size
;
183 if (EndOfSection
> EndOfSections
) {
184 return EFI_VOLUME_CORRUPTED
;
188 // Look for the requested section type
190 if (Section
->Type
== SectionType
) {
192 *FoundSection
= Section
;
200 return EFI_NOT_FOUND
;
204 Locates a section within a series of sections
205 with the specified section type.
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
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
218 FindFfsSectionInSections (
220 IN UINTN SizeOfSections
,
221 IN EFI_SECTION_TYPE SectionType
,
222 OUT EFI_COMMON_SECTION_HEADER
**FoundSection
225 return FindFfsSectionInstance (
235 Locates a FFS file with the specified file type and a section
236 within that file with the specified section type.
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
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
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
257 EFI_PHYSICAL_ADDRESS CurrentAddress
;
258 EFI_PHYSICAL_ADDRESS EndOfFirmwareVolume
;
259 EFI_FFS_FILE_HEADER
*File
;
261 EFI_PHYSICAL_ADDRESS EndOfFile
;
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
;
268 CurrentAddress
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)Fv
;
269 EndOfFirmwareVolume
= CurrentAddress
+ Fv
->FvLength
;
272 // Loop through the FFS files in the Boot Firmware Volume
274 for (EndOfFile
= CurrentAddress
+ Fv
->HeaderLength
; ; ) {
275 CurrentAddress
= (EndOfFile
+ 7) & ~(7ULL);
276 if (CurrentAddress
> EndOfFirmwareVolume
) {
277 return EFI_VOLUME_CORRUPTED
;
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
;
286 EndOfFile
= CurrentAddress
+ Size
;
287 if (EndOfFile
> EndOfFirmwareVolume
) {
288 return EFI_VOLUME_CORRUPTED
;
292 // Look for the request file type
294 if (File
->Type
!= FileType
) {
298 Status
= FindFfsSectionInSections (
300 (UINTN
)EndOfFile
- (UINTN
)(File
+ 1),
304 if (!EFI_ERROR (Status
) || (Status
== EFI_VOLUME_CORRUPTED
)) {
311 Locates the compressed main firmware volume and decompresses it.
313 @param[in,out] Fv On input, the firmware volume to search
314 On output, the decompressed BOOT/PEI FV
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
323 IN OUT EFI_FIRMWARE_VOLUME_HEADER
**Fv
327 EFI_GUID_DEFINED_SECTION
*Section
;
328 UINT32 OutputBufferSize
;
329 UINT32 ScratchBufferSize
;
330 UINT16 SectionAttribute
;
331 UINT32 AuthenticationStatus
;
334 EFI_COMMON_SECTION_HEADER
*FvSection
;
335 EFI_FIRMWARE_VOLUME_HEADER
*PeiMemFv
;
336 EFI_FIRMWARE_VOLUME_HEADER
*DxeMemFv
;
338 UINT32 FvSectionSize
;
340 FvSection
= (EFI_COMMON_SECTION_HEADER
*)NULL
;
342 Status
= FindFfsFileAndSection (
344 EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE
,
345 EFI_SECTION_GUID_DEFINED
,
346 (EFI_COMMON_SECTION_HEADER
**)&Section
348 if (EFI_ERROR (Status
)) {
349 DEBUG ((DEBUG_ERROR
, "Unable to find GUID defined section\n"));
353 Status
= ExtractGuidedSectionGetInfo (
359 if (EFI_ERROR (Status
)) {
360 DEBUG ((DEBUG_ERROR
, "Unable to GetInfo for GUIDed section\n"));
364 OutputBuffer
= (VOID
*)((UINT8
*)(UINTN
)PcdGet32 (PcdOvmfDxeMemFvBase
) + SIZE_1MB
);
365 ScratchBuffer
= ALIGN_POINTER ((UINT8
*)OutputBuffer
+ OutputBufferSize
, SIZE_1MB
);
369 "%a: OutputBuffer@%p+0x%x ScratchBuffer@%p+0x%x "
370 "PcdOvmfDecompressionScratchEnd=0x%x\n",
376 PcdGet32 (PcdOvmfDecompressionScratchEnd
)
379 (UINTN
)ScratchBuffer
+ ScratchBufferSize
==
380 PcdGet32 (PcdOvmfDecompressionScratchEnd
)
383 Status
= ExtractGuidedSectionDecode (
387 &AuthenticationStatus
389 if (EFI_ERROR (Status
)) {
390 DEBUG ((DEBUG_ERROR
, "Error during GUID section decode\n"));
394 Status
= FindFfsSectionInstance (
397 EFI_SECTION_FIRMWARE_VOLUME_IMAGE
,
401 if (EFI_ERROR (Status
)) {
402 DEBUG ((DEBUG_ERROR
, "Unable to find PEI FV section\n"));
407 SECTION_SIZE (FvSection
) ==
408 (PcdGet32 (PcdOvmfPeiMemFvSize
) + sizeof (*FvSection
))
410 ASSERT (FvSection
->Type
== EFI_SECTION_FIRMWARE_VOLUME_IMAGE
);
412 PeiMemFv
= (EFI_FIRMWARE_VOLUME_HEADER
*)(UINTN
)PcdGet32 (PcdOvmfPeiMemFvBase
);
413 CopyMem (PeiMemFv
, (VOID
*)(FvSection
+ 1), PcdGet32 (PcdOvmfPeiMemFvSize
));
415 if (PeiMemFv
->Signature
!= EFI_FVH_SIGNATURE
) {
416 DEBUG ((DEBUG_ERROR
, "Extracted FV at %p does not have FV header signature\n", PeiMemFv
));
418 return EFI_VOLUME_CORRUPTED
;
421 Status
= FindFfsSectionInstance (
424 EFI_SECTION_FIRMWARE_VOLUME_IMAGE
,
428 if (EFI_ERROR (Status
)) {
429 DEBUG ((DEBUG_ERROR
, "Unable to find DXE FV section\n"));
433 ASSERT (FvSection
->Type
== EFI_SECTION_FIRMWARE_VOLUME_IMAGE
);
435 if (IS_SECTION2 (FvSection
)) {
436 FvSectionSize
= SECTION2_SIZE (FvSection
);
437 FvHeaderSize
= sizeof (EFI_COMMON_SECTION_HEADER2
);
439 FvSectionSize
= SECTION_SIZE (FvSection
);
440 FvHeaderSize
= sizeof (EFI_COMMON_SECTION_HEADER
);
443 ASSERT (FvSectionSize
== (PcdGet32 (PcdOvmfDxeMemFvSize
) + FvHeaderSize
));
445 DxeMemFv
= (EFI_FIRMWARE_VOLUME_HEADER
*)(UINTN
)PcdGet32 (PcdOvmfDxeMemFvBase
);
446 CopyMem (DxeMemFv
, (VOID
*)((UINTN
)FvSection
+ FvHeaderSize
), PcdGet32 (PcdOvmfDxeMemFvSize
));
448 if (DxeMemFv
->Signature
!= EFI_FVH_SIGNATURE
) {
449 DEBUG ((DEBUG_ERROR
, "Extracted FV at %p does not have FV header signature\n", DxeMemFv
));
451 return EFI_VOLUME_CORRUPTED
;
459 Locates the PEI Core entry point address
461 @param[in] Fv The firmware volume to search
462 @param[out] PeiCoreEntryPoint The entry point of the PEI Core image
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
470 FindPeiCoreImageBaseInFv (
471 IN EFI_FIRMWARE_VOLUME_HEADER
*Fv
,
472 OUT EFI_PHYSICAL_ADDRESS
*PeiCoreImageBase
476 EFI_COMMON_SECTION_HEADER
*Section
;
478 Status
= FindFfsFileAndSection (
480 EFI_FV_FILETYPE_PEI_CORE
,
484 if (EFI_ERROR (Status
)) {
485 Status
= FindFfsFileAndSection (
487 EFI_FV_FILETYPE_PEI_CORE
,
491 if (EFI_ERROR (Status
)) {
492 DEBUG ((DEBUG_ERROR
, "Unable to find PEI Core image\n"));
497 *PeiCoreImageBase
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)(Section
+ 1);
502 Reads 8-bits of CMOS data.
504 Reads the 8-bits of CMOS data at the location specified by Index.
505 The 8-bit read value is returned.
507 @param Index The CMOS location to read.
509 @return The value read.
518 IoWrite8 (0x70, (UINT8
)Index
);
519 return IoRead8 (0x71);
528 return (CmosRead8 (0xF) == 0xFE);
534 IN OUT EFI_FIRMWARE_VOLUME_HEADER
**PeiFv
537 *PeiFv
= (EFI_FIRMWARE_VOLUME_HEADER
*)(UINTN
)PcdGet32 (PcdOvmfPeiMemFvBase
);
542 Locates the PEI Core entry point address
544 @param[in,out] Fv The firmware volume to search
545 @param[out] PeiCoreEntryPoint The entry point of the PEI Core image
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
553 FindPeiCoreImageBase (
554 IN OUT EFI_FIRMWARE_VOLUME_HEADER
**BootFv
,
555 OUT EFI_PHYSICAL_ADDRESS
*PeiCoreImageBase
560 *PeiCoreImageBase
= 0;
562 S3Resume
= IsS3Resume ();
563 if (S3Resume
&& !FeaturePcdGet (PcdSmmSmramRequire
)) {
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.
568 DEBUG ((DEBUG_VERBOSE
, "SEC: S3 resume\n"));
569 GetS3ResumePeiFv (BootFv
);
572 // We're either not resuming, or resuming "securely" -- we'll decompress
573 // both PEI FV and DXE FV from pristine flash.
578 S3Resume
? "S3 resume (with PEI decompression)" : "Normal boot"
582 DecompressMemFvs (BootFv
);
585 FindPeiCoreImageBaseInFv (*BootFv
, PeiCoreImageBase
);
589 Find core image base.
594 IN EFI_FIRMWARE_VOLUME_HEADER
*BootFirmwareVolumePtr
,
595 OUT EFI_PHYSICAL_ADDRESS
*SecCoreImageBase
598 EFI_PHYSICAL_ADDRESS CurrentAddress
;
599 EFI_PHYSICAL_ADDRESS EndOfFirmwareVolume
;
600 EFI_FFS_FILE_HEADER
*File
;
602 EFI_PHYSICAL_ADDRESS EndOfFile
;
603 EFI_COMMON_SECTION_HEADER
*Section
;
604 EFI_PHYSICAL_ADDRESS EndOfSection
;
606 *SecCoreImageBase
= 0;
608 CurrentAddress
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)BootFirmwareVolumePtr
;
609 EndOfFirmwareVolume
= CurrentAddress
+ BootFirmwareVolumePtr
->FvLength
;
612 // Loop through the FFS files in the Boot Firmware Volume
614 for (EndOfFile
= CurrentAddress
+ BootFirmwareVolumePtr
->HeaderLength
; ; ) {
615 CurrentAddress
= (EndOfFile
+ 7) & 0xfffffffffffffff8ULL
;
616 if (CurrentAddress
> EndOfFirmwareVolume
) {
617 return EFI_NOT_FOUND
;
620 File
= (EFI_FFS_FILE_HEADER
*)(UINTN
)CurrentAddress
;
621 Size
= FFS_FILE_SIZE (File
);
622 if (Size
< sizeof (*File
)) {
623 return EFI_NOT_FOUND
;
626 EndOfFile
= CurrentAddress
+ Size
;
627 if (EndOfFile
> EndOfFirmwareVolume
) {
628 return EFI_NOT_FOUND
;
634 if (File
->Type
!= EFI_FV_FILETYPE_SECURITY_CORE
) {
639 // Loop through the FFS file sections within the FFS file
641 EndOfSection
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)(File
+ 1);
643 CurrentAddress
= (EndOfSection
+ 3) & 0xfffffffffffffffcULL
;
644 Section
= (EFI_COMMON_SECTION_HEADER
*)(UINTN
)CurrentAddress
;
646 Size
= SECTION_SIZE (Section
);
647 if (Size
< sizeof (*Section
)) {
648 return EFI_NOT_FOUND
;
651 EndOfSection
= CurrentAddress
+ Size
;
652 if (EndOfSection
> EndOfFile
) {
653 return EFI_NOT_FOUND
;
657 // Look for executable sections
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);
669 // SEC Core image found
671 if (*SecCoreImageBase
!= 0) {
678 Find and return Pei Core entry point.
680 It also find SEC and PEI Core file debug information. It will report them if
681 remote debug is enabled.
685 FindAndReportEntryPoints (
686 IN EFI_FIRMWARE_VOLUME_HEADER
**BootFirmwareVolumePtr
,
687 OUT EFI_PEI_CORE_ENTRY_POINT
*PeiCoreEntryPoint
691 EFI_PHYSICAL_ADDRESS SecCoreImageBase
;
692 EFI_PHYSICAL_ADDRESS PeiCoreImageBase
;
693 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext
;
696 // Find SEC Core and PEI Core image base
698 Status
= FindImageBase (*BootFirmwareVolumePtr
, &SecCoreImageBase
);
699 ASSERT_EFI_ERROR (Status
);
701 FindPeiCoreImageBase (BootFirmwareVolumePtr
, &PeiCoreImageBase
);
703 ZeroMem ((VOID
*)&ImageContext
, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT
));
705 // Report SEC Core debug information when remote debug is enabled
707 ImageContext
.ImageAddress
= SecCoreImageBase
;
708 ImageContext
.PdbPointer
= PeCoffLoaderGetPdbPointer ((VOID
*)(UINTN
)ImageContext
.ImageAddress
);
709 PeCoffLoaderRelocateImageExtraAction (&ImageContext
);
712 // Report PEI Core debug information when remote debug is enabled
714 ImageContext
.ImageAddress
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)PeiCoreImageBase
;
715 ImageContext
.PdbPointer
= PeCoffLoaderGetPdbPointer ((VOID
*)(UINTN
)ImageContext
.ImageAddress
);
716 PeCoffLoaderRelocateImageExtraAction (&ImageContext
);
719 // Find PEI Core entry point
721 Status
= PeCoffLoaderGetEntryPoint ((VOID
*)(UINTN
)PeiCoreImageBase
, (VOID
**)PeiCoreEntryPoint
);
722 if (EFI_ERROR (Status
)) {
723 *PeiCoreEntryPoint
= 0;
730 Handle an SEV-ES/GHCB protocol check failure.
732 Notify the hypervisor using the VMGEXIT instruction that the SEV-ES guest
733 wishes to be terminated.
735 @param[in] ReasonCode Reason code to provide to the hypervisor for the
741 SevEsProtocolFailure (
745 MSR_SEV_ES_GHCB_REGISTER Msr
;
748 // Use the GHCB MSR Protocol to request termination by the hypervisor
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
);
763 Validate the SEV-ES/GHCB protocol level.
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.
775 MSR_SEV_ES_GHCB_REGISTER Msr
;
779 // Use the GHCB MSR Protocol to obtain the GHCB SEV-ES Information for
782 Msr
.GhcbPhysicalAddress
= 0;
783 Msr
.GhcbInfo
.Function
= GHCB_INFO_SEV_INFO_GET
;
784 AsmWriteMsr64 (MSR_SEV_ES_GHCB
, Msr
.GhcbPhysicalAddress
);
788 Msr
.GhcbPhysicalAddress
= AsmReadMsr64 (MSR_SEV_ES_GHCB
);
790 if (Msr
.GhcbInfo
.Function
!= GHCB_INFO_SEV_INFO
) {
791 SevEsProtocolFailure (GHCB_TERMINATE_GHCB_GENERAL
);
794 if (Msr
.GhcbProtocol
.SevEsProtocolMin
> Msr
.GhcbProtocol
.SevEsProtocolMax
) {
795 SevEsProtocolFailure (GHCB_TERMINATE_GHCB_PROTOCOL
);
798 if ((Msr
.GhcbProtocol
.SevEsProtocolMin
> GHCB_VERSION_MAX
) ||
799 (Msr
.GhcbProtocol
.SevEsProtocolMax
< GHCB_VERSION_MIN
))
801 SevEsProtocolFailure (GHCB_TERMINATE_GHCB_PROTOCOL
);
805 // SEV-ES protocol checking succeeded, set the initial GHCB address
807 Msr
.GhcbPhysicalAddress
= FixedPcdGet32 (PcdOvmfSecGhcbBase
);
808 AsmWriteMsr64 (MSR_SEV_ES_GHCB
, Msr
.GhcbPhysicalAddress
);
811 SetMem (Ghcb
, sizeof (*Ghcb
), 0);
814 // Set the version to the maximum that can be supported
816 Ghcb
->ProtocolVersion
= MIN (Msr
.GhcbProtocol
.SevEsProtocolMax
, GHCB_VERSION_MAX
);
817 Ghcb
->GhcbUsage
= GHCB_STANDARD_USAGE
;
821 Determine if the SEV is active.
823 During the early booting, GuestType is set in the work area. Verify that it
826 @retval TRUE SEV is enabled
827 @retval FALSE SEV is not enabled
836 OVMF_WORK_AREA
*WorkArea
;
839 // Ensure that the size of the Confidential Computing work area header
840 // is same as what is provided through a fixed PCD.
843 (UINTN
)FixedPcdGet32 (PcdOvmfConfidentialComputingWorkAreaHeader
) ==
844 sizeof (CONFIDENTIAL_COMPUTING_WORK_AREA_HEADER
)
847 WorkArea
= (OVMF_WORK_AREA
*)FixedPcdGet32 (PcdOvmfWorkAreaBase
);
849 return ((WorkArea
!= NULL
) && (WorkArea
->Header
.GuestType
== GUEST_TYPE_AMD_SEV
));
853 Determine if SEV-ES is active.
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
859 @retval TRUE SEV-ES is enabled
860 @retval FALSE SEV-ES is not enabled
869 SEC_SEV_ES_WORK_AREA
*SevEsWorkArea
;
871 if (!IsSevGuest ()) {
875 SevEsWorkArea
= (SEC_SEV_ES_WORK_AREA
*)FixedPcdGet32 (PcdSevEsWorkAreaBase
);
877 return (SevEsWorkArea
->SevEsEnabled
!= 0);
882 SecCoreStartupWithStack (
883 IN EFI_FIRMWARE_VOLUME_HEADER
*BootFv
,
884 IN VOID
*TopOfCurrentStack
887 EFI_SEC_PEI_HAND_OFF SecCoreData
;
888 SEC_IDT_TABLE IdtTableInStack
;
889 IA32_DESCRIPTOR IdtDescriptor
;
891 volatile UINT8
*Table
;
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.
898 Table
= (UINT8
*)(UINTN
)FixedPcdGet64 (PcdGuidedExtractHandlerTableAddress
);
900 Index
< FixedPcdGet32 (PcdGuidedExtractHandlerTableSize
);
907 // Initialize IDT - Since this is before library constructors are called,
908 // we use a loop rather than CopyMem.
910 IdtTableInStack
.PeiService
= NULL
;
911 for (Index
= 0; Index
< SEC_IDT_ENTRY_COUNT
; Index
++) {
916 Src
= (UINT8
*)&mIdtEntryTemplate
;
917 Dst
= (UINT8
*)&IdtTableInStack
.IdtTable
[Index
];
918 for (Byte
= 0; Byte
< sizeof (mIdtEntryTemplate
); Byte
++) {
919 Dst
[Byte
] = Src
[Byte
];
923 IdtDescriptor
.Base
= (UINTN
)&IdtTableInStack
.IdtTable
;
924 IdtDescriptor
.Limit
= (UINT16
)(sizeof (IdtTableInStack
.IdtTable
) - 1);
926 if (SevEsIsEnabled ()) {
927 SevEsProtocolCheck ();
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.
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.
943 AsmWriteIdtr (&IdtDescriptor
);
944 InitializeCpuExceptionHandlers (NULL
);
947 ProcessLibraryConstructorList (NULL
, NULL
);
949 if (!SevEsIsEnabled ()) {
951 // For non SEV-ES guests, just load the IDTR.
953 AsmWriteIdtr (&IdtDescriptor
);
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
965 "SecCoreStartupWithStack(0x%x, 0x%x)\n",
966 (UINT32
)(UINTN
)BootFv
,
967 (UINT32
)(UINTN
)TopOfCurrentStack
971 // Initialize floating point operating environment
972 // to be compliant with UEFI spec.
974 InitializeFloatingPointUnits ();
976 #if defined (MDE_CPU_X64)
978 // ASSERT that the Page Tables were set by the reset vector code to
979 // the address we expect.
981 ASSERT (AsmReadCr3 () == (UINTN
)PcdGet32 (PcdOvmfSecPageTablesBase
));
985 // |-------------| <-- TopOfCurrentStack
989 // |-------------| <-- SecCoreData.TemporaryRamBase
993 (UINTN
)(PcdGet32 (PcdOvmfSecPeiTempRamBase
) +
994 PcdGet32 (PcdOvmfSecPeiTempRamSize
)) ==
995 (UINTN
)TopOfCurrentStack
999 // Initialize SEC hand-off state
1001 SecCoreData
.DataSize
= sizeof (EFI_SEC_PEI_HAND_OFF
);
1003 SecCoreData
.TemporaryRamSize
= (UINTN
)PcdGet32 (PcdOvmfSecPeiTempRamSize
);
1004 SecCoreData
.TemporaryRamBase
= (VOID
*)((UINT8
*)TopOfCurrentStack
- SecCoreData
.TemporaryRamSize
);
1006 SecCoreData
.PeiTemporaryRamBase
= SecCoreData
.TemporaryRamBase
;
1007 SecCoreData
.PeiTemporaryRamSize
= SecCoreData
.TemporaryRamSize
>> 1;
1009 SecCoreData
.StackBase
= (UINT8
*)SecCoreData
.TemporaryRamBase
+ SecCoreData
.PeiTemporaryRamSize
;
1010 SecCoreData
.StackSize
= SecCoreData
.TemporaryRamSize
>> 1;
1012 SecCoreData
.BootFirmwareVolumeBase
= BootFv
;
1013 SecCoreData
.BootFirmwareVolumeSize
= (UINTN
)BootFv
->FvLength
;
1016 // Make sure the 8259 is masked before initializing the Debug Agent and the debug timer is enabled
1018 IoWrite8 (0x21, 0xff);
1019 IoWrite8 (0xA1, 0xff);
1022 // Initialize Local APIC Timer hardware and disable Local APIC Timer
1023 // interrupts before initializing the Debug Agent and the debug timer is
1026 InitializeApicTimer (0, MAX_UINT32
, TRUE
, 5);
1027 DisableApicTimerInterrupt ();
1030 // Initialize Debug Agent to support source level debug in SEC/PEI phases before memory ready.
1032 InitializeDebugAgent (DEBUG_AGENT_INIT_PREMEM_SEC
, &SecCoreData
, SecStartupPhase2
);
1036 Caller provided function to be invoked at the end of InitializeDebugAgent().
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.
1042 @param[in] Context The first input parameter of InitializeDebugAgent().
1051 EFI_SEC_PEI_HAND_OFF
*SecCoreData
;
1052 EFI_FIRMWARE_VOLUME_HEADER
*BootFv
;
1053 EFI_PEI_CORE_ENTRY_POINT PeiCoreEntryPoint
;
1055 SecCoreData
= (EFI_SEC_PEI_HAND_OFF
*)Context
;
1058 // Find PEI Core entry point. It will report SEC and Pei Core debug information if remote debug
1061 BootFv
= (EFI_FIRMWARE_VOLUME_HEADER
*)SecCoreData
->BootFirmwareVolumeBase
;
1062 FindAndReportEntryPoints (&BootFv
, &PeiCoreEntryPoint
);
1063 SecCoreData
->BootFirmwareVolumeBase
= BootFv
;
1064 SecCoreData
->BootFirmwareVolumeSize
= (UINTN
)BootFv
->FvLength
;
1067 // Transfer the control to the PEI core
1069 (*PeiCoreEntryPoint
)(SecCoreData
, (EFI_PEI_PPI_DESCRIPTOR
*)&mPrivateDispatchTable
);
1072 // If we get here then the PEI Core returned, which is not recoverable.
1080 TemporaryRamMigration (
1081 IN CONST EFI_PEI_SERVICES
**PeiServices
,
1082 IN EFI_PHYSICAL_ADDRESS TemporaryMemoryBase
,
1083 IN EFI_PHYSICAL_ADDRESS PermanentMemoryBase
,
1087 IA32_DESCRIPTOR IdtDescriptor
;
1092 DEBUG_AGENT_CONTEXT_POSTMEM_SEC DebugAgentContext
;
1094 BASE_LIBRARY_JUMP_BUFFER JumpBuffer
;
1098 "TemporaryRamMigration(0x%Lx, 0x%Lx, 0x%Lx)\n",
1099 TemporaryMemoryBase
,
1100 PermanentMemoryBase
,
1104 OldHeap
= (VOID
*)(UINTN
)TemporaryMemoryBase
;
1105 NewHeap
= (VOID
*)((UINTN
)PermanentMemoryBase
+ (CopySize
>> 1));
1107 OldStack
= (VOID
*)((UINTN
)TemporaryMemoryBase
+ (CopySize
>> 1));
1108 NewStack
= (VOID
*)(UINTN
)PermanentMemoryBase
;
1110 DebugAgentContext
.HeapMigrateOffset
= (UINTN
)NewHeap
- (UINTN
)OldHeap
;
1111 DebugAgentContext
.StackMigrateOffset
= (UINTN
)NewStack
- (UINTN
)OldStack
;
1113 OldStatus
= SaveAndSetDebugTimerInterrupt (FALSE
);
1114 InitializeDebugAgent (DEBUG_AGENT_INIT_POSTMEM_SEC
, (VOID
*)&DebugAgentContext
, NULL
);
1119 CopyMem (NewHeap
, OldHeap
, CopySize
>> 1);
1124 CopyMem (NewStack
, OldStack
, CopySize
>> 1);
1127 // Rebase IDT table in permanent memory
1129 AsmReadIdtr (&IdtDescriptor
);
1130 IdtDescriptor
.Base
= IdtDescriptor
.Base
- (UINTN
)OldStack
+ (UINTN
)NewStack
;
1132 AsmWriteIdtr (&IdtDescriptor
);
1135 // Use SetJump()/LongJump() to switch to a new stack.
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
;
1142 #if defined (MDE_CPU_X64)
1143 JumpBuffer
.Rsp
= JumpBuffer
.Rsp
+ DebugAgentContext
.StackMigrateOffset
;
1144 JumpBuffer
.Rbp
= JumpBuffer
.Rbp
+ DebugAgentContext
.StackMigrateOffset
;
1146 LongJump (&JumpBuffer
, (UINTN
)-1);
1149 SaveAndSetDebugTimerInterrupt (OldStatus
);