TianoCore EDK2 master
Loading...
Searching...
No Matches
FaultTolerantWriteSmm.c
Go to the documentation of this file.
1
51#include <PiMm.h>
53#include <Library/BaseLib.h>
55#include "FaultTolerantWrite.h"
57#include <Protocol/MmEndOfDxe.h>
58
59VOID *mFvbRegistration = NULL;
60EFI_FTW_DEVICE *mFtwDevice = NULL;
61
65BOOLEAN mEndOfDxe = FALSE;
66
81 IN EFI_HANDLE FvBlockHandle,
83 )
84{
85 //
86 // To get the SMM FVB protocol interface on the handle
87 //
88 return gMmst->MmHandleProtocol (
89 FvBlockHandle,
90 &gEfiSmmFirmwareVolumeBlockProtocolGuid,
91 (VOID **)FvBlock
92 );
93}
94
107 OUT VOID **SarProtocol
108 )
109{
110 EFI_STATUS Status;
111
112 //
113 // Locate Smm Swap Address Range protocol
114 //
115 Status = gMmst->MmLocateProtocol (
116 &gEfiSmmSwapAddressRangeProtocolGuid,
117 NULL,
118 SarProtocol
119 );
120 return Status;
121}
122
140 OUT UINTN *NumberHandles,
141 OUT EFI_HANDLE **Buffer
142 )
143{
144 EFI_STATUS Status;
145 UINTN BufferSize;
146
147 if ((NumberHandles == NULL) || (Buffer == NULL)) {
148 return EFI_INVALID_PARAMETER;
149 }
150
151 BufferSize = 0;
152 *NumberHandles = 0;
153 *Buffer = NULL;
154 Status = gMmst->MmLocateHandle (
156 &gEfiSmmFirmwareVolumeBlockProtocolGuid,
157 NULL,
158 &BufferSize,
159 *Buffer
160 );
161 if (EFI_ERROR (Status) && (Status != EFI_BUFFER_TOO_SMALL)) {
162 return EFI_NOT_FOUND;
163 }
164
165 *Buffer = AllocatePool (BufferSize);
166 if (*Buffer == NULL) {
167 return EFI_OUT_OF_RESOURCES;
168 }
169
170 Status = gMmst->MmLocateHandle (
172 &gEfiSmmFirmwareVolumeBlockProtocolGuid,
173 NULL,
174 &BufferSize,
175 *Buffer
176 );
177
178 *NumberHandles = BufferSize / sizeof (EFI_HANDLE);
179 if (EFI_ERROR (Status)) {
180 *NumberHandles = 0;
181 FreePool (*Buffer);
182 *Buffer = NULL;
183 }
184
185 return Status;
186}
187
201 IN EFI_PHYSICAL_ADDRESS Address,
202 IN EFI_FVB_ATTRIBUTES_2 Attributes,
203 OUT EFI_HANDLE *SmmFvbHandle
204 )
205{
206 EFI_STATUS Status;
207 EFI_HANDLE *HandleBuffer;
208 UINTN HandleCount;
209 UINTN Index;
210 EFI_PHYSICAL_ADDRESS FvbBaseAddress;
211 EFI_FVB_ATTRIBUTES_2 FvbAttributes;
213
214 HandleBuffer = NULL;
215
216 //
217 // Locate all handles of SMM Fvb protocol.
218 //
219 Status = GetFvbCountAndBuffer (&HandleCount, &HandleBuffer);
220 if (EFI_ERROR (Status)) {
221 return EFI_ABORTED;
222 }
223
224 //
225 // Find the proper SMM Fvb handle by the address and attributes.
226 //
227 for (Index = 0; Index < HandleCount; Index++) {
228 Status = FtwGetFvbByHandle (HandleBuffer[Index], &Fvb);
229 if (EFI_ERROR (Status)) {
230 break;
231 }
232
233 //
234 // Compare the address.
235 //
236 Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress);
237 if (EFI_ERROR (Status)) {
238 continue;
239 }
240
241 if (Address != FvbBaseAddress) {
242 continue;
243 }
244
245 //
246 // Compare the attribute.
247 //
248 Status = Fvb->GetAttributes (Fvb, &FvbAttributes);
249 if (EFI_ERROR (Status)) {
250 continue;
251 }
252
253 if (Attributes != FvbAttributes) {
254 continue;
255 }
256
257 //
258 // Found the proper FVB handle.
259 //
260 *SmmFvbHandle = HandleBuffer[Index];
261 FreePool (HandleBuffer);
262 return EFI_SUCCESS;
263 }
264
265 FreePool (HandleBuffer);
266 return EFI_ABORTED;
267}
268
296EFIAPI
298 IN EFI_HANDLE DispatchHandle,
299 IN CONST VOID *RegisterContext,
300 IN OUT VOID *CommBuffer,
301 IN OUT UINTN *CommBufferSize
302 )
303{
304 EFI_STATUS Status;
305 SMM_FTW_COMMUNICATE_FUNCTION_HEADER *SmmFtwFunctionHeader;
306 SMM_FTW_GET_MAX_BLOCK_SIZE_HEADER *SmmGetMaxBlockSizeHeader;
307 SMM_FTW_ALLOCATE_HEADER *SmmFtwAllocateHeader;
308 SMM_FTW_WRITE_HEADER *SmmFtwWriteHeader;
309 SMM_FTW_RESTART_HEADER *SmmFtwRestartHeader;
310 SMM_FTW_GET_LAST_WRITE_HEADER *SmmFtwGetLastWriteHeader;
311 VOID *PrivateData;
312 EFI_HANDLE SmmFvbHandle;
313 UINTN InfoSize;
314 UINTN CommBufferPayloadSize;
315 UINTN PrivateDataSize;
316 UINTN Length;
317 UINTN TempCommBufferSize;
318
319 //
320 // If input is invalid, stop processing this SMI
321 //
322 if ((CommBuffer == NULL) || (CommBufferSize == NULL)) {
323 return EFI_SUCCESS;
324 }
325
326 TempCommBufferSize = *CommBufferSize;
327
328 if (TempCommBufferSize < SMM_FTW_COMMUNICATE_HEADER_SIZE) {
329 DEBUG ((DEBUG_ERROR, "SmmFtwHandler: SMM communication buffer size invalid!\n"));
330 return EFI_SUCCESS;
331 }
332
333 CommBufferPayloadSize = TempCommBufferSize - SMM_FTW_COMMUNICATE_HEADER_SIZE;
334
335 if (!FtwSmmIsPrimaryBufferValid ((UINTN)CommBuffer, TempCommBufferSize)) {
336 DEBUG ((DEBUG_ERROR, "SmmFtwHandler: SMM Primary(communication buffer) is not valid!\n"));
337 return EFI_SUCCESS;
338 }
339
340 SmmFtwFunctionHeader = (SMM_FTW_COMMUNICATE_FUNCTION_HEADER *)CommBuffer;
341
342 if (mEndOfDxe) {
343 //
344 // It will be not safe to expose the operations after End Of Dxe.
345 //
346 DEBUG ((DEBUG_ERROR, "SmmFtwHandler: Not safe to do the operation: %x after End Of Dxe, so access denied!\n", SmmFtwFunctionHeader->Function));
347 SmmFtwFunctionHeader->ReturnStatus = EFI_ACCESS_DENIED;
348 return EFI_SUCCESS;
349 }
350
351 switch (SmmFtwFunctionHeader->Function) {
352 case FTW_FUNCTION_GET_MAX_BLOCK_SIZE:
353 if (CommBufferPayloadSize < sizeof (SMM_FTW_GET_MAX_BLOCK_SIZE_HEADER)) {
354 DEBUG ((DEBUG_ERROR, "GetMaxBlockSize: SMM communication buffer size invalid!\n"));
355 return EFI_SUCCESS;
356 }
357
358 SmmGetMaxBlockSizeHeader = (SMM_FTW_GET_MAX_BLOCK_SIZE_HEADER *)SmmFtwFunctionHeader->Data;
359
360 Status = FtwGetMaxBlockSize (
361 &mFtwDevice->FtwInstance,
362 &SmmGetMaxBlockSizeHeader->BlockSize
363 );
364 break;
365
366 case FTW_FUNCTION_ALLOCATE:
367 if (CommBufferPayloadSize < sizeof (SMM_FTW_ALLOCATE_HEADER)) {
368 DEBUG ((DEBUG_ERROR, "Allocate: SMM communication buffer size invalid!\n"));
369 return EFI_SUCCESS;
370 }
371
372 SmmFtwAllocateHeader = (SMM_FTW_ALLOCATE_HEADER *)SmmFtwFunctionHeader->Data;
373 Status = FtwAllocate (
374 &mFtwDevice->FtwInstance,
375 &SmmFtwAllocateHeader->CallerId,
376 SmmFtwAllocateHeader->PrivateDataSize,
377 SmmFtwAllocateHeader->NumberOfWrites
378 );
379 break;
380
381 case FTW_FUNCTION_WRITE:
382 if (CommBufferPayloadSize < OFFSET_OF (SMM_FTW_WRITE_HEADER, Data)) {
383 DEBUG ((DEBUG_ERROR, "Write: SMM communication buffer size invalid!\n"));
384 return EFI_SUCCESS;
385 }
386
387 SmmFtwWriteHeader = (SMM_FTW_WRITE_HEADER *)SmmFtwFunctionHeader->Data;
388 Length = SmmFtwWriteHeader->Length;
389 PrivateDataSize = SmmFtwWriteHeader->PrivateDataSize;
390 if (((UINTN)(~0) - Length < OFFSET_OF (SMM_FTW_WRITE_HEADER, Data)) ||
391 ((UINTN)(~0) - PrivateDataSize < OFFSET_OF (SMM_FTW_WRITE_HEADER, Data) + Length))
392 {
393 //
394 // Prevent InfoSize overflow
395 //
396 Status = EFI_ACCESS_DENIED;
397 break;
398 }
399
400 InfoSize = OFFSET_OF (SMM_FTW_WRITE_HEADER, Data) + Length + PrivateDataSize;
401
402 //
403 // SMRAM range check already covered before
404 //
405 if (InfoSize > CommBufferPayloadSize) {
406 DEBUG ((DEBUG_ERROR, "Write: Data size exceed communication buffer size limit!\n"));
407 Status = EFI_ACCESS_DENIED;
408 break;
409 }
410
411 if (PrivateDataSize == 0) {
412 PrivateData = NULL;
413 } else {
414 PrivateData = (VOID *)&SmmFtwWriteHeader->Data[Length];
415 }
416
418 SmmFtwWriteHeader->FvbBaseAddress,
419 SmmFtwWriteHeader->FvbAttributes,
420 &SmmFvbHandle
421 );
422 if (!EFI_ERROR (Status)) {
423 //
424 // The SpeculationBarrier() call here is to ensure the previous
425 // range/content checks for the CommBuffer have been completed before
426 // calling into FtwWrite().
427 //
429 Status = FtwWrite (
430 &mFtwDevice->FtwInstance,
431 SmmFtwWriteHeader->Lba,
432 SmmFtwWriteHeader->Offset,
433 Length,
434 PrivateData,
435 SmmFvbHandle,
436 SmmFtwWriteHeader->Data
437 );
438 }
439
440 break;
441
442 case FTW_FUNCTION_RESTART:
443 if (CommBufferPayloadSize < sizeof (SMM_FTW_RESTART_HEADER)) {
444 DEBUG ((DEBUG_ERROR, "Restart: SMM communication buffer size invalid!\n"));
445 return EFI_SUCCESS;
446 }
447
448 SmmFtwRestartHeader = (SMM_FTW_RESTART_HEADER *)SmmFtwFunctionHeader->Data;
450 SmmFtwRestartHeader->FvbBaseAddress,
451 SmmFtwRestartHeader->FvbAttributes,
452 &SmmFvbHandle
453 );
454 if (!EFI_ERROR (Status)) {
455 Status = FtwRestart (&mFtwDevice->FtwInstance, SmmFvbHandle);
456 }
457
458 break;
459
460 case FTW_FUNCTION_ABORT:
461 Status = FtwAbort (&mFtwDevice->FtwInstance);
462 break;
463
464 case FTW_FUNCTION_GET_LAST_WRITE:
465 if (CommBufferPayloadSize < OFFSET_OF (SMM_FTW_GET_LAST_WRITE_HEADER, Data)) {
466 DEBUG ((DEBUG_ERROR, "GetLastWrite: SMM communication buffer size invalid!\n"));
467 return EFI_SUCCESS;
468 }
469
470 SmmFtwGetLastWriteHeader = (SMM_FTW_GET_LAST_WRITE_HEADER *)SmmFtwFunctionHeader->Data;
471 PrivateDataSize = SmmFtwGetLastWriteHeader->PrivateDataSize;
472 if ((UINTN)(~0) - PrivateDataSize < OFFSET_OF (SMM_FTW_GET_LAST_WRITE_HEADER, Data)) {
473 //
474 // Prevent InfoSize overflow
475 //
476 Status = EFI_ACCESS_DENIED;
477 break;
478 }
479
480 InfoSize = OFFSET_OF (SMM_FTW_GET_LAST_WRITE_HEADER, Data) + PrivateDataSize;
481
482 //
483 // SMRAM range check already covered before
484 //
485 if (InfoSize > CommBufferPayloadSize) {
486 DEBUG ((DEBUG_ERROR, "Data size exceed communication buffer size limit!\n"));
487 Status = EFI_ACCESS_DENIED;
488 break;
489 }
490
491 Status = FtwGetLastWrite (
492 &mFtwDevice->FtwInstance,
493 &SmmFtwGetLastWriteHeader->CallerId,
494 &SmmFtwGetLastWriteHeader->Lba,
495 &SmmFtwGetLastWriteHeader->Offset,
496 &SmmFtwGetLastWriteHeader->Length,
497 &PrivateDataSize,
498 (VOID *)SmmFtwGetLastWriteHeader->Data,
499 &SmmFtwGetLastWriteHeader->Complete
500 );
501 SmmFtwGetLastWriteHeader->PrivateDataSize = PrivateDataSize;
502 break;
503
504 default:
505 Status = EFI_UNSUPPORTED;
506 }
507
508 SmmFtwFunctionHeader->ReturnStatus = Status;
509
510 return EFI_SUCCESS;
511}
512
524EFIAPI
526 IN CONST EFI_GUID *Protocol,
527 IN VOID *Interface,
528 IN EFI_HANDLE Handle
529 )
530{
531 EFI_STATUS Status;
533 EFI_HANDLE SmmFtwHandle;
534
535 //
536 // Just return to avoid install SMM FaultTolerantWriteProtocol again
537 // if SMM Fault Tolerant Write protocol had been installed.
538 //
539 Status = gMmst->MmLocateProtocol (
540 &gEfiSmmFaultTolerantWriteProtocolGuid,
541 NULL,
542 (VOID **)&FtwProtocol
543 );
544 if (!EFI_ERROR (Status)) {
545 return EFI_SUCCESS;
546 }
547
548 //
549 // Found proper FVB protocol and initialize FtwDevice for protocol installation
550 //
551 Status = InitFtwProtocol (mFtwDevice);
552 if (EFI_ERROR (Status)) {
553 return Status;
554 }
555
556 //
557 // Install protocol interface
558 //
559 Status = gMmst->MmInstallProtocolInterface (
560 &mFtwDevice->Handle,
561 &gEfiSmmFaultTolerantWriteProtocolGuid,
563 &mFtwDevice->FtwInstance
564 );
565 ASSERT_EFI_ERROR (Status);
566
570 Status = gMmst->MmiHandlerRegister (SmmFaultTolerantWriteHandler, &gEfiSmmFaultTolerantWriteProtocolGuid, &SmmFtwHandle);
571 ASSERT_EFI_ERROR (Status);
572
573 //
574 // Notify the Ftw wrapper driver SMM Ftw is ready
575 //
577
578 return EFI_SUCCESS;
579}
580
592EFIAPI
594 IN CONST EFI_GUID *Protocol,
595 IN VOID *Interface,
596 IN EFI_HANDLE Handle
597 )
598{
599 mEndOfDxe = TRUE;
600 return EFI_SUCCESS;
601}
602
612 VOID
613 )
614{
615 EFI_STATUS Status;
616 VOID *MmEndOfDxeRegistration;
617
618 //
619 // Allocate private data structure for SMM FTW protocol and do some initialization
620 //
621 Status = InitFtwDevice (&mFtwDevice);
622 if (EFI_ERROR (Status)) {
623 return Status;
624 }
625
626 //
627 // Register EFI_SMM_END_OF_DXE_PROTOCOL_GUID notify function.
628 //
629 Status = gMmst->MmRegisterProtocolNotify (
630 &gEfiMmEndOfDxeProtocolGuid,
632 &MmEndOfDxeRegistration
633 );
634 ASSERT_EFI_ERROR (Status);
635
636 //
637 // Register FvbNotificationEvent () notify function.
638 //
639 Status = gMmst->MmRegisterProtocolNotify (
640 &gEfiSmmFirmwareVolumeBlockProtocolGuid,
642 &mFvbRegistration
643 );
644 ASSERT_EFI_ERROR (Status);
645
647
648 return EFI_SUCCESS;
649}
UINT64 UINTN
VOID EFIAPI SpeculationBarrier(VOID)
VOID EFIAPI FreePool(IN VOID *Buffer)
EFI_STATUS EFIAPI FtwGetMaxBlockSize(IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This, OUT UINTN *BlockSize)
EFI_STATUS EFIAPI FtwRestart(IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This, IN EFI_HANDLE FvBlockHandle)
EFI_STATUS EFIAPI FtwAllocate(IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This, IN EFI_GUID *CallerId, IN UINTN PrivateDataSize, IN UINTN NumberOfWrites)
EFI_STATUS EFIAPI FtwWrite(IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This, IN EFI_LBA Lba, IN UINTN Offset, IN UINTN Length, IN VOID *PrivateData, IN EFI_HANDLE FvBlockHandle, IN VOID *Buffer)
EFI_STATUS EFIAPI FtwGetLastWrite(IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This, OUT EFI_GUID *CallerId, OUT EFI_LBA *Lba, OUT UINTN *Offset, OUT UINTN *Length, IN OUT UINTN *PrivateDataSize, OUT VOID *PrivateData, OUT BOOLEAN *Complete)
EFI_STATUS EFIAPI FtwAbort(IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This)
BOOLEAN mEndOfDxe
EFI_STATUS FtwGetSarProtocol(OUT VOID **SarProtocol)
EFI_STATUS EFIAPI MmEndOfDxeCallback(IN CONST EFI_GUID *Protocol, IN VOID *Interface, IN EFI_HANDLE Handle)
EFI_STATUS EFIAPI FvbNotificationEvent(IN CONST EFI_GUID *Protocol, IN VOID *Interface, IN EFI_HANDLE Handle)
EFI_STATUS GetFvbCountAndBuffer(OUT UINTN *NumberHandles, OUT EFI_HANDLE **Buffer)
EFI_STATUS FtwGetFvbByHandle(IN EFI_HANDLE FvBlockHandle, OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvBlock)
EFI_STATUS EFIAPI SmmFaultTolerantWriteHandler(IN EFI_HANDLE DispatchHandle, IN CONST VOID *RegisterContext, IN OUT VOID *CommBuffer, IN OUT UINTN *CommBufferSize)
EFI_STATUS MmFaultTolerantWriteInitialize(VOID)
EFI_STATUS GetFvbByAddressAndAttribute(IN EFI_PHYSICAL_ADDRESS Address, IN EFI_FVB_ATTRIBUTES_2 Attributes, OUT EFI_HANDLE *SmmFvbHandle)
#define SMM_FTW_COMMUNICATE_HEADER_SIZE
VOID FtwNotifySmmReady(VOID)
BOOLEAN FtwSmmIsPrimaryBufferValid(IN EFI_PHYSICAL_ADDRESS Buffer, IN UINT64 Length)
#define NULL
Definition: Base.h:319
#define CONST
Definition: Base.h:259
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define OFFSET_OF(TYPE, Field)
Definition: Base.h:758
#define OUT
Definition: Base.h:284
#define ASSERT_EFI_ERROR(StatusParameter)
Definition: DebugLib.h:462
#define DEBUG(Expression)
Definition: DebugLib.h:434
UINT32 EFI_FVB_ATTRIBUTES_2
VOID *EFIAPI AllocatePool(IN UINTN AllocationSize)
UINT64 EFI_PHYSICAL_ADDRESS
Definition: UefiBaseType.h:50
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
VOID * EFI_HANDLE
Definition: UefiBaseType.h:33
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
@ EFI_NATIVE_INTERFACE
Definition: UefiSpec.h:1193
@ ByProtocol
Definition: UefiSpec.h:1518
EFI_STATUS InitFtwDevice(OUT EFI_FTW_DEVICE **FtwData)
Definition: FtwMisc.c:992
EFI_STATUS InitFtwProtocol(IN OUT EFI_FTW_DEVICE *FtwDevice)
Definition: FtwMisc.c:1236
EFI_INSTALL_PROTOCOL_INTERFACE MmInstallProtocolInterface
Definition: PiMmCis.h:327
Definition: Base.h:213