TianoCore EDK2 master
Loading...
Searching...
No Matches
BlSupportSmm.c
Go to the documentation of this file.
1
14#include <BlSupportSmm.h>
15
16PLD_S3_COMMUNICATION mPldS3Hob;
18PLD_SMM_REGISTERS *mSmmRegisterHob = NULL;
19UINT64 mSmmFeatureControl = 0;
20
36 IN UINT8 BlSwSmiHandlerInput
37 )
38{
39 EFI_STATUS Status;
40 EFI_PROCESSOR_INFORMATION ProcessorInfo;
41 EFI_MP_SERVICES_PROTOCOL *MpService;
42 CPU_SMMBASE *SmmBaseInfo;
43 PLD_TO_BL_SMM_INFO *PldSmmInfo;
44 UINTN Index;
45
46 PldSmmInfo = (PLD_TO_BL_SMM_INFO *)(UINTN)mPldS3Hob.CommBuffer.PhysicalStart;
47 PldSmmInfo->Header.Header.HobLength = (UINT16)(sizeof (PLD_TO_BL_SMM_INFO) + gSmst->NumberOfCpus * sizeof (CPU_SMMBASE));
48 for (Index = 0; Index < mSmramHob->NumberOfSmmReservedRegions; Index++) {
49 if ((mPldS3Hob.CommBuffer.PhysicalStart >= mSmramHob->Descriptor[Index].PhysicalStart) &&
50 (mPldS3Hob.CommBuffer.PhysicalStart < mSmramHob->Descriptor[Index].PhysicalStart + mSmramHob->Descriptor[Index].PhysicalSize))
51 {
52 break;
53 }
54 }
55
56 if (Index == mSmramHob->NumberOfSmmReservedRegions) {
57 return EFI_NOT_FOUND;
58 }
59
60 //
61 // Make sure the dedicated region for SMM info communication whose attribute is "allocated" (i.e., excluded from SMM memory service)
62 //
63 if ((mSmramHob->Descriptor[Index].RegionState & EFI_ALLOCATED) == 0) {
64 DEBUG ((DEBUG_ERROR, "SMM communication region not set to EFI_ALLOCATED\n"));
65 return EFI_INVALID_PARAMETER;
66 }
67
68 if (((UINTN)PldSmmInfo + PldSmmInfo->Header.Header.HobLength) > (mSmramHob->Descriptor[Index].PhysicalStart + mSmramHob->Descriptor[Index].PhysicalSize)) {
69 DEBUG ((DEBUG_ERROR, "SMM communication buffer (0x%x) is too small.\n", (UINTN)PldSmmInfo + PldSmmInfo->Header.Header.HobLength));
70 return EFI_BUFFER_TOO_SMALL;
71 }
72
73 CopyGuid (&PldSmmInfo->Header.Name, &gS3CommunicationGuid);
74 PldSmmInfo->Header.Header.HobType = EFI_HOB_TYPE_GUID_EXTENSION;
75 PldSmmInfo->S3Info.SwSmiTriggerValue = BlSwSmiHandlerInput;
76
77 //
78 // Save APIC ID and SMM base
79 //
80 Status = gBS->LocateProtocol (&gEfiMpServiceProtocolGuid, NULL, (VOID **)&MpService);
81 if (EFI_ERROR (Status)) {
82 return Status;
83 }
84
85 PldSmmInfo->S3Info.CpuCount = (UINT32)gSmst->NumberOfCpus;
86 SmmBaseInfo = &PldSmmInfo->S3Info.SmmBase[0];
87 for (Index = 0; Index < gSmst->NumberOfCpus; Index++) {
88 Status = MpService->GetProcessorInfo (MpService, Index, &ProcessorInfo);
89 if (EFI_ERROR (Status)) {
90 return Status;
91 }
92
93 SmmBaseInfo->ApicId = (UINT32)(UINTN)ProcessorInfo.ProcessorId;
94 SmmBaseInfo->SmmBase = (UINT32)(UINTN)gSmst->CpuSaveState[Index] - SMRAM_SAVE_STATE_MAP_OFFSET;
95 DEBUG ((DEBUG_INFO, "CPU%d ID:%02X Base: %08X\n", Index, SmmBaseInfo->ApicId, SmmBaseInfo->SmmBase));
96 SmmBaseInfo++;
97 }
98
99 return EFI_SUCCESS;
100}
101
113 UINT64 Id
114 )
115{
116 UINT32 Index;
117
118 for (Index = 0; Index < mSmmRegisterHob->Count; Index++) {
119 if (mSmmRegisterHob->Registers[Index].Id == Id) {
120 return &mSmmRegisterHob->Registers[Index];
121 }
122 }
123
124 return NULL;
125}
126
131VOID
133 VOID
134 )
135{
136 PLD_GENERIC_REGISTER *SmiLockReg;
137
138 DEBUG ((DEBUG_ERROR, "LockSmiGlobalEn .....\n"));
139
140 SmiLockReg = GetRegisterById (REGISTER_ID_SMI_GBL_EN_LOCK);
141 if (SmiLockReg == NULL) {
142 DEBUG ((DEBUG_ERROR, "SMI global enable lock reg not found.\n"));
143 return;
144 }
145
146 //
147 // Set SMM SMI lock in S3 path
148 //
149 if ((SmiLockReg->Address.AccessSize == EFI_ACPI_3_0_DWORD) &&
150 (SmiLockReg->Address.Address != 0) &&
151 (SmiLockReg->Address.RegisterBitWidth == 1) &&
152 (SmiLockReg->Address.AddressSpaceId == EFI_ACPI_3_0_SYSTEM_MEMORY) &&
153 (SmiLockReg->Value == 1))
154 {
155 DEBUG ((DEBUG_ERROR, "LockSmiGlobalEn ....is locked\n"));
156
157 MmioOr32 ((UINT32)SmiLockReg->Address.Address, 1 << SmiLockReg->Address.RegisterBitOffset);
158 } else {
159 DEBUG ((DEBUG_ERROR, "Unexpected SMM SMI lock register, need enhancement here.\n"));
160 }
161}
162
168VOID
170 VOID
171 )
172{
173 if (mSmmFeatureControl != 0) {
174 return;
175 }
176
177 mSmmFeatureControl = AsmReadMsr64 (MSR_SMM_FEATURE_CONTROL);
178 if ((mSmmFeatureControl & 0x5) != 0x5) {
179 //
180 // Set Lock bit [BIT0] for this register and SMM code check enable bit [BIT2]
181 //
182 AsmWriteMsr64 (MSR_SMM_FEATURE_CONTROL, mSmmFeatureControl | 0x5);
183 }
184
185 mSmmFeatureControl = AsmReadMsr64 (MSR_SMM_FEATURE_CONTROL);
186}
187
193VOID
194EFIAPI
196 IN VOID *ProcedureArgument
197 )
198{
199 if (ProcedureArgument != NULL) {
200 AsmWriteMsr64 (MSR_IA32_SMRR_PHYSBASE, ((SMRR_BASE_MASK *)ProcedureArgument)->Base);
201 AsmWriteMsr64 (MSR_IA32_SMRR_PHYSMASK, ((SMRR_BASE_MASK *)ProcedureArgument)->Mask);
202 }
203}
204
209VOID
211 VOID
212 )
213{
214 EFI_STATUS Status;
215 SMRR_BASE_MASK Arguments;
216 UINTN Index;
217 UINT32 SmmBase;
218 UINT32 SmmSize;
219
220 if ((AsmReadMsr64 (MSR_IA32_SMRR_PHYSBASE) != 0) && ((AsmReadMsr64 (MSR_IA32_SMRR_PHYSMASK) & BIT11) != 0)) {
221 return;
222 }
223
224 SmmBase = (UINT32)(UINTN)mSmramHob->Descriptor[0].PhysicalStart;
225 SmmSize = (UINT32)(UINTN)mSmramHob->Descriptor[0].PhysicalSize;
226 if ((mSmramHob->NumberOfSmmReservedRegions > 2) || (mSmramHob->NumberOfSmmReservedRegions == 0)) {
227 DEBUG ((DEBUG_ERROR, "%d SMM ranges are not supported.\n", mSmramHob->NumberOfSmmReservedRegions));
228 return;
229 } else if (mSmramHob->NumberOfSmmReservedRegions == 2) {
230 if ((mSmramHob->Descriptor[1].PhysicalStart + mSmramHob->Descriptor[1].PhysicalSize) == SmmBase) {
231 SmmBase = (UINT32)(UINTN)mSmramHob->Descriptor[1].PhysicalStart;
232 } else if (mSmramHob->Descriptor[1].PhysicalStart != (SmmBase + SmmSize)) {
233 DEBUG ((DEBUG_ERROR, "Two SMM regions are not continous.\n"));
234 return;
235 }
236
237 SmmSize += (UINT32)(UINTN)mSmramHob->Descriptor[1].PhysicalSize;
238 }
239
240 if ((SmmBase == 0) || (SmmSize < SIZE_4KB)) {
241 DEBUG ((DEBUG_ERROR, "Invalid SMM range.\n"));
242 return;
243 }
244
245 //
246 // SMRR size must be of length 2^n
247 // SMRR base alignment cannot be less than SMRR length
248 //
249 if ((SmmSize != GetPowerOfTwo32 (SmmSize)) || ((SmmBase & ~(SmmSize - 1)) != SmmBase)) {
250 DEBUG ((DEBUG_ERROR, " Invalid SMM range.\n"));
251 return;
252 }
253
254 //
255 // Calculate smrr base, mask and pass them as arguments.
256 //
257 Arguments.Base = (SmmSize | MTRR_CACHE_WRITE_BACK);
258 Arguments.Mask = (~(SmmSize - 1) & EFI_MSR_SMRR_MASK);
259
260 //
261 // Set SMRR valid bit
262 //
263 Arguments.Mask |= BIT11;
264
265 //
266 // Program smrr base and mask on BSP first and then on APs
267 //
268 SetSmrr (&Arguments);
269 for (Index = 0; Index < gSmst->NumberOfCpus; Index++) {
270 if (Index != gSmst->CurrentlyExecutingCpu) {
271 Status = gSmst->SmmStartupThisAp (SetSmrr, Index, (VOID *)&Arguments);
272 if (EFI_ERROR (Status)) {
273 DEBUG ((DEBUG_ERROR, "Programming SMRR on AP# %d status: %r\n", Index, Status));
274 }
275 }
276 }
277}
278
293EFIAPI
295 IN EFI_HANDLE DispatchHandle,
296 IN CONST VOID *Context,
297 IN OUT VOID *CommBuffer,
298 IN OUT UINTN *CommBufferSize
299 )
300{
301 SetSmrrOnS3 ();
304
305 return EFI_SUCCESS;
306}
307
319EFIAPI
321 IN CONST EFI_GUID *Protocol,
322 IN VOID *Interface,
323 IN EFI_HANDLE Handle
324 )
325{
326 //
327 // Set SMM SMI lock
328 //
330 return EFI_SUCCESS;
331}
332
344EFIAPI
346 IN EFI_HANDLE ImageHandle,
347 IN EFI_SYSTEM_TABLE *SystemTable
348 )
349{
350 EFI_STATUS Status;
353 EFI_HANDLE SwHandle;
354 EFI_HOB_GUID_TYPE *GuidHob;
355 VOID *SmmHob;
356 VOID *Registration;
357
358 //
359 // Get SMM S3 communication hob and save it
360 //
361 GuidHob = GetFirstGuidHob (&gS3CommunicationGuid);
362 if (GuidHob != NULL) {
363 SmmHob = (VOID *)(GET_GUID_HOB_DATA (GuidHob));
364 CopyMem (&mPldS3Hob, SmmHob, GET_GUID_HOB_DATA_SIZE (GuidHob));
365 } else {
366 return EFI_NOT_FOUND;
367 }
368
369 if (mPldS3Hob.PldAcpiS3Enable) {
370 // Other drivers will take care of S3.
371 return EFI_SUCCESS;
372 }
373
374 //
375 // Get smram hob and save it
376 //
377 GuidHob = GetFirstGuidHob (&gEfiSmmSmramMemoryGuid);
378 if (GuidHob != NULL) {
379 SmmHob = (VOID *)(GET_GUID_HOB_DATA (GuidHob));
380 mSmramHob = AllocatePool (GET_GUID_HOB_DATA_SIZE (GuidHob));
381 if (mSmramHob == NULL) {
382 return EFI_OUT_OF_RESOURCES;
383 }
384
385 CopyMem (mSmramHob, SmmHob, GET_GUID_HOB_DATA_SIZE (GuidHob));
386 } else {
387 return EFI_NOT_FOUND;
388 }
389
390 //
391 // Get SMM register hob and save it
392 //
394 if (GuidHob != NULL) {
395 SmmHob = (VOID *)(GET_GUID_HOB_DATA (GuidHob));
396 mSmmRegisterHob = AllocatePool (GET_GUID_HOB_DATA_SIZE (GuidHob));
397 if (mSmmRegisterHob == NULL) {
398 return EFI_OUT_OF_RESOURCES;
399 }
400
401 CopyMem (mSmmRegisterHob, SmmHob, GET_GUID_HOB_DATA_SIZE (GuidHob));
402 } else {
403 return EFI_NOT_FOUND;
404 }
405
406 //
407 // Get the Sw dispatch protocol and register SMI handler.
408 //
409 Status = gSmst->SmmLocateProtocol (&gEfiSmmSwDispatch2ProtocolGuid, NULL, (VOID **)&SwDispatch);
410 if (EFI_ERROR (Status)) {
411 return Status;
412 }
413
414 SwContext.SwSmiInputValue = (UINTN)-1;
415 Status = SwDispatch->Register (SwDispatch, BlSwSmiHandler, &SwContext, &SwHandle);
416 if (EFI_ERROR (Status)) {
417 DEBUG ((DEBUG_ERROR, "Registering S3 smi handler failed: %r\n", Status));
418 return Status;
419 }
420
421 //
422 // Register SMM ready to lock callback
423 //
424 Status = gSmst->SmmRegisterProtocolNotify (
425 &gEfiSmmReadyToLockProtocolGuid,
427 &Registration
428 );
429 ASSERT_EFI_ERROR (Status);
430
431 SaveSmmInfoForS3 ((UINT8)SwContext.SwSmiInputValue);
432
433 return EFI_SUCCESS;
434}
UINT64 UINTN
VOID *EFIAPI GetFirstGuidHob(IN CONST EFI_GUID *Guid)
Definition: HobLib.c:215
UINT32 EFIAPI GetPowerOfTwo32(IN UINT32 Operand)
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
GUID *EFIAPI CopyGuid(OUT GUID *DestinationGuid, IN CONST GUID *SourceGuid)
Definition: MemLibGuid.c:39
VOID SmmFeatureLockOnS3(VOID)
Definition: BlSupportSmm.c:169
EFI_STATUS SaveSmmInfoForS3(IN UINT8 BlSwSmiHandlerInput)
Definition: BlSupportSmm.c:35
EFI_STATUS EFIAPI BlSupportSmmReadyToLockCallback(IN CONST EFI_GUID *Protocol, IN VOID *Interface, IN EFI_HANDLE Handle)
Definition: BlSupportSmm.c:320
EFI_STATUS EFIAPI BlSwSmiHandler(IN EFI_HANDLE DispatchHandle, IN CONST VOID *Context, IN OUT VOID *CommBuffer, IN OUT UINTN *CommBufferSize)
Definition: BlSupportSmm.c:294
VOID EFIAPI SetSmrr(IN VOID *ProcedureArgument)
Definition: BlSupportSmm.c:195
VOID LockSmiGlobalEn(VOID)
Definition: BlSupportSmm.c:132
EFI_STATUS EFIAPI BlSupportSmm(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable)
Definition: BlSupportSmm.c:345
PLD_GENERIC_REGISTER * GetRegisterById(UINT64 Id)
Definition: BlSupportSmm.c:112
VOID SetSmrrOnS3(VOID)
Definition: BlSupportSmm.c:210
UINT64 EFIAPI AsmReadMsr64(IN UINT32 Index)
Definition: GccInlinePriv.c:60
UINT64 EFIAPI AsmWriteMsr64(IN UINT32 Index, IN UINT64 Value)
UINT32 EFIAPI MmioOr32(IN UINTN Address, IN UINT32 OrData)
Definition: IoHighLevel.c:1785
#define NULL
Definition: Base.h:319
#define CONST
Definition: Base.h:259
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
#define ASSERT_EFI_ERROR(StatusParameter)
Definition: DebugLib.h:462
#define DEBUG(Expression)
Definition: DebugLib.h:434
#define MSR_IA32_SMRR_PHYSBASE
#define MSR_IA32_SMRR_PHYSMASK
#define SMRAM_SAVE_STATE_MAP_OFFSET
EFI_SMM_SYSTEM_TABLE2 * gSmst
VOID *EFIAPI AllocatePool(IN UINTN AllocationSize)
EFI_GUID gSmmRegisterInfoGuid
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
VOID * EFI_HANDLE
Definition: UefiBaseType.h:33
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
EFI_BOOT_SERVICES * gBS
EFI_SMM_STARTUP_THIS_AP SmmStartupThisAp
Definition: PiSmmCis.h:140
EFI_HOB_GENERIC_HEADER Header
Definition: PiHob.h:343
EFI_GUID Name
Definition: PiHob.h:347
EFI_PHYSICAL_ADDRESS PhysicalStart
Definition: PiMultiPhase.h:122
EFI_SMRAM_DESCRIPTOR Descriptor[1]
Definition: Base.h:213