#include <Library/PeCoffExtraActionLib.h>\r
#include <Library/ExtractGuidedSectionLib.h>\r
#include <Library/LocalApicLib.h>\r
+#include <Library/CpuExceptionHandlerLib.h>\r
+#include <Register/Amd/Ghcb.h>\r
+#include <Register/Amd/Msr.h>\r
\r
#include <Ppi/TemporaryRamSupport.h>\r
\r
IA32_IDT_GATE_DESCRIPTOR IdtTable[SEC_IDT_ENTRY_COUNT];\r
} SEC_IDT_TABLE;\r
\r
+typedef struct _SEC_SEV_ES_WORK_AREA {\r
+ UINT8 SevEsEnabled;\r
+} SEC_SEV_ES_WORK_AREA;\r
+\r
VOID\r
EFIAPI\r
SecStartupPhase2 (\r
return;\r
}\r
\r
+/**\r
+ Handle an SEV-ES/GHCB protocol check failure.\r
+\r
+ Notify the hypervisor using the VMGEXIT instruction that the SEV-ES guest\r
+ wishes to be terminated.\r
+\r
+ @param[in] ReasonCode Reason code to provide to the hypervisor for the\r
+ termination request.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+SevEsProtocolFailure (\r
+ IN UINT8 ReasonCode\r
+ )\r
+{\r
+ MSR_SEV_ES_GHCB_REGISTER Msr;\r
+\r
+ //\r
+ // Use the GHCB MSR Protocol to request termination by the hypervisor\r
+ //\r
+ Msr.GhcbPhysicalAddress = 0;\r
+ Msr.GhcbTerminate.Function = GHCB_INFO_TERMINATE_REQUEST;\r
+ Msr.GhcbTerminate.ReasonCodeSet = GHCB_TERMINATE_GHCB;\r
+ Msr.GhcbTerminate.ReasonCode = ReasonCode;\r
+ AsmWriteMsr64 (MSR_SEV_ES_GHCB, Msr.GhcbPhysicalAddress);\r
+\r
+ AsmVmgExit ();\r
+\r
+ ASSERT (FALSE);\r
+ CpuDeadLoop ();\r
+}\r
+\r
+/**\r
+ Validate the SEV-ES/GHCB protocol level.\r
+\r
+ Verify that the level of SEV-ES/GHCB protocol supported by the hypervisor\r
+ and the guest intersect. If they don't intersect, request termination.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+SevEsProtocolCheck (\r
+ VOID\r
+ )\r
+{\r
+ MSR_SEV_ES_GHCB_REGISTER Msr;\r
+ GHCB *Ghcb;\r
+\r
+ //\r
+ // Use the GHCB MSR Protocol to obtain the GHCB SEV-ES Information for\r
+ // protocol checking\r
+ //\r
+ Msr.GhcbPhysicalAddress = 0;\r
+ Msr.GhcbInfo.Function = GHCB_INFO_SEV_INFO_GET;\r
+ AsmWriteMsr64 (MSR_SEV_ES_GHCB, Msr.GhcbPhysicalAddress);\r
+\r
+ AsmVmgExit ();\r
+\r
+ Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);\r
+\r
+ if (Msr.GhcbInfo.Function != GHCB_INFO_SEV_INFO) {\r
+ SevEsProtocolFailure (GHCB_TERMINATE_GHCB_GENERAL);\r
+ }\r
+\r
+ if (Msr.GhcbProtocol.SevEsProtocolMin > Msr.GhcbProtocol.SevEsProtocolMax) {\r
+ SevEsProtocolFailure (GHCB_TERMINATE_GHCB_PROTOCOL);\r
+ }\r
+\r
+ if ((Msr.GhcbProtocol.SevEsProtocolMin > GHCB_VERSION_MAX) ||\r
+ (Msr.GhcbProtocol.SevEsProtocolMax < GHCB_VERSION_MIN)) {\r
+ SevEsProtocolFailure (GHCB_TERMINATE_GHCB_PROTOCOL);\r
+ }\r
+\r
+ //\r
+ // SEV-ES protocol checking succeeded, set the initial GHCB address\r
+ //\r
+ Msr.GhcbPhysicalAddress = FixedPcdGet32 (PcdOvmfSecGhcbBase);\r
+ AsmWriteMsr64 (MSR_SEV_ES_GHCB, Msr.GhcbPhysicalAddress);\r
+\r
+ Ghcb = Msr.Ghcb;\r
+ SetMem (Ghcb, sizeof (*Ghcb), 0);\r
+\r
+ //\r
+ // Set the version to the maximum that can be supported\r
+ //\r
+ Ghcb->ProtocolVersion = MIN (Msr.GhcbProtocol.SevEsProtocolMax, GHCB_VERSION_MAX);\r
+ Ghcb->GhcbUsage = GHCB_STANDARD_USAGE;\r
+}\r
+\r
+/**\r
+ Determine if SEV-ES is active.\r
+\r
+ During early booting, SEV-ES support code will set a flag to indicate that\r
+ SEV-ES is enabled. Return the value of this flag as an indicator that SEV-ES\r
+ is enabled.\r
+\r
+ @retval TRUE SEV-ES is enabled\r
+ @retval FALSE SEV-ES is not enabled\r
+\r
+**/\r
+STATIC\r
+BOOLEAN\r
+SevEsIsEnabled (\r
+ VOID\r
+ )\r
+{\r
+ SEC_SEV_ES_WORK_AREA *SevEsWorkArea;\r
+\r
+ SevEsWorkArea = (SEC_SEV_ES_WORK_AREA *) FixedPcdGet32 (PcdSevEsWorkAreaBase);\r
+\r
+ return ((SevEsWorkArea != NULL) && (SevEsWorkArea->SevEsEnabled != 0));\r
+}\r
+\r
VOID\r
EFIAPI\r
SecCoreStartupWithStack (\r
Table[Index] = 0;\r
}\r
\r
+ //\r
+ // Initialize IDT - Since this is before library constructors are called,\r
+ // we use a loop rather than CopyMem.\r
+ //\r
+ IdtTableInStack.PeiService = NULL;\r
+ for (Index = 0; Index < SEC_IDT_ENTRY_COUNT; Index ++) {\r
+ UINT8 *Src;\r
+ UINT8 *Dst;\r
+ UINTN Byte;\r
+\r
+ Src = (UINT8 *) &mIdtEntryTemplate;\r
+ Dst = (UINT8 *) &IdtTableInStack.IdtTable[Index];\r
+ for (Byte = 0; Byte < sizeof (mIdtEntryTemplate); Byte++) {\r
+ Dst[Byte] = Src[Byte];\r
+ }\r
+ }\r
+\r
+ IdtDescriptor.Base = (UINTN)&IdtTableInStack.IdtTable;\r
+ IdtDescriptor.Limit = (UINT16)(sizeof (IdtTableInStack.IdtTable) - 1);\r
+\r
+ if (SevEsIsEnabled ()) {\r
+ SevEsProtocolCheck ();\r
+\r
+ //\r
+ // For SEV-ES guests, the exception handler is needed before calling\r
+ // ProcessLibraryConstructorList() because some of the library constructors\r
+ // perform some functions that result in #VC exceptions being generated.\r
+ //\r
+ // Due to this code executing before library constructors, *all* library\r
+ // API calls are theoretically interface contract violations. However,\r
+ // because this is SEC (executing in flash), those constructors cannot\r
+ // write variables with static storage duration anyway. Furthermore, only\r
+ // a small, restricted set of APIs, such as AsmWriteIdtr() and\r
+ // InitializeCpuExceptionHandlers(), are called, where we require that the\r
+ // underlying library not require constructors to have been invoked and\r
+ // that the library instance not trigger any #VC exceptions.\r
+ //\r
+ AsmWriteIdtr (&IdtDescriptor);\r
+ InitializeCpuExceptionHandlers (NULL);\r
+ }\r
+\r
ProcessLibraryConstructorList (NULL, NULL);\r
\r
+ if (!SevEsIsEnabled ()) {\r
+ //\r
+ // For non SEV-ES guests, just load the IDTR.\r
+ //\r
+ AsmWriteIdtr (&IdtDescriptor);\r
+ }\r
+\r
DEBUG ((DEBUG_INFO,\r
"SecCoreStartupWithStack(0x%x, 0x%x)\n",\r
(UINT32)(UINTN)BootFv,\r
//\r
InitializeFloatingPointUnits ();\r
\r
- //\r
- // Initialize IDT\r
- //\r
- IdtTableInStack.PeiService = NULL;\r
- for (Index = 0; Index < SEC_IDT_ENTRY_COUNT; Index ++) {\r
- CopyMem (&IdtTableInStack.IdtTable[Index], &mIdtEntryTemplate, sizeof (mIdtEntryTemplate));\r
- }\r
-\r
- IdtDescriptor.Base = (UINTN)&IdtTableInStack.IdtTable;\r
- IdtDescriptor.Limit = (UINT16)(sizeof (IdtTableInStack.IdtTable) - 1);\r
-\r
- AsmWriteIdtr (&IdtDescriptor);\r
-\r
#if defined (MDE_CPU_X64)\r
//\r
// ASSERT that the Page Tables were set by the reset vector code to\r