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
) {
129 Locates a section within a series of sections
130 with the specified section type.
132 The Instance parameter indicates which instance of the section
133 type to return. (0 is first instance, 1 is second...)
135 @param[in] Sections The sections to search
136 @param[in] SizeOfSections Total size of all sections
137 @param[in] SectionType The section type to locate
138 @param[in] Instance The section instance number
139 @param[out] FoundSection The FFS section if found
141 @retval EFI_SUCCESS The file and section was found
142 @retval EFI_NOT_FOUND The file and section was not found
143 @retval EFI_VOLUME_CORRUPTED The firmware volume was corrupted
147 FindFfsSectionInstance (
149 IN UINTN SizeOfSections
,
150 IN EFI_SECTION_TYPE SectionType
,
152 OUT EFI_COMMON_SECTION_HEADER
**FoundSection
155 EFI_PHYSICAL_ADDRESS CurrentAddress
;
157 EFI_PHYSICAL_ADDRESS EndOfSections
;
158 EFI_COMMON_SECTION_HEADER
*Section
;
159 EFI_PHYSICAL_ADDRESS EndOfSection
;
162 // Loop through the FFS file sections within the PEI Core FFS file
164 EndOfSection
= (EFI_PHYSICAL_ADDRESS
)(UINTN
) Sections
;
165 EndOfSections
= EndOfSection
+ SizeOfSections
;
167 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
; ; ) {
276 CurrentAddress
= (EndOfFile
+ 7) & ~(7ULL);
277 if (CurrentAddress
> EndOfFirmwareVolume
) {
278 return EFI_VOLUME_CORRUPTED
;
281 File
= (EFI_FFS_FILE_HEADER
*)(UINTN
) CurrentAddress
;
282 Size
= FFS_FILE_SIZE (File
);
283 if (Size
< (sizeof (*File
) + sizeof (EFI_COMMON_SECTION_HEADER
))) {
284 return EFI_VOLUME_CORRUPTED
;
287 EndOfFile
= CurrentAddress
+ Size
;
288 if (EndOfFile
> EndOfFirmwareVolume
) {
289 return EFI_VOLUME_CORRUPTED
;
293 // Look for the request file type
295 if (File
->Type
!= FileType
) {
299 Status
= FindFfsSectionInSections (
301 (UINTN
) EndOfFile
- (UINTN
) (File
+ 1),
305 if (!EFI_ERROR (Status
) || (Status
== EFI_VOLUME_CORRUPTED
)) {
312 Locates the compressed main firmware volume and decompresses it.
314 @param[in,out] Fv On input, the firmware volume to search
315 On output, the decompressed BOOT/PEI FV
317 @retval EFI_SUCCESS The file and section was found
318 @retval EFI_NOT_FOUND The file and section was not found
319 @retval EFI_VOLUME_CORRUPTED The firmware volume was corrupted
324 IN OUT EFI_FIRMWARE_VOLUME_HEADER
**Fv
328 EFI_GUID_DEFINED_SECTION
*Section
;
329 UINT32 OutputBufferSize
;
330 UINT32 ScratchBufferSize
;
331 UINT16 SectionAttribute
;
332 UINT32 AuthenticationStatus
;
335 EFI_COMMON_SECTION_HEADER
*FvSection
;
336 EFI_FIRMWARE_VOLUME_HEADER
*PeiMemFv
;
337 EFI_FIRMWARE_VOLUME_HEADER
*DxeMemFv
;
339 UINT32 FvSectionSize
;
341 FvSection
= (EFI_COMMON_SECTION_HEADER
*) NULL
;
343 Status
= FindFfsFileAndSection (
345 EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE
,
346 EFI_SECTION_GUID_DEFINED
,
347 (EFI_COMMON_SECTION_HEADER
**) &Section
349 if (EFI_ERROR (Status
)) {
350 DEBUG ((DEBUG_ERROR
, "Unable to find GUID defined section\n"));
354 Status
= ExtractGuidedSectionGetInfo (
360 if (EFI_ERROR (Status
)) {
361 DEBUG ((DEBUG_ERROR
, "Unable to GetInfo for GUIDed section\n"));
365 OutputBuffer
= (VOID
*) ((UINT8
*)(UINTN
) PcdGet32 (PcdOvmfDxeMemFvBase
) + SIZE_1MB
);
366 ScratchBuffer
= ALIGN_POINTER ((UINT8
*) OutputBuffer
+ OutputBufferSize
, SIZE_1MB
);
368 DEBUG ((DEBUG_VERBOSE
, "%a: OutputBuffer@%p+0x%x ScratchBuffer@%p+0x%x "
369 "PcdOvmfDecompressionScratchEnd=0x%x\n", __FUNCTION__
, OutputBuffer
,
370 OutputBufferSize
, ScratchBuffer
, ScratchBufferSize
,
371 PcdGet32 (PcdOvmfDecompressionScratchEnd
)));
372 ASSERT ((UINTN
)ScratchBuffer
+ ScratchBufferSize
==
373 PcdGet32 (PcdOvmfDecompressionScratchEnd
));
375 Status
= ExtractGuidedSectionDecode (
379 &AuthenticationStatus
381 if (EFI_ERROR (Status
)) {
382 DEBUG ((DEBUG_ERROR
, "Error during GUID section decode\n"));
386 Status
= FindFfsSectionInstance (
389 EFI_SECTION_FIRMWARE_VOLUME_IMAGE
,
393 if (EFI_ERROR (Status
)) {
394 DEBUG ((DEBUG_ERROR
, "Unable to find PEI FV section\n"));
398 ASSERT (SECTION_SIZE (FvSection
) ==
399 (PcdGet32 (PcdOvmfPeiMemFvSize
) + sizeof (*FvSection
)));
400 ASSERT (FvSection
->Type
== EFI_SECTION_FIRMWARE_VOLUME_IMAGE
);
402 PeiMemFv
= (EFI_FIRMWARE_VOLUME_HEADER
*)(UINTN
) PcdGet32 (PcdOvmfPeiMemFvBase
);
403 CopyMem (PeiMemFv
, (VOID
*) (FvSection
+ 1), PcdGet32 (PcdOvmfPeiMemFvSize
));
405 if (PeiMemFv
->Signature
!= EFI_FVH_SIGNATURE
) {
406 DEBUG ((DEBUG_ERROR
, "Extracted FV at %p does not have FV header signature\n", PeiMemFv
));
408 return EFI_VOLUME_CORRUPTED
;
411 Status
= FindFfsSectionInstance (
414 EFI_SECTION_FIRMWARE_VOLUME_IMAGE
,
418 if (EFI_ERROR (Status
)) {
419 DEBUG ((DEBUG_ERROR
, "Unable to find DXE FV section\n"));
423 ASSERT (FvSection
->Type
== EFI_SECTION_FIRMWARE_VOLUME_IMAGE
);
425 if (IS_SECTION2 (FvSection
)) {
426 FvSectionSize
= SECTION2_SIZE (FvSection
);
427 FvHeaderSize
= sizeof (EFI_COMMON_SECTION_HEADER2
);
429 FvSectionSize
= SECTION_SIZE (FvSection
);
430 FvHeaderSize
= sizeof (EFI_COMMON_SECTION_HEADER
);
433 ASSERT (FvSectionSize
== (PcdGet32 (PcdOvmfDxeMemFvSize
) + FvHeaderSize
));
435 DxeMemFv
= (EFI_FIRMWARE_VOLUME_HEADER
*)(UINTN
) PcdGet32 (PcdOvmfDxeMemFvBase
);
436 CopyMem (DxeMemFv
, (VOID
*) ((UINTN
)FvSection
+ FvHeaderSize
), PcdGet32 (PcdOvmfDxeMemFvSize
));
438 if (DxeMemFv
->Signature
!= EFI_FVH_SIGNATURE
) {
439 DEBUG ((DEBUG_ERROR
, "Extracted FV at %p does not have FV header signature\n", DxeMemFv
));
441 return EFI_VOLUME_CORRUPTED
;
449 Locates the PEI Core entry point address
451 @param[in] Fv The firmware volume to search
452 @param[out] PeiCoreEntryPoint The entry point of the PEI Core image
454 @retval EFI_SUCCESS The file and section was found
455 @retval EFI_NOT_FOUND The file and section was not found
456 @retval EFI_VOLUME_CORRUPTED The firmware volume was corrupted
460 FindPeiCoreImageBaseInFv (
461 IN EFI_FIRMWARE_VOLUME_HEADER
*Fv
,
462 OUT EFI_PHYSICAL_ADDRESS
*PeiCoreImageBase
466 EFI_COMMON_SECTION_HEADER
*Section
;
468 Status
= FindFfsFileAndSection (
470 EFI_FV_FILETYPE_PEI_CORE
,
474 if (EFI_ERROR (Status
)) {
475 Status
= FindFfsFileAndSection (
477 EFI_FV_FILETYPE_PEI_CORE
,
481 if (EFI_ERROR (Status
)) {
482 DEBUG ((DEBUG_ERROR
, "Unable to find PEI Core image\n"));
487 *PeiCoreImageBase
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)(Section
+ 1);
493 Reads 8-bits of CMOS data.
495 Reads the 8-bits of CMOS data at the location specified by Index.
496 The 8-bit read value is returned.
498 @param Index The CMOS location to read.
500 @return The value read.
509 IoWrite8 (0x70, (UINT8
) Index
);
510 return IoRead8 (0x71);
520 return (CmosRead8 (0xF) == 0xFE);
527 IN OUT EFI_FIRMWARE_VOLUME_HEADER
**PeiFv
530 *PeiFv
= (EFI_FIRMWARE_VOLUME_HEADER
*)(UINTN
) PcdGet32 (PcdOvmfPeiMemFvBase
);
536 Locates the PEI Core entry point address
538 @param[in,out] Fv The firmware volume to search
539 @param[out] PeiCoreEntryPoint The entry point of the PEI Core image
541 @retval EFI_SUCCESS The file and section was found
542 @retval EFI_NOT_FOUND The file and section was not found
543 @retval EFI_VOLUME_CORRUPTED The firmware volume was corrupted
547 FindPeiCoreImageBase (
548 IN OUT EFI_FIRMWARE_VOLUME_HEADER
**BootFv
,
549 OUT EFI_PHYSICAL_ADDRESS
*PeiCoreImageBase
554 *PeiCoreImageBase
= 0;
556 S3Resume
= IsS3Resume ();
557 if (S3Resume
&& !FeaturePcdGet (PcdSmmSmramRequire
)) {
559 // A malicious runtime OS may have injected something into our previously
560 // decoded PEI FV, but we don't care about that unless SMM/SMRAM is required.
562 DEBUG ((DEBUG_VERBOSE
, "SEC: S3 resume\n"));
563 GetS3ResumePeiFv (BootFv
);
566 // We're either not resuming, or resuming "securely" -- we'll decompress
567 // both PEI FV and DXE FV from pristine flash.
569 DEBUG ((DEBUG_VERBOSE
, "SEC: %a\n",
570 S3Resume
? "S3 resume (with PEI decompression)" : "Normal boot"));
573 DecompressMemFvs (BootFv
);
576 FindPeiCoreImageBaseInFv (*BootFv
, PeiCoreImageBase
);
580 Find core image base.
585 IN EFI_FIRMWARE_VOLUME_HEADER
*BootFirmwareVolumePtr
,
586 OUT EFI_PHYSICAL_ADDRESS
*SecCoreImageBase
589 EFI_PHYSICAL_ADDRESS CurrentAddress
;
590 EFI_PHYSICAL_ADDRESS EndOfFirmwareVolume
;
591 EFI_FFS_FILE_HEADER
*File
;
593 EFI_PHYSICAL_ADDRESS EndOfFile
;
594 EFI_COMMON_SECTION_HEADER
*Section
;
595 EFI_PHYSICAL_ADDRESS EndOfSection
;
597 *SecCoreImageBase
= 0;
599 CurrentAddress
= (EFI_PHYSICAL_ADDRESS
)(UINTN
) BootFirmwareVolumePtr
;
600 EndOfFirmwareVolume
= CurrentAddress
+ BootFirmwareVolumePtr
->FvLength
;
603 // Loop through the FFS files in the Boot Firmware Volume
605 for (EndOfFile
= CurrentAddress
+ BootFirmwareVolumePtr
->HeaderLength
; ; ) {
607 CurrentAddress
= (EndOfFile
+ 7) & 0xfffffffffffffff8ULL
;
608 if (CurrentAddress
> EndOfFirmwareVolume
) {
609 return EFI_NOT_FOUND
;
612 File
= (EFI_FFS_FILE_HEADER
*)(UINTN
) CurrentAddress
;
613 Size
= FFS_FILE_SIZE (File
);
614 if (Size
< sizeof (*File
)) {
615 return EFI_NOT_FOUND
;
618 EndOfFile
= CurrentAddress
+ Size
;
619 if (EndOfFile
> EndOfFirmwareVolume
) {
620 return EFI_NOT_FOUND
;
626 if (File
->Type
!= EFI_FV_FILETYPE_SECURITY_CORE
) {
631 // Loop through the FFS file sections within the FFS file
633 EndOfSection
= (EFI_PHYSICAL_ADDRESS
)(UINTN
) (File
+ 1);
635 CurrentAddress
= (EndOfSection
+ 3) & 0xfffffffffffffffcULL
;
636 Section
= (EFI_COMMON_SECTION_HEADER
*)(UINTN
) CurrentAddress
;
638 Size
= SECTION_SIZE (Section
);
639 if (Size
< sizeof (*Section
)) {
640 return EFI_NOT_FOUND
;
643 EndOfSection
= CurrentAddress
+ Size
;
644 if (EndOfSection
> EndOfFile
) {
645 return EFI_NOT_FOUND
;
649 // Look for executable sections
651 if (Section
->Type
== EFI_SECTION_PE32
|| Section
->Type
== EFI_SECTION_TE
) {
652 if (File
->Type
== EFI_FV_FILETYPE_SECURITY_CORE
) {
653 *SecCoreImageBase
= (PHYSICAL_ADDRESS
) (UINTN
) (Section
+ 1);
660 // SEC Core image found
662 if (*SecCoreImageBase
!= 0) {
669 Find and return Pei Core entry point.
671 It also find SEC and PEI Core file debug information. It will report them if
672 remote debug is enabled.
676 FindAndReportEntryPoints (
677 IN EFI_FIRMWARE_VOLUME_HEADER
**BootFirmwareVolumePtr
,
678 OUT EFI_PEI_CORE_ENTRY_POINT
*PeiCoreEntryPoint
682 EFI_PHYSICAL_ADDRESS SecCoreImageBase
;
683 EFI_PHYSICAL_ADDRESS PeiCoreImageBase
;
684 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext
;
687 // Find SEC Core and PEI Core image base
689 Status
= FindImageBase (*BootFirmwareVolumePtr
, &SecCoreImageBase
);
690 ASSERT_EFI_ERROR (Status
);
692 FindPeiCoreImageBase (BootFirmwareVolumePtr
, &PeiCoreImageBase
);
694 ZeroMem ((VOID
*) &ImageContext
, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT
));
696 // Report SEC Core debug information when remote debug is enabled
698 ImageContext
.ImageAddress
= SecCoreImageBase
;
699 ImageContext
.PdbPointer
= PeCoffLoaderGetPdbPointer ((VOID
*) (UINTN
) ImageContext
.ImageAddress
);
700 PeCoffLoaderRelocateImageExtraAction (&ImageContext
);
703 // Report PEI Core debug information when remote debug is enabled
705 ImageContext
.ImageAddress
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)PeiCoreImageBase
;
706 ImageContext
.PdbPointer
= PeCoffLoaderGetPdbPointer ((VOID
*) (UINTN
) ImageContext
.ImageAddress
);
707 PeCoffLoaderRelocateImageExtraAction (&ImageContext
);
710 // Find PEI Core entry point
712 Status
= PeCoffLoaderGetEntryPoint ((VOID
*) (UINTN
) PeiCoreImageBase
, (VOID
**) PeiCoreEntryPoint
);
713 if (EFI_ERROR (Status
)) {
714 *PeiCoreEntryPoint
= 0;
721 Handle an SEV-ES/GHCB protocol check failure.
723 Notify the hypervisor using the VMGEXIT instruction that the SEV-ES guest
724 wishes to be terminated.
726 @param[in] ReasonCode Reason code to provide to the hypervisor for the
732 SevEsProtocolFailure (
736 MSR_SEV_ES_GHCB_REGISTER Msr
;
739 // Use the GHCB MSR Protocol to request termination by the hypervisor
741 Msr
.GhcbPhysicalAddress
= 0;
742 Msr
.GhcbTerminate
.Function
= GHCB_INFO_TERMINATE_REQUEST
;
743 Msr
.GhcbTerminate
.ReasonCodeSet
= GHCB_TERMINATE_GHCB
;
744 Msr
.GhcbTerminate
.ReasonCode
= ReasonCode
;
745 AsmWriteMsr64 (MSR_SEV_ES_GHCB
, Msr
.GhcbPhysicalAddress
);
754 Validate the SEV-ES/GHCB protocol level.
756 Verify that the level of SEV-ES/GHCB protocol supported by the hypervisor
757 and the guest intersect. If they don't intersect, request termination.
766 MSR_SEV_ES_GHCB_REGISTER Msr
;
770 // Use the GHCB MSR Protocol to obtain the GHCB SEV-ES Information for
773 Msr
.GhcbPhysicalAddress
= 0;
774 Msr
.GhcbInfo
.Function
= GHCB_INFO_SEV_INFO_GET
;
775 AsmWriteMsr64 (MSR_SEV_ES_GHCB
, Msr
.GhcbPhysicalAddress
);
779 Msr
.GhcbPhysicalAddress
= AsmReadMsr64 (MSR_SEV_ES_GHCB
);
781 if (Msr
.GhcbInfo
.Function
!= GHCB_INFO_SEV_INFO
) {
782 SevEsProtocolFailure (GHCB_TERMINATE_GHCB_GENERAL
);
785 if (Msr
.GhcbProtocol
.SevEsProtocolMin
> Msr
.GhcbProtocol
.SevEsProtocolMax
) {
786 SevEsProtocolFailure (GHCB_TERMINATE_GHCB_PROTOCOL
);
789 if ((Msr
.GhcbProtocol
.SevEsProtocolMin
> GHCB_VERSION_MAX
) ||
790 (Msr
.GhcbProtocol
.SevEsProtocolMax
< GHCB_VERSION_MIN
)) {
791 SevEsProtocolFailure (GHCB_TERMINATE_GHCB_PROTOCOL
);
795 // SEV-ES protocol checking succeeded, set the initial GHCB address
797 Msr
.GhcbPhysicalAddress
= FixedPcdGet32 (PcdOvmfSecGhcbBase
);
798 AsmWriteMsr64 (MSR_SEV_ES_GHCB
, Msr
.GhcbPhysicalAddress
);
801 SetMem (Ghcb
, sizeof (*Ghcb
), 0);
804 // Set the version to the maximum that can be supported
806 Ghcb
->ProtocolVersion
= MIN (Msr
.GhcbProtocol
.SevEsProtocolMax
, GHCB_VERSION_MAX
);
807 Ghcb
->GhcbUsage
= GHCB_STANDARD_USAGE
;
811 Determine if SEV-ES is active.
813 During early booting, SEV-ES support code will set a flag to indicate that
814 SEV-ES is enabled. Return the value of this flag as an indicator that SEV-ES
817 @retval TRUE SEV-ES is enabled
818 @retval FALSE SEV-ES is not enabled
827 SEC_SEV_ES_WORK_AREA
*SevEsWorkArea
;
829 SevEsWorkArea
= (SEC_SEV_ES_WORK_AREA
*) FixedPcdGet32 (PcdSevEsWorkAreaBase
);
831 return ((SevEsWorkArea
!= NULL
) && (SevEsWorkArea
->SevEsEnabled
!= 0));
836 SecCoreStartupWithStack (
837 IN EFI_FIRMWARE_VOLUME_HEADER
*BootFv
,
838 IN VOID
*TopOfCurrentStack
841 EFI_SEC_PEI_HAND_OFF SecCoreData
;
842 SEC_IDT_TABLE IdtTableInStack
;
843 IA32_DESCRIPTOR IdtDescriptor
;
845 volatile UINT8
*Table
;
848 // To ensure SMM can't be compromised on S3 resume, we must force re-init of
849 // the BaseExtractGuidedSectionLib. Since this is before library contructors
850 // are called, we must use a loop rather than SetMem.
852 Table
= (UINT8
*)(UINTN
)FixedPcdGet64 (PcdGuidedExtractHandlerTableAddress
);
854 Index
< FixedPcdGet32 (PcdGuidedExtractHandlerTableSize
);
860 // Initialize IDT - Since this is before library constructors are called,
861 // we use a loop rather than CopyMem.
863 IdtTableInStack
.PeiService
= NULL
;
864 for (Index
= 0; Index
< SEC_IDT_ENTRY_COUNT
; Index
++) {
869 Src
= (UINT8
*) &mIdtEntryTemplate
;
870 Dst
= (UINT8
*) &IdtTableInStack
.IdtTable
[Index
];
871 for (Byte
= 0; Byte
< sizeof (mIdtEntryTemplate
); Byte
++) {
872 Dst
[Byte
] = Src
[Byte
];
876 IdtDescriptor
.Base
= (UINTN
)&IdtTableInStack
.IdtTable
;
877 IdtDescriptor
.Limit
= (UINT16
)(sizeof (IdtTableInStack
.IdtTable
) - 1);
879 if (SevEsIsEnabled ()) {
880 SevEsProtocolCheck ();
883 // For SEV-ES guests, the exception handler is needed before calling
884 // ProcessLibraryConstructorList() because some of the library constructors
885 // perform some functions that result in #VC exceptions being generated.
887 // Due to this code executing before library constructors, *all* library
888 // API calls are theoretically interface contract violations. However,
889 // because this is SEC (executing in flash), those constructors cannot
890 // write variables with static storage duration anyway. Furthermore, only
891 // a small, restricted set of APIs, such as AsmWriteIdtr() and
892 // InitializeCpuExceptionHandlers(), are called, where we require that the
893 // underlying library not require constructors to have been invoked and
894 // that the library instance not trigger any #VC exceptions.
896 AsmWriteIdtr (&IdtDescriptor
);
897 InitializeCpuExceptionHandlers (NULL
);
900 ProcessLibraryConstructorList (NULL
, NULL
);
902 if (!SevEsIsEnabled ()) {
904 // For non SEV-ES guests, just load the IDTR.
906 AsmWriteIdtr (&IdtDescriptor
);
909 // Under SEV-ES, the hypervisor can't modify CR0 and so can't enable
910 // caching in order to speed up the boot. Enable caching early for
917 "SecCoreStartupWithStack(0x%x, 0x%x)\n",
918 (UINT32
)(UINTN
)BootFv
,
919 (UINT32
)(UINTN
)TopOfCurrentStack
923 // Initialize floating point operating environment
924 // to be compliant with UEFI spec.
926 InitializeFloatingPointUnits ();
928 #if defined (MDE_CPU_X64)
930 // ASSERT that the Page Tables were set by the reset vector code to
931 // the address we expect.
933 ASSERT (AsmReadCr3 () == (UINTN
) PcdGet32 (PcdOvmfSecPageTablesBase
));
937 // |-------------| <-- TopOfCurrentStack
941 // |-------------| <-- SecCoreData.TemporaryRamBase
944 ASSERT ((UINTN
) (PcdGet32 (PcdOvmfSecPeiTempRamBase
) +
945 PcdGet32 (PcdOvmfSecPeiTempRamSize
)) ==
946 (UINTN
) TopOfCurrentStack
);
949 // Initialize SEC hand-off state
951 SecCoreData
.DataSize
= sizeof(EFI_SEC_PEI_HAND_OFF
);
953 SecCoreData
.TemporaryRamSize
= (UINTN
) PcdGet32 (PcdOvmfSecPeiTempRamSize
);
954 SecCoreData
.TemporaryRamBase
= (VOID
*)((UINT8
*)TopOfCurrentStack
- SecCoreData
.TemporaryRamSize
);
956 SecCoreData
.PeiTemporaryRamBase
= SecCoreData
.TemporaryRamBase
;
957 SecCoreData
.PeiTemporaryRamSize
= SecCoreData
.TemporaryRamSize
>> 1;
959 SecCoreData
.StackBase
= (UINT8
*)SecCoreData
.TemporaryRamBase
+ SecCoreData
.PeiTemporaryRamSize
;
960 SecCoreData
.StackSize
= SecCoreData
.TemporaryRamSize
>> 1;
962 SecCoreData
.BootFirmwareVolumeBase
= BootFv
;
963 SecCoreData
.BootFirmwareVolumeSize
= (UINTN
) BootFv
->FvLength
;
966 // Make sure the 8259 is masked before initializing the Debug Agent and the debug timer is enabled
968 IoWrite8 (0x21, 0xff);
969 IoWrite8 (0xA1, 0xff);
972 // Initialize Local APIC Timer hardware and disable Local APIC Timer
973 // interrupts before initializing the Debug Agent and the debug timer is
976 InitializeApicTimer (0, MAX_UINT32
, TRUE
, 5);
977 DisableApicTimerInterrupt ();
980 // Initialize Debug Agent to support source level debug in SEC/PEI phases before memory ready.
982 InitializeDebugAgent (DEBUG_AGENT_INIT_PREMEM_SEC
, &SecCoreData
, SecStartupPhase2
);
986 Caller provided function to be invoked at the end of InitializeDebugAgent().
988 Entry point to the C language phase of SEC. After the SEC assembly
989 code has initialized some temporary memory and set up the stack,
990 the control is transferred to this function.
992 @param[in] Context The first input parameter of InitializeDebugAgent().
1001 EFI_SEC_PEI_HAND_OFF
*SecCoreData
;
1002 EFI_FIRMWARE_VOLUME_HEADER
*BootFv
;
1003 EFI_PEI_CORE_ENTRY_POINT PeiCoreEntryPoint
;
1005 SecCoreData
= (EFI_SEC_PEI_HAND_OFF
*) Context
;
1008 // Find PEI Core entry point. It will report SEC and Pei Core debug information if remote debug
1011 BootFv
= (EFI_FIRMWARE_VOLUME_HEADER
*)SecCoreData
->BootFirmwareVolumeBase
;
1012 FindAndReportEntryPoints (&BootFv
, &PeiCoreEntryPoint
);
1013 SecCoreData
->BootFirmwareVolumeBase
= BootFv
;
1014 SecCoreData
->BootFirmwareVolumeSize
= (UINTN
) BootFv
->FvLength
;
1017 // Transfer the control to the PEI core
1019 (*PeiCoreEntryPoint
) (SecCoreData
, (EFI_PEI_PPI_DESCRIPTOR
*)&mPrivateDispatchTable
);
1022 // If we get here then the PEI Core returned, which is not recoverable.
1030 TemporaryRamMigration (
1031 IN CONST EFI_PEI_SERVICES
**PeiServices
,
1032 IN EFI_PHYSICAL_ADDRESS TemporaryMemoryBase
,
1033 IN EFI_PHYSICAL_ADDRESS PermanentMemoryBase
,
1037 IA32_DESCRIPTOR IdtDescriptor
;
1042 DEBUG_AGENT_CONTEXT_POSTMEM_SEC DebugAgentContext
;
1044 BASE_LIBRARY_JUMP_BUFFER JumpBuffer
;
1047 "TemporaryRamMigration(0x%Lx, 0x%Lx, 0x%Lx)\n",
1048 TemporaryMemoryBase
,
1049 PermanentMemoryBase
,
1053 OldHeap
= (VOID
*)(UINTN
)TemporaryMemoryBase
;
1054 NewHeap
= (VOID
*)((UINTN
)PermanentMemoryBase
+ (CopySize
>> 1));
1056 OldStack
= (VOID
*)((UINTN
)TemporaryMemoryBase
+ (CopySize
>> 1));
1057 NewStack
= (VOID
*)(UINTN
)PermanentMemoryBase
;
1059 DebugAgentContext
.HeapMigrateOffset
= (UINTN
)NewHeap
- (UINTN
)OldHeap
;
1060 DebugAgentContext
.StackMigrateOffset
= (UINTN
)NewStack
- (UINTN
)OldStack
;
1062 OldStatus
= SaveAndSetDebugTimerInterrupt (FALSE
);
1063 InitializeDebugAgent (DEBUG_AGENT_INIT_POSTMEM_SEC
, (VOID
*) &DebugAgentContext
, NULL
);
1068 CopyMem (NewHeap
, OldHeap
, CopySize
>> 1);
1073 CopyMem (NewStack
, OldStack
, CopySize
>> 1);
1076 // Rebase IDT table in permanent memory
1078 AsmReadIdtr (&IdtDescriptor
);
1079 IdtDescriptor
.Base
= IdtDescriptor
.Base
- (UINTN
)OldStack
+ (UINTN
)NewStack
;
1081 AsmWriteIdtr (&IdtDescriptor
);
1084 // Use SetJump()/LongJump() to switch to a new stack.
1086 if (SetJump (&JumpBuffer
) == 0) {
1087 #if defined (MDE_CPU_IA32)
1088 JumpBuffer
.Esp
= JumpBuffer
.Esp
+ DebugAgentContext
.StackMigrateOffset
;
1089 JumpBuffer
.Ebp
= JumpBuffer
.Ebp
+ DebugAgentContext
.StackMigrateOffset
;
1091 #if defined (MDE_CPU_X64)
1092 JumpBuffer
.Rsp
= JumpBuffer
.Rsp
+ DebugAgentContext
.StackMigrateOffset
;
1093 JumpBuffer
.Rbp
= JumpBuffer
.Rbp
+ DebugAgentContext
.StackMigrateOffset
;
1095 LongJump (&JumpBuffer
, (UINTN
)-1);
1098 SaveAndSetDebugTimerInterrupt (OldStatus
);