TianoCore EDK2 master
AmdSev.c
Go to the documentation of this file.
1
10#include "MpLib.h"
11#include <Library/VmgExitLib.h>
12
20UINT16
22 VOID
23 )
24{
25 IA32_DESCRIPTOR GdtrDesc;
26 IA32_SEGMENT_DESCRIPTOR *GdtEntry;
27 UINTN GdtEntryCount;
28 UINT16 Index;
29
30 Index = (UINT16)-1;
31 AsmReadGdtr (&GdtrDesc);
32 GdtEntryCount = (GdtrDesc.Limit + 1) / sizeof (IA32_SEGMENT_DESCRIPTOR);
33 GdtEntry = (IA32_SEGMENT_DESCRIPTOR *)GdtrDesc.Base;
34 for (Index = 0; Index < GdtEntryCount; Index++) {
35 if ((GdtEntry->Bits.L == 0) &&
36 (GdtEntry->Bits.DB == 0) &&
37 (GdtEntry->Bits.Type > 8))
38 {
39 break;
40 }
41
42 GdtEntry++;
43 }
44
45 ASSERT (Index != GdtEntryCount);
46 return Index * 8;
47}
48
56UINT16
58 VOID
59 )
60{
61 IA32_DESCRIPTOR GdtrDesc;
62 IA32_SEGMENT_DESCRIPTOR *GdtEntry;
63 UINTN GdtEntryCount;
64 UINT16 Index;
65
66 Index = (UINT16)-1;
67 AsmReadGdtr (&GdtrDesc);
68 GdtEntryCount = (GdtrDesc.Limit + 1) / sizeof (IA32_SEGMENT_DESCRIPTOR);
69 GdtEntry = (IA32_SEGMENT_DESCRIPTOR *)GdtrDesc.Base;
70 for (Index = 0; Index < GdtEntryCount; Index++) {
71 if ((GdtEntry->Bits.L == 0) &&
72 (GdtEntry->Bits.DB == 1) &&
73 (GdtEntry->Bits.Type > 8))
74 {
75 break;
76 }
77
78 GdtEntry++;
79 }
80
81 ASSERT (Index != GdtEntryCount);
82 return Index * 8;
83}
84
94VOID
96 IN GHCB *Ghcb,
97 IN CPU_MP_DATA *CpuMpData
98 )
99{
100 EFI_STATUS Status;
101 UINTN ProcessorNumber;
102 UINT16 Code16, Code32;
103 AP_RESET *APResetFn;
104 UINTN BufferStart;
105 UINTN StackStart;
106
107 Status = GetProcessorNumber (CpuMpData, &ProcessorNumber);
108 ASSERT_EFI_ERROR (Status);
109
110 Code16 = GetProtectedMode16CS ();
111 Code32 = GetProtectedMode32CS ();
112
113 APResetFn = (AP_RESET *)(CpuMpData->WakeupBufferHigh + CpuMpData->AddressMap.SwitchToRealNoNxOffset);
114
115 BufferStart = CpuMpData->MpCpuExchangeInfo->BufferStart;
116 StackStart = CpuMpData->SevEsAPResetStackStart -
117 (AP_RESET_STACK_SIZE * ProcessorNumber);
118
119 //
120 // This call never returns.
121 //
122 APResetFn (BufferStart, Code16, Code32, StackStart);
123}
124
130VOID
132 IN OUT CPU_MP_DATA *CpuMpData
133 )
134{
135 if (CpuMpData->SevEsAPBuffer == (UINTN)-1) {
136 CpuMpData->SevEsAPBuffer =
137 CpuMpData->SevEsIsEnabled ? GetSevEsAPMemory () : 0;
138 }
139}
140
146VOID
148 IN UINTN SipiVector
149 )
150{
151 SEV_ES_AP_JMP_FAR *JmpFar;
152 UINT32 Offset, InsnByte;
153 UINT8 LoNib, HiNib;
154
155 JmpFar = (SEV_ES_AP_JMP_FAR *)(UINTN)FixedPcdGet32 (PcdSevEsWorkAreaBase);
156 ASSERT (JmpFar != NULL);
157
158 //
159 // Obtain the address of the Segment/Rip location in the workarea.
160 // This will be set to a value derived from the SIPI vector and will
161 // be the memory address used for the far jump below.
162 //
163 Offset = FixedPcdGet32 (PcdSevEsWorkAreaBase);
164 Offset += sizeof (JmpFar->InsnBuffer);
165 LoNib = (UINT8)Offset;
166 HiNib = (UINT8)(Offset >> 8);
167
168 //
169 // Program the workarea (which is the initial AP boot address) with
170 // far jump to the SIPI vector (where XX and YY represent the
171 // address of where the SIPI vector is stored.
172 //
173 // JMP FAR [CS:XXYY] => 2E FF 2E YY XX
174 //
175 InsnByte = 0;
176 JmpFar->InsnBuffer[InsnByte++] = 0x2E; // CS override prefix
177 JmpFar->InsnBuffer[InsnByte++] = 0xFF; // JMP (FAR)
178 JmpFar->InsnBuffer[InsnByte++] = 0x2E; // ModRM (JMP memory location)
179 JmpFar->InsnBuffer[InsnByte++] = LoNib; // YY offset ...
180 JmpFar->InsnBuffer[InsnByte++] = HiNib; // XX offset ...
181
182 //
183 // Program the Segment/Rip based on the SIPI vector (always at least
184 // 16-byte aligned, so Rip is set to 0).
185 //
186 JmpFar->Rip = 0;
187 JmpFar->Segment = (UINT16)(SipiVector >> 4);
188}
189
195VOID
197 CPU_MP_DATA *CpuMpData
198 )
199{
201 GHCB *Ghcb;
202 UINT64 Status;
203 BOOLEAN DoDecrement;
204 BOOLEAN InterruptState;
205
206 DoDecrement = (BOOLEAN)(CpuMpData->InitFlag == ApInitConfig);
207
208 while (TRUE) {
209 Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);
210 Ghcb = Msr.Ghcb;
211
212 VmgInit (Ghcb, &InterruptState);
213
214 if (DoDecrement) {
215 DoDecrement = FALSE;
216
217 //
218 // Perform the delayed decrement just before issuing the first
219 // VMGEXIT with AP_RESET_HOLD.
220 //
221 InterlockedDecrement ((UINT32 *)&CpuMpData->MpCpuExchangeInfo->NumApsExecuting);
222 }
223
224 Status = VmgExit (Ghcb, SVM_EXIT_AP_RESET_HOLD, 0, 0);
225 if ((Status == 0) && (Ghcb->SaveArea.SwExitInfo2 != 0)) {
226 VmgDone (Ghcb, InterruptState);
227 break;
228 }
229
230 VmgDone (Ghcb, InterruptState);
231 }
232
233 //
234 // Awakened in a new phase? Use the new CpuMpData
235 //
236 if (CpuMpData->NewCpuMpData != NULL) {
237 CpuMpData = CpuMpData->NewCpuMpData;
238 }
239
240 MpInitLibSevEsAPReset (Ghcb, CpuMpData);
241}
242
248VOID
250 IN volatile MP_CPU_EXCHANGE_INFO *ExchangeInfo
251 )
252{
253 UINT32 StdRangeMax;
254
255 AsmCpuid (CPUID_SIGNATURE, &StdRangeMax, NULL, NULL, NULL);
256 if (StdRangeMax >= CPUID_EXTENDED_TOPOLOGY) {
258
260 ExchangeInfo->ExtTopoAvail = !!ExtTopoEbx.Bits.LogicalProcessors;
261 }
262}
UINT64 UINTN
#define NULL
Definition: Base.h:312
#define STATIC
Definition: Base.h:264
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
#define ASSERT_EFI_ERROR(StatusParameter)
Definition: DebugLib.h:440
#define ASSERT(Expression)
Definition: DebugLib.h:391
UINTN GetSevEsAPMemory(VOID)
Definition: DxeMpLib.c:195
#define MSR_SEV_ES_GHCB
Definition: Fam17Msr.h:24
UINT64 EFIAPI AsmReadMsr64(IN UINT32 Index)
Definition: GccInlinePriv.c:60
#define CPUID_SIGNATURE
Definition: Cpuid.h:45
#define CPUID_EXTENDED_TOPOLOGY
Definition: Cpuid.h:1810
UINT32 EFIAPI AsmCpuid(IN UINT32 Index, OUT UINT32 *RegisterEax OPTIONAL, OUT UINT32 *RegisterEbx OPTIONAL, OUT UINT32 *RegisterEcx OPTIONAL, OUT UINT32 *RegisterEdx OPTIONAL)
Definition: CpuId.c:36
EFI_STATUS GetProcessorNumber(IN CPU_MP_DATA *CpuMpData, OUT UINTN *ProcessorNumber)
Definition: MpLib.c:445
#define FixedPcdGet32(TokenName)
Definition: PcdLib.h:92
UINT32 EFIAPI InterlockedDecrement(IN volatile UINT32 *Value)
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:28
VOID AllocateSevEsAPMemory(IN OUT CPU_MP_DATA *CpuMpData)
Definition: AmdSev.c:131
VOID SetSevEsJumpTable(IN UINTN SipiVector)
Definition: AmdSev.c:147
VOID MpInitLibSevEsAPReset(IN GHCB *Ghcb, IN CPU_MP_DATA *CpuMpData)
Definition: AmdSev.c:95
VOID SevEsPlaceApHlt(CPU_MP_DATA *CpuMpData)
Definition: AmdSev.c:196
VOID FillExchangeInfoDataSevEs(IN volatile MP_CPU_EXCHANGE_INFO *ExchangeInfo)
Definition: AmdSev.c:249
STATIC UINT16 GetProtectedMode16CS(VOID)
Definition: AmdSev.c:21
STATIC UINT16 GetProtectedMode32CS(VOID)
Definition: AmdSev.c:57
UINT64 EFIAPI VmgExit(IN OUT GHCB *Ghcb, IN UINT64 ExitCode, IN UINT64 ExitInfo1, IN UINT64 ExitInfo2)
Definition: VmgExitLib.c:105
VOID EFIAPI VmgInit(IN OUT GHCB *Ghcb, IN OUT BOOLEAN *InterruptState)
Definition: VmgExitLib.c:145
VOID EFIAPI VmgDone(IN OUT GHCB *Ghcb, IN BOOLEAN InterruptState)
Definition: VmgExitLib.c:175
VOID EFIAPI AsmReadGdtr(OUT IA32_DESCRIPTOR *Gdtr)
Definition: X86ReadGdtr.c:24
struct CPUID_EXTENDED_TOPOLOGY_EBX::@626 Bits