SEV_ES_INSTRUCTION_DATA *InstructionData\r
);\r
\r
+//\r
+// Per-CPU data mapping structure\r
+//\r
+typedef struct {\r
+ BOOLEAN Dr7Cached;\r
+ UINT64 Dr7;\r
+} SEV_ES_PER_CPU_DATA;\r
\r
-/**\r
- Checks the GHCB to determine if the specified register has been marked valid.\r
-\r
- The ValidBitmap area represents the areas of the GHCB that have been marked\r
- valid. Return an indication of whether the area of the GHCB that holds the\r
- specified register has been marked valid.\r
-\r
- @param[in] Ghcb Pointer to the Guest-Hypervisor Communication Block\r
- @param[in] Reg Offset in the GHCB of the register to check\r
-\r
- @retval TRUE Register has been marked vald in the GHCB\r
- @retval FALSE Register has not been marked valid in the GHCB\r
-\r
-**/\r
-STATIC\r
-BOOLEAN\r
-GhcbIsRegValid (\r
- IN GHCB *Ghcb,\r
- IN GHCB_REGISTER Reg\r
- )\r
-{\r
- UINT32 RegIndex;\r
- UINT32 RegBit;\r
-\r
- RegIndex = Reg / 8;\r
- RegBit = Reg & 0x07;\r
-\r
- return ((Ghcb->SaveArea.ValidBitmap[RegIndex] & (1 << RegBit)) != 0);\r
-}\r
-\r
-/**\r
- Marks a register as valid in the GHCB.\r
-\r
- The ValidBitmap area represents the areas of the GHCB that have been marked\r
- valid. Set the area of the GHCB that holds the specified register as valid.\r
-\r
- @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication Block\r
- @param[in] Reg Offset in the GHCB of the register to mark valid\r
-\r
-**/\r
-STATIC\r
-VOID\r
-GhcbSetRegValid (\r
- IN OUT GHCB *Ghcb,\r
- IN GHCB_REGISTER Reg\r
- )\r
-{\r
- UINT32 RegIndex;\r
- UINT32 RegBit;\r
-\r
- RegIndex = Reg / 8;\r
- RegBit = Reg & 0x07;\r
-\r
- Ghcb->SaveArea.ValidBitmap[RegIndex] |= (1 << RegBit);\r
-}\r
\r
/**\r
Return a pointer to the contents of the specified register.\r
CopyMem (Ghcb->SharedBuffer, &InstructionData->Ext.RegData, Bytes);\r
\r
Ghcb->SaveArea.SwScratch = (UINT64) Ghcb->SharedBuffer;\r
+ VmgSetOffsetValid (Ghcb, GhcbSwScratch);\r
Status = VmgExit (Ghcb, SVM_EXIT_MMIO_WRITE, ExitInfo1, ExitInfo2);\r
if (Status != 0) {\r
return Status;\r
CopyMem (Ghcb->SharedBuffer, InstructionData->Immediate, Bytes);\r
\r
Ghcb->SaveArea.SwScratch = (UINT64) Ghcb->SharedBuffer;\r
+ VmgSetOffsetValid (Ghcb, GhcbSwScratch);\r
Status = VmgExit (Ghcb, SVM_EXIT_MMIO_WRITE, ExitInfo1, ExitInfo2);\r
if (Status != 0) {\r
return Status;\r
ExitInfo2 = Bytes;\r
\r
Ghcb->SaveArea.SwScratch = (UINT64) Ghcb->SharedBuffer;\r
+ VmgSetOffsetValid (Ghcb, GhcbSwScratch);\r
Status = VmgExit (Ghcb, SVM_EXIT_MMIO_READ, ExitInfo1, ExitInfo2);\r
if (Status != 0) {\r
return Status;\r
ExitInfo2 = Bytes;\r
\r
Ghcb->SaveArea.SwScratch = (UINT64) Ghcb->SharedBuffer;\r
+ VmgSetOffsetValid (Ghcb, GhcbSwScratch);\r
Status = VmgExit (Ghcb, SVM_EXIT_MMIO_READ, ExitInfo1, ExitInfo2);\r
if (Status != 0) {\r
return Status;\r
ExitInfo2 = Bytes;\r
\r
Ghcb->SaveArea.SwScratch = (UINT64) Ghcb->SharedBuffer;\r
+ VmgSetOffsetValid (Ghcb, GhcbSwScratch);\r
Status = VmgExit (Ghcb, SVM_EXIT_MMIO_READ, ExitInfo1, ExitInfo2);\r
if (Status != 0) {\r
return Status;\r
return Status;\r
}\r
\r
+/**\r
+ Handle a MWAIT event.\r
+\r
+ Use the VMGEXIT instruction to handle a MWAIT event.\r
+\r
+ @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
+ Block\r
+ @param[in, out] Regs x64 processor context\r
+ @param[in] InstructionData Instruction parsing context\r
+\r
+ @retval 0 Event handled successfully\r
+ @return New exception value to propagate\r
+\r
+**/\r
+STATIC\r
+UINT64\r
+MwaitExit (\r
+ IN OUT GHCB *Ghcb,\r
+ IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
+ IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
+ )\r
+{\r
+ DecodeModRm (Regs, InstructionData);\r
+\r
+ Ghcb->SaveArea.Rax = Regs->Rax;\r
+ VmgSetOffsetValid (Ghcb, GhcbRax);\r
+ Ghcb->SaveArea.Rcx = Regs->Rcx;\r
+ VmgSetOffsetValid (Ghcb, GhcbRcx);\r
+\r
+ return VmgExit (Ghcb, SVM_EXIT_MWAIT, 0, 0);\r
+}\r
+\r
/**\r
Handle a MONITOR event.\r
\r
DecodeModRm (Regs, InstructionData);\r
\r
Ghcb->SaveArea.Rax = Regs->Rax; // Identity mapped, so VA = PA\r
- GhcbSetRegValid (Ghcb, GhcbRax);\r
+ VmgSetOffsetValid (Ghcb, GhcbRax);\r
Ghcb->SaveArea.Rcx = Regs->Rcx;\r
- GhcbSetRegValid (Ghcb, GhcbRcx);\r
+ VmgSetOffsetValid (Ghcb, GhcbRcx);\r
Ghcb->SaveArea.Rdx = Regs->Rdx;\r
- GhcbSetRegValid (Ghcb, GhcbRdx);\r
+ VmgSetOffsetValid (Ghcb, GhcbRdx);\r
\r
return VmgExit (Ghcb, SVM_EXIT_MONITOR, 0, 0);\r
}\r
return Status;\r
}\r
\r
- if (!GhcbIsRegValid (Ghcb, GhcbRax) ||\r
- !GhcbIsRegValid (Ghcb, GhcbRcx) ||\r
- !GhcbIsRegValid (Ghcb, GhcbRdx)) {\r
+ if (!VmgIsOffsetValid (Ghcb, GhcbRax) ||\r
+ !VmgIsOffsetValid (Ghcb, GhcbRcx) ||\r
+ !VmgIsOffsetValid (Ghcb, GhcbRdx)) {\r
return UnsupportedExit (Ghcb, Regs, InstructionData);\r
}\r
Regs->Rax = Ghcb->SaveArea.Rax;\r
DecodeModRm (Regs, InstructionData);\r
\r
Ghcb->SaveArea.Rax = Regs->Rax;\r
- GhcbSetRegValid (Ghcb, GhcbRax);\r
+ VmgSetOffsetValid (Ghcb, GhcbRax);\r
Ghcb->SaveArea.Cpl = (UINT8) (Regs->Cs & 0x3);\r
- GhcbSetRegValid (Ghcb, GhcbCpl);\r
+ VmgSetOffsetValid (Ghcb, GhcbCpl);\r
\r
Status = VmgExit (Ghcb, SVM_EXIT_VMMCALL, 0, 0);\r
if (Status != 0) {\r
return Status;\r
}\r
\r
- if (!GhcbIsRegValid (Ghcb, GhcbRax)) {\r
+ if (!VmgIsOffsetValid (Ghcb, GhcbRax)) {\r
return UnsupportedExit (Ghcb, Regs, InstructionData);\r
}\r
Regs->Rax = Ghcb->SaveArea.Rax;\r
case 0x30: // WRMSR\r
ExitInfo1 = 1;\r
Ghcb->SaveArea.Rax = Regs->Rax;\r
- GhcbSetRegValid (Ghcb, GhcbRax);\r
+ VmgSetOffsetValid (Ghcb, GhcbRax);\r
Ghcb->SaveArea.Rdx = Regs->Rdx;\r
- GhcbSetRegValid (Ghcb, GhcbRdx);\r
+ VmgSetOffsetValid (Ghcb, GhcbRdx);\r
//\r
// fall through\r
//\r
case 0x32: // RDMSR\r
Ghcb->SaveArea.Rcx = Regs->Rcx;\r
- GhcbSetRegValid (Ghcb, GhcbRcx);\r
+ VmgSetOffsetValid (Ghcb, GhcbRcx);\r
break;\r
default:\r
return UnsupportedExit (Ghcb, Regs, InstructionData);\r
}\r
\r
if (ExitInfo1 == 0) {\r
- if (!GhcbIsRegValid (Ghcb, GhcbRax) ||\r
- !GhcbIsRegValid (Ghcb, GhcbRdx)) {\r
+ if (!VmgIsOffsetValid (Ghcb, GhcbRax) ||\r
+ !VmgIsOffsetValid (Ghcb, GhcbRdx)) {\r
return UnsupportedExit (Ghcb, Regs, InstructionData);\r
}\r
Regs->Rax = Ghcb->SaveArea.Rax;\r
}\r
\r
Ghcb->SaveArea.SwScratch = (UINT64) Ghcb->SharedBuffer;\r
+ VmgSetOffsetValid (Ghcb, GhcbSwScratch);\r
Status = VmgExit (Ghcb, SVM_EXIT_IOIO_PROT, ExitInfo1, ExitInfo2);\r
if (Status != 0) {\r
return Status;\r
} else {\r
CopyMem (&Ghcb->SaveArea.Rax, &Regs->Rax, IOIO_DATA_BYTES (ExitInfo1));\r
}\r
- GhcbSetRegValid (Ghcb, GhcbRax);\r
+ VmgSetOffsetValid (Ghcb, GhcbRax);\r
\r
Status = VmgExit (Ghcb, SVM_EXIT_IOIO_PROT, ExitInfo1, 0);\r
if (Status != 0) {\r
}\r
\r
if ((ExitInfo1 & IOIO_TYPE_IN) != 0) {\r
- if (!GhcbIsRegValid (Ghcb, GhcbRax)) {\r
+ if (!VmgIsOffsetValid (Ghcb, GhcbRax)) {\r
return UnsupportedExit (Ghcb, Regs, InstructionData);\r
}\r
CopyMem (&Regs->Rax, &Ghcb->SaveArea.Rax, IOIO_DATA_BYTES (ExitInfo1));\r
UINT64 Status;\r
\r
Ghcb->SaveArea.Rax = Regs->Rax;\r
- GhcbSetRegValid (Ghcb, GhcbRax);\r
+ VmgSetOffsetValid (Ghcb, GhcbRax);\r
Ghcb->SaveArea.Rcx = Regs->Rcx;\r
- GhcbSetRegValid (Ghcb, GhcbRcx);\r
+ VmgSetOffsetValid (Ghcb, GhcbRcx);\r
if (Regs->Rax == CPUID_EXTENDED_STATE) {\r
IA32_CR4 Cr4;\r
\r
Cr4.UintN = AsmReadCr4 ();\r
Ghcb->SaveArea.XCr0 = (Cr4.Bits.OSXSAVE == 1) ? AsmXGetBv (0) : 1;\r
- GhcbSetRegValid (Ghcb, GhcbXCr0);\r
+ VmgSetOffsetValid (Ghcb, GhcbXCr0);\r
}\r
\r
Status = VmgExit (Ghcb, SVM_EXIT_CPUID, 0, 0);\r
return Status;\r
}\r
\r
- if (!GhcbIsRegValid (Ghcb, GhcbRax) ||\r
- !GhcbIsRegValid (Ghcb, GhcbRbx) ||\r
- !GhcbIsRegValid (Ghcb, GhcbRcx) ||\r
- !GhcbIsRegValid (Ghcb, GhcbRdx)) {\r
+ if (!VmgIsOffsetValid (Ghcb, GhcbRax) ||\r
+ !VmgIsOffsetValid (Ghcb, GhcbRbx) ||\r
+ !VmgIsOffsetValid (Ghcb, GhcbRcx) ||\r
+ !VmgIsOffsetValid (Ghcb, GhcbRdx)) {\r
return UnsupportedExit (Ghcb, Regs, InstructionData);\r
}\r
Regs->Rax = Ghcb->SaveArea.Rax;\r
UINT64 Status;\r
\r
Ghcb->SaveArea.Rcx = Regs->Rcx;\r
- GhcbSetRegValid (Ghcb, GhcbRcx);\r
+ VmgSetOffsetValid (Ghcb, GhcbRcx);\r
\r
Status = VmgExit (Ghcb, SVM_EXIT_RDPMC, 0, 0);\r
if (Status != 0) {\r
return Status;\r
}\r
\r
- if (!GhcbIsRegValid (Ghcb, GhcbRax) ||\r
- !GhcbIsRegValid (Ghcb, GhcbRdx)) {\r
+ if (!VmgIsOffsetValid (Ghcb, GhcbRax) ||\r
+ !VmgIsOffsetValid (Ghcb, GhcbRdx)) {\r
return UnsupportedExit (Ghcb, Regs, InstructionData);\r
}\r
Regs->Rax = Ghcb->SaveArea.Rax;\r
return Status;\r
}\r
\r
- if (!GhcbIsRegValid (Ghcb, GhcbRax) ||\r
- !GhcbIsRegValid (Ghcb, GhcbRdx)) {\r
+ if (!VmgIsOffsetValid (Ghcb, GhcbRax) ||\r
+ !VmgIsOffsetValid (Ghcb, GhcbRdx)) {\r
return UnsupportedExit (Ghcb, Regs, InstructionData);\r
}\r
Regs->Rax = Ghcb->SaveArea.Rax;\r
return 0;\r
}\r
\r
+/**\r
+ Handle a DR7 register write event.\r
+\r
+ Use the VMGEXIT instruction to handle a DR7 write event.\r
+\r
+ @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
+ Block\r
+ @param[in, out] Regs x64 processor context\r
+ @param[in] InstructionData Instruction parsing context\r
+\r
+ @retval 0 Event handled successfully\r
+ @return New exception value to propagate\r
+\r
+**/\r
+STATIC\r
+UINT64\r
+Dr7WriteExit (\r
+ IN OUT GHCB *Ghcb,\r
+ IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
+ IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
+ )\r
+{\r
+ SEV_ES_INSTRUCTION_OPCODE_EXT *Ext;\r
+ SEV_ES_PER_CPU_DATA *SevEsData;\r
+ UINT64 *Register;\r
+ UINT64 Status;\r
+\r
+ Ext = &InstructionData->Ext;\r
+ SevEsData = (SEV_ES_PER_CPU_DATA *) (Ghcb + 1);\r
+\r
+ DecodeModRm (Regs, InstructionData);\r
+\r
+ //\r
+ // MOV DRn always treats MOD == 3 no matter how encoded\r
+ //\r
+ Register = GetRegisterPointer (Regs, Ext->ModRm.Rm);\r
+\r
+ //\r
+ // Using a value of 0 for ExitInfo1 means RAX holds the value\r
+ //\r
+ Ghcb->SaveArea.Rax = *Register;\r
+ VmgSetOffsetValid (Ghcb, GhcbRax);\r
+\r
+ Status = VmgExit (Ghcb, SVM_EXIT_DR7_WRITE, 0, 0);\r
+ if (Status != 0) {\r
+ return Status;\r
+ }\r
+\r
+ SevEsData->Dr7 = *Register;\r
+ SevEsData->Dr7Cached = TRUE;\r
+\r
+ return 0;\r
+}\r
+\r
+/**\r
+ Handle a DR7 register read event.\r
+\r
+ Use the VMGEXIT instruction to handle a DR7 read event.\r
+\r
+ @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
+ Block\r
+ @param[in, out] Regs x64 processor context\r
+ @param[in] InstructionData Instruction parsing context\r
+\r
+ @retval 0 Event handled successfully\r
+\r
+**/\r
+STATIC\r
+UINT64\r
+Dr7ReadExit (\r
+ IN OUT GHCB *Ghcb,\r
+ IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
+ IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
+ )\r
+{\r
+ SEV_ES_INSTRUCTION_OPCODE_EXT *Ext;\r
+ SEV_ES_PER_CPU_DATA *SevEsData;\r
+ UINT64 *Register;\r
+\r
+ Ext = &InstructionData->Ext;\r
+ SevEsData = (SEV_ES_PER_CPU_DATA *) (Ghcb + 1);\r
+\r
+ DecodeModRm (Regs, InstructionData);\r
+\r
+ //\r
+ // MOV DRn always treats MOD == 3 no matter how encoded\r
+ //\r
+ Register = GetRegisterPointer (Regs, Ext->ModRm.Rm);\r
+\r
+ //\r
+ // If there is a cached valued for DR7, return that. Otherwise return the\r
+ // DR7 standard reset value of 0x400 (no debug breakpoints set).\r
+ //\r
+ *Register = (SevEsData->Dr7Cached) ? SevEsData->Dr7 : 0x400;\r
+\r
+ return 0;\r
+}\r
+\r
/**\r
Handle a #VC exception.\r
\r
\r
ExitCode = Regs->ExceptionData;\r
switch (ExitCode) {\r
+ case SVM_EXIT_DR7_READ:\r
+ NaeExit = Dr7ReadExit;\r
+ break;\r
+\r
+ case SVM_EXIT_DR7_WRITE:\r
+ NaeExit = Dr7WriteExit;\r
+ break;\r
+\r
case SVM_EXIT_RDTSC:\r
NaeExit = RdtscExit;\r
break;\r
NaeExit = MonitorExit;\r
break;\r
\r
+ case SVM_EXIT_MWAIT:\r
+ NaeExit = MwaitExit;\r
+ break;\r
+\r
case SVM_EXIT_NPF:\r
NaeExit = MmioExit;\r
break;\r