\r
MpInitLibSevEsAPReset (Ghcb, CpuMpData);\r
}\r
+\r
+/**\r
+ The function fills the exchange data for the AP.\r
+\r
+ @param[in] ExchangeInfo The pointer to CPU Exchange Data structure\r
+**/\r
+VOID\r
+FillExchangeInfoDataSevEs (\r
+ IN volatile MP_CPU_EXCHANGE_INFO *ExchangeInfo\r
+ )\r
+{\r
+ UINT32 StdRangeMax;\r
+\r
+ AsmCpuid (CPUID_SIGNATURE, &StdRangeMax, NULL, NULL, NULL);\r
+ if (StdRangeMax >= CPUID_EXTENDED_TOPOLOGY) {\r
+ CPUID_EXTENDED_TOPOLOGY_EBX ExtTopoEbx;\r
+\r
+ AsmCpuid (CPUID_EXTENDED_TOPOLOGY, NULL, &ExtTopoEbx.Uint32, NULL, NULL);\r
+ ExchangeInfo->ExtTopoAvail = !!ExtTopoEbx.Bits.LogicalProcessors;\r
+ }\r
+}\r
.SevEsIsEnabled: CTYPE_BOOLEAN 1\r
.SevSnpIsEnabled CTYPE_BOOLEAN 1\r
.GhcbBase: CTYPE_UINTN 1\r
+ .ExtTopoAvail: CTYPE_BOOLEAN 1\r
endstruc\r
\r
MP_CPU_EXCHANGE_INFO_OFFSET equ (SwitchToRealProcEnd - RendezvousFunnelProcStart)\r
ExchangeInfo->SevSnpIsEnabled = CpuMpData->SevSnpIsEnabled;\r
ExchangeInfo->GhcbBase = (UINTN)CpuMpData->GhcbBase;\r
\r
+ //\r
+ // Populate SEV-ES specific exchange data.\r
+ //\r
+ if (ExchangeInfo->SevSnpIsEnabled) {\r
+ FillExchangeInfoDataSevEs (ExchangeInfo);\r
+ }\r
+\r
//\r
// Get the BSP's data of GDT and IDT\r
//\r
BOOLEAN SevEsIsEnabled;\r
BOOLEAN SevSnpIsEnabled;\r
UINTN GhcbBase;\r
+ BOOLEAN ExtTopoAvail;\r
} MP_CPU_EXCHANGE_INFO;\r
\r
#pragma pack()\r
CONFIDENTIAL_COMPUTING_GUEST_ATTR Attr\r
);\r
\r
+/**\r
+ The function fills the exchange data for the AP.\r
+\r
+ @param[in] ExchangeInfo The pointer to CPU Exchange Data structure\r
+**/\r
+VOID\r
+FillExchangeInfoDataSevEs (\r
+ IN volatile MP_CPU_EXCHANGE_INFO *ExchangeInfo\r
+ );\r
+\r
#endif\r
or rax, rdx\r
mov rdi, rax ; RDI now holds the original GHCB GPA\r
\r
+ ;\r
+ ; For SEV-SNP, the recommended handling for getting the x2APIC ID\r
+ ; would be to use the SNP CPUID table to fetch CPUID.00H:EAX and\r
+ ; CPUID:0BH:EBX[15:0] instead of the GHCB MSR protocol vmgexits\r
+ ; below.\r
+ ;\r
+ ; To avoid the unecessary ugliness to accomplish that here, the BSP\r
+ ; has performed these checks in advance (where #VC handler handles\r
+ ; the CPUID table lookups automatically) and cached them in a flag\r
+ ; so those checks can be skipped here.\r
+ ;\r
+ mov eax, [esi + MP_CPU_EXCHANGE_INFO_FIELD (SevSnpIsEnabled)]\r
+ cmp al, 1\r
+ jne CheckExtTopoAvail\r
+\r
+ ;\r
+ ; Even with SEV-SNP, the actual x2APIC ID in CPUID.0BH:EDX\r
+ ; fetched from the hypervisor the same way SEV-ES does it.\r
+ ;\r
+ mov eax, [esi + MP_CPU_EXCHANGE_INFO_FIELD (ExtTopoAvail)]\r
+ cmp al, 1\r
+ je GetApicIdSevEs\r
+ ; The 8-bit APIC ID fallback is also the same as with SEV-ES\r
+ jmp NoX2ApicSevEs\r
+\r
+CheckExtTopoAvail:\r
mov rdx, 0 ; CPUID function 0\r
mov rax, 0 ; RAX register requested\r
or rax, 4\r
test edx, 0ffffh\r
jz NoX2ApicSevEs ; CPUID.0BH:EBX[15:0] is zero\r
\r
+GetApicIdSevEs:\r
mov rdx, 0bh ; CPUID function 0x0b\r
mov rax, 0c0000000h ; RDX register requested\r
or rax, 4\r