1 /** @file
2 
3   Implement the Fault Tolerant Write (FTW) protocol based on SMM FTW
4   module.
5 
6 Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved. <BR>
7 SPDX-License-Identifier: BSD-2-Clause-Patent
8 
9 **/
10 
11 #include "FaultTolerantWriteSmmDxe.h"
12 
13 EFI_HANDLE                         mHandle                   = NULL;
14 EFI_MM_COMMUNICATION2_PROTOCOL     *mMmCommunication2        = NULL;
15 UINTN                              mPrivateDataSize          = 0;
16 
17 EFI_FAULT_TOLERANT_WRITE_PROTOCOL  mFaultTolerantWriteDriver = {
18   FtwGetMaxBlockSize,
19   FtwAllocate,
20   FtwWrite,
21   FtwRestart,
22   FtwAbort,
23   FtwGetLastWrite
24 };
25 
26 /**
27   Initialize the communicate buffer using DataSize and Function number.
28 
29   @param[out]      CommunicateBuffer The communicate buffer. Caller should free it after use.
30   @param[out]      DataPtr           Points to the data in the communicate buffer. Caller should not free it.
31   @param[in]       DataSize          The payload size.
32   @param[in]       Function          The function number used to initialize the communicate header.
33 
34 **/
35 VOID
InitCommunicateBuffer(OUT VOID ** CommunicateBuffer,OUT VOID ** DataPtr,IN UINTN DataSize,IN UINTN Function)36 InitCommunicateBuffer (
37   OUT     VOID                              **CommunicateBuffer,
38   OUT     VOID                              **DataPtr,
39   IN      UINTN                             DataSize,
40   IN      UINTN                             Function
41   )
42 {
43   EFI_MM_COMMUNICATE_HEADER                 *SmmCommunicateHeader;
44   SMM_FTW_COMMUNICATE_FUNCTION_HEADER       *SmmFtwFunctionHeader;
45 
46   //
47   // The whole buffer size: SMM_COMMUNICATE_HEADER_SIZE + SMM_FTW_COMMUNICATE_HEADER_SIZE + DataSize.
48   //
49   SmmCommunicateHeader = AllocateZeroPool (DataSize + SMM_COMMUNICATE_HEADER_SIZE + SMM_FTW_COMMUNICATE_HEADER_SIZE);
50   ASSERT (SmmCommunicateHeader != NULL);
51 
52   //
53   // Prepare data buffer.
54   //
55   CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmFaultTolerantWriteProtocolGuid);
56   SmmCommunicateHeader->MessageLength = DataSize + SMM_FTW_COMMUNICATE_HEADER_SIZE;
57 
58   SmmFtwFunctionHeader = (SMM_FTW_COMMUNICATE_FUNCTION_HEADER *) SmmCommunicateHeader->Data;
59   SmmFtwFunctionHeader->Function = Function;
60 
61   *CommunicateBuffer = SmmCommunicateHeader;
62   if (DataPtr != NULL) {
63     *DataPtr = SmmFtwFunctionHeader->Data;
64   }
65 }
66 
67 
68 /**
69   Send the data in communicate buffer to SMI handler and get response.
70 
71   @param[in, out]  SmmCommunicateHeader    The communicate buffer.
72   @param[in]       DataSize                The payload size.
73 
74 **/
75 EFI_STATUS
SendCommunicateBuffer(IN OUT EFI_MM_COMMUNICATE_HEADER * SmmCommunicateHeader,IN UINTN DataSize)76 SendCommunicateBuffer (
77   IN OUT  EFI_MM_COMMUNICATE_HEADER         *SmmCommunicateHeader,
78   IN      UINTN                             DataSize
79   )
80 {
81   EFI_STATUS                                Status;
82   UINTN                                     CommSize;
83   SMM_FTW_COMMUNICATE_FUNCTION_HEADER       *SmmFtwFunctionHeader;
84 
85   CommSize = DataSize + SMM_COMMUNICATE_HEADER_SIZE + SMM_FTW_COMMUNICATE_HEADER_SIZE;
86   Status = mMmCommunication2->Communicate (mMmCommunication2,
87                                            SmmCommunicateHeader,
88                                            SmmCommunicateHeader,
89                                            &CommSize);
90   ASSERT_EFI_ERROR (Status);
91 
92   SmmFtwFunctionHeader = (SMM_FTW_COMMUNICATE_FUNCTION_HEADER *) SmmCommunicateHeader->Data;
93   return  SmmFtwFunctionHeader->ReturnStatus;
94 }
95 
96 
97 /**
98   Get the FvbBaseAddress and FvbAttributes from the FVB handle FvbHandle.
99 
100   @param[in]   FvbHandle         The handle of FVB protocol that provides services.
101   @param[out]  FvbBaseAddress    The base address of the FVB attached with FvbHandle.
102   @param[out]  FvbAttributes     The attributes of the FVB attached with FvbHandle.
103 
104   @retval EFI_SUCCESS            The function completed successfully.
105   @retval Others                 The function could not complete successfully.
106 
107 **/
108 EFI_STATUS
ConvertFvbHandle(IN EFI_HANDLE FvbHandle,OUT EFI_PHYSICAL_ADDRESS * FvbBaseAddress,OUT EFI_FVB_ATTRIBUTES_2 * FvbAttributes)109 ConvertFvbHandle (
110   IN  EFI_HANDLE                            FvbHandle,
111   OUT EFI_PHYSICAL_ADDRESS                  *FvbBaseAddress,
112   OUT EFI_FVB_ATTRIBUTES_2                  *FvbAttributes
113   )
114 {
115   EFI_STATUS                                Status;
116   EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL        *Fvb;
117 
118   Status = gBS->HandleProtocol (FvbHandle, &gEfiFirmwareVolumeBlockProtocolGuid, (VOID **) &Fvb);
119   if (EFI_ERROR (Status)) {
120     return Status;
121   }
122 
123   Status = Fvb->GetPhysicalAddress (Fvb, FvbBaseAddress);
124   if (EFI_ERROR (Status)) {
125     return Status;
126   }
127 
128   Status = Fvb->GetAttributes (Fvb, FvbAttributes);
129   return Status;
130 }
131 
132 
133 /**
134   Get the size of the largest block that can be updated in a fault-tolerant manner.
135 
136   @param[in]  This             Indicates a pointer to the calling context.
137   @param[out] BlockSize        A pointer to a caller-allocated UINTN that is
138                                updated to indicate the size of the largest block
139                                that can be updated.
140 
141   @retval EFI_SUCCESS          The function completed successfully.
142   @retval EFI_ABORTED          The function could not complete successfully.
143 
144 **/
145 EFI_STATUS
146 EFIAPI
FtwGetMaxBlockSize(IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL * This,OUT UINTN * BlockSize)147 FtwGetMaxBlockSize (
148   IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL      *This,
149   OUT UINTN                                 *BlockSize
150   )
151 {
152   EFI_STATUS                                Status;
153   UINTN                                     PayloadSize;
154   EFI_MM_COMMUNICATE_HEADER                 *SmmCommunicateHeader;
155   SMM_FTW_GET_MAX_BLOCK_SIZE_HEADER         *SmmFtwBlockSizeHeader;
156 
157   //
158   // Initialize the communicate buffer.
159   //
160   PayloadSize  = sizeof (SMM_FTW_GET_MAX_BLOCK_SIZE_HEADER);
161   InitCommunicateBuffer ((VOID **)&SmmCommunicateHeader, (VOID **)&SmmFtwBlockSizeHeader, PayloadSize, FTW_FUNCTION_GET_MAX_BLOCK_SIZE);
162 
163   //
164   // Send data to SMM.
165   //
166   Status = SendCommunicateBuffer (SmmCommunicateHeader, PayloadSize);
167 
168   //
169   // Get data from SMM
170   //
171   *BlockSize = SmmFtwBlockSizeHeader->BlockSize;
172   FreePool (SmmCommunicateHeader);
173 
174   return Status;
175 }
176 
177 
178 /**
179   Allocates space for the protocol to maintain information about writes.
180   Since writes must be completed in a fault-tolerant manner and multiple
181   writes require more resources to be successful, this function
182   enables the protocol to ensure that enough space exists to track
183   information about upcoming writes.
184 
185   @param[in]  This             A pointer to the calling context.
186   @param[in]  CallerId         The GUID identifying the write.
187   @param[in]  PrivateDataSize  The size of the caller's private data  that must be
188                                recorded for each write.
189   @param[in]  NumberOfWrites   The number of fault tolerant block writes that will
190                                need to occur.
191 
192   @retval EFI_SUCCESS          The function completed successfully
193   @retval EFI_ABORTED          The function could not complete successfully.
194   @retval EFI_ACCESS_DENIED    Not all allocated writes have been completed.  All
195                                writes must be completed or aborted before another
196                                fault tolerant write can occur.
197 
198 **/
199 EFI_STATUS
200 EFIAPI
FtwAllocate(IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL * This,IN EFI_GUID * CallerId,IN UINTN PrivateDataSize,IN UINTN NumberOfWrites)201 FtwAllocate (
202   IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL      *This,
203   IN EFI_GUID                               *CallerId,
204   IN UINTN                                  PrivateDataSize,
205   IN UINTN                                  NumberOfWrites
206   )
207 {
208   EFI_STATUS                                Status;
209   UINTN                                     PayloadSize;
210   EFI_MM_COMMUNICATE_HEADER                 *SmmCommunicateHeader;
211   SMM_FTW_ALLOCATE_HEADER                   *SmmFtwAllocateHeader;
212 
213   //
214   // Initialize the communicate buffer.
215   //
216   PayloadSize  = sizeof (SMM_FTW_ALLOCATE_HEADER);
217   InitCommunicateBuffer ((VOID **)&SmmCommunicateHeader, (VOID **)&SmmFtwAllocateHeader, PayloadSize, FTW_FUNCTION_ALLOCATE);
218   CopyGuid (&SmmFtwAllocateHeader->CallerId, CallerId);
219   SmmFtwAllocateHeader->PrivateDataSize = PrivateDataSize;
220   SmmFtwAllocateHeader->NumberOfWrites  = NumberOfWrites;
221 
222   //
223   // Send data to SMM.
224   //
225   Status = SendCommunicateBuffer (SmmCommunicateHeader, PayloadSize);
226   if (!EFI_ERROR( Status)) {
227     mPrivateDataSize = PrivateDataSize;
228   }
229 
230   FreePool (SmmCommunicateHeader);
231   return Status;
232 }
233 
234 
235 /**
236   Starts a target block update. This records information about the write
237   in fault tolerant storage, and will complete the write in a recoverable
238   manner, ensuring at all times that either the original contents or
239   the modified contents are available.
240 
241   @param[in]  This             The calling context.
242   @param[in]  Lba              The logical block address of the target block.
243   @param[in]  Offset           The offset within the target block to place the
244                                data.
245   @param[in]  Length           The number of bytes to write to the target block.
246   @param[in]  PrivateData      A pointer to private data that the caller requires
247                                to complete any pending writes in the event of a
248                                fault.
249   @param[in]  FvBlockHandle    The handle of FVB protocol that provides services
250                                for reading, writing, and erasing the target block.
251   @param[in]  Buffer           The data to write.
252 
253   @retval EFI_SUCCESS          The function completed successfully.
254   @retval EFI_ABORTED          The function could not complete successfully.
255   @retval EFI_BAD_BUFFER_SIZE  The write would span a block boundary, which is not
256                                a valid action.
257   @retval EFI_ACCESS_DENIED    No writes have been allocated.
258   @retval EFI_NOT_READY        The last write has not been completed. Restart()
259                                must be called to complete it.
260 
261 **/
262 EFI_STATUS
263 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)264 FtwWrite (
265   IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL      *This,
266   IN EFI_LBA                                Lba,
267   IN UINTN                                  Offset,
268   IN UINTN                                  Length,
269   IN VOID                                   *PrivateData,
270   IN EFI_HANDLE                             FvBlockHandle,
271   IN VOID                                   *Buffer
272   )
273 {
274   EFI_STATUS                                Status;
275   UINTN                                     PayloadSize;
276   EFI_MM_COMMUNICATE_HEADER                 *SmmCommunicateHeader;
277   SMM_FTW_WRITE_HEADER                      *SmmFtwWriteHeader;
278 
279   //
280   // Initialize the communicate buffer.
281   //
282   PayloadSize  = OFFSET_OF (SMM_FTW_WRITE_HEADER, Data) + Length;
283   if (PrivateData != NULL) {
284     //
285     // The private data buffer size should be the same one in FtwAllocate API.
286     //
287     PayloadSize += mPrivateDataSize;
288   }
289   InitCommunicateBuffer ((VOID **)&SmmCommunicateHeader, (VOID **)&SmmFtwWriteHeader, PayloadSize, FTW_FUNCTION_WRITE);
290 
291   //
292   // FvBlockHandle can not be used in SMM environment. Here we get the FVB protocol first, then get FVB base address
293   // and its attribute. Send these information to SMM handler, the SMM handler will find the proper FVB to write data.
294   //
295   Status = ConvertFvbHandle (FvBlockHandle, &SmmFtwWriteHeader->FvbBaseAddress, &SmmFtwWriteHeader->FvbAttributes);
296   if (EFI_ERROR (Status)) {
297     FreePool (SmmCommunicateHeader);
298     return EFI_ABORTED;
299   }
300 
301   SmmFtwWriteHeader->Lba    = Lba;
302   SmmFtwWriteHeader->Offset = Offset;
303   SmmFtwWriteHeader->Length = Length;
304   CopyMem (SmmFtwWriteHeader->Data, Buffer, Length);
305   if (PrivateData == NULL) {
306     SmmFtwWriteHeader->PrivateDataSize = 0;
307   } else {
308     SmmFtwWriteHeader->PrivateDataSize = mPrivateDataSize;
309     CopyMem (&SmmFtwWriteHeader->Data[Length], PrivateData, mPrivateDataSize);
310   }
311 
312   //
313   // Send data to SMM.
314   //
315   Status = SendCommunicateBuffer (SmmCommunicateHeader, PayloadSize);
316   FreePool (SmmCommunicateHeader);
317   return Status;
318 }
319 
320 
321 /**
322   Restarts a previously interrupted write. The caller must provide the
323   block protocol needed to complete the interrupted write.
324 
325   @param[in]  This             The calling context.
326   @param[in]  FvBlockHandle    The handle of FVB protocol that provides services.
327 
328   @retval EFI_SUCCESS          The function completed successfully.
329   @retval EFI_ABORTED          The function could not complete successfully.
330   @retval EFI_ACCESS_DENIED    No pending writes exist.
331 
332 **/
333 EFI_STATUS
334 EFIAPI
FtwRestart(IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL * This,IN EFI_HANDLE FvBlockHandle)335 FtwRestart (
336   IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL      *This,
337   IN EFI_HANDLE                             FvBlockHandle
338   )
339 {
340   EFI_STATUS                                Status;
341   UINTN                                     PayloadSize;
342   EFI_MM_COMMUNICATE_HEADER                 *SmmCommunicateHeader;
343   SMM_FTW_RESTART_HEADER                    *SmmFtwRestartHeader;
344 
345   //
346   // Initialize the communicate buffer.
347   //
348   PayloadSize  = sizeof (SMM_FTW_RESTART_HEADER);
349   InitCommunicateBuffer ((VOID **)&SmmCommunicateHeader, (VOID **)&SmmFtwRestartHeader, PayloadSize, FTW_FUNCTION_RESTART);
350 
351   //
352   // FvBlockHandle can not be used in SMM environment. Here we get the FVB protocol first, then get FVB base address
353   // and its attribute. Send these information to SMM handler, the SMM handler will find the proper FVB to write data.
354   //
355   Status = ConvertFvbHandle (FvBlockHandle, &SmmFtwRestartHeader->FvbBaseAddress, &SmmFtwRestartHeader->FvbAttributes);
356   if (EFI_ERROR (Status)) {
357     FreePool (SmmCommunicateHeader);
358     return EFI_ABORTED;
359   }
360 
361   //
362   // Send data to SMM.
363   //
364   Status = SendCommunicateBuffer (SmmCommunicateHeader, PayloadSize);
365   FreePool (SmmCommunicateHeader);
366   return Status;
367 }
368 
369 
370 /**
371   Aborts all previously allocated writes.
372 
373   @param[in]  This             The calling context.
374 
375   @retval EFI_SUCCESS          The function completed successfully.
376   @retval EFI_ABORTED          The function could not complete successfully.
377   @retval EFI_NOT_FOUND        No allocated writes exist.
378 
379 **/
380 EFI_STATUS
381 EFIAPI
FtwAbort(IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL * This)382 FtwAbort (
383   IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL      *This
384   )
385 {
386   EFI_STATUS                                Status;
387   EFI_MM_COMMUNICATE_HEADER                 *SmmCommunicateHeader;
388 
389   //
390   // Initialize the communicate buffer.
391   //
392   InitCommunicateBuffer ((VOID **)&SmmCommunicateHeader, NULL, 0, FTW_FUNCTION_ABORT);
393 
394   //
395   // Send data to SMM.
396   //
397   Status = SendCommunicateBuffer (SmmCommunicateHeader, 0);
398 
399   FreePool (SmmCommunicateHeader);
400   return Status;
401 }
402 
403 
404 /**
405   Starts a target block update. This function records information about the write
406   in fault-tolerant storage and completes the write in a recoverable
407   manner, ensuring at all times that either the original contents or
408   the modified contents are available.
409 
410   @param[in]      This            Indicates a pointer to the calling context.
411   @param[out]     CallerId        The GUID identifying the last write.
412   @param[out]     Lba             The logical block address of the last write.
413   @param[out]     Offset          The offset within the block of the last write.
414   @param[out]     Length          The length of the last write.
415   @param[in, out] PrivateDataSize On input, the size of the PrivateData buffer. On
416                                   output, the size of the private data stored for
417                                   this write.
418   @param[out]     PrivateData     A pointer to a buffer. The function will copy
419                                   PrivateDataSize bytes from the private data stored
420                                   for this write.
421   @param[out]     Complete        A Boolean value with TRUE indicating that the write
422                                   was completed.
423 
424   @retval EFI_SUCCESS             The function completed successfully.
425   @retval EFI_ABORTED             The function could not complete successfully.
426   @retval EFI_NOT_FOUND           No allocated writes exist.
427 
428 **/
429 EFI_STATUS
430 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)431 FtwGetLastWrite (
432   IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL      *This,
433   OUT EFI_GUID                              *CallerId,
434   OUT EFI_LBA                               *Lba,
435   OUT UINTN                                 *Offset,
436   OUT UINTN                                 *Length,
437   IN OUT UINTN                              *PrivateDataSize,
438   OUT VOID                                  *PrivateData,
439   OUT BOOLEAN                               *Complete
440   )
441 {
442   EFI_STATUS                                Status;
443   UINTN                                     PayloadSize;
444   EFI_MM_COMMUNICATE_HEADER                 *SmmCommunicateHeader;
445   SMM_FTW_GET_LAST_WRITE_HEADER             *SmmFtwGetLastWriteHeader;
446 
447   //
448   // Initialize the communicate buffer.
449   //
450   PayloadSize  = OFFSET_OF (SMM_FTW_GET_LAST_WRITE_HEADER, Data) + *PrivateDataSize;
451   InitCommunicateBuffer ((VOID **)&SmmCommunicateHeader, (VOID **)&SmmFtwGetLastWriteHeader, PayloadSize, FTW_FUNCTION_GET_LAST_WRITE);
452   SmmFtwGetLastWriteHeader->PrivateDataSize = *PrivateDataSize;
453 
454   //
455   // Send data to SMM.
456   //
457   Status = SendCommunicateBuffer (SmmCommunicateHeader, PayloadSize);
458 
459   //
460   // Get data from SMM
461   //
462   *PrivateDataSize = SmmFtwGetLastWriteHeader->PrivateDataSize;
463   if (Status == EFI_SUCCESS || Status == EFI_BUFFER_TOO_SMALL) {
464     *Lba      = SmmFtwGetLastWriteHeader->Lba;
465     *Offset   = SmmFtwGetLastWriteHeader->Offset;
466     *Length   = SmmFtwGetLastWriteHeader->Length;
467     *Complete = SmmFtwGetLastWriteHeader->Complete;
468     CopyGuid (CallerId, &SmmFtwGetLastWriteHeader->CallerId);
469     if (Status == EFI_SUCCESS) {
470       CopyMem (PrivateData, SmmFtwGetLastWriteHeader->Data, *PrivateDataSize);
471     }
472   } else if (Status == EFI_NOT_FOUND) {
473     *Complete = SmmFtwGetLastWriteHeader->Complete;
474   }
475 
476   FreePool (SmmCommunicateHeader);
477   return Status;
478 }
479 
480 /**
481   SMM Fault Tolerant Write Protocol notification event handler.
482 
483   Install Fault Tolerant Write Protocol.
484 
485   @param[in] Event    Event whose notification function is being invoked.
486   @param[in] Context  Pointer to the notification function's context.
487 **/
488 VOID
489 EFIAPI
SmmFtwReady(IN EFI_EVENT Event,IN VOID * Context)490 SmmFtwReady (
491   IN  EFI_EVENT                             Event,
492   IN  VOID                                  *Context
493   )
494 {
495   EFI_STATUS                                Status;
496   EFI_FAULT_TOLERANT_WRITE_PROTOCOL         *FtwProtocol;
497 
498   //
499   // Just return to avoid install SMM FaultTolerantWriteProtocol again
500   // if Fault Tolerant Write protocol had been installed.
501   //
502   Status = gBS->LocateProtocol (&gEfiFaultTolerantWriteProtocolGuid, NULL, (VOID **)&FtwProtocol);
503   if (!EFI_ERROR (Status)) {
504     return;
505   }
506 
507   Status = gBS->LocateProtocol (&gEfiMmCommunication2ProtocolGuid, NULL, (VOID **) &mMmCommunication2);
508   ASSERT_EFI_ERROR (Status);
509 
510   //
511   // Install protocol interface
512   //
513   Status = gBS->InstallProtocolInterface (
514                   &mHandle,
515                   &gEfiFaultTolerantWriteProtocolGuid,
516                   EFI_NATIVE_INTERFACE,
517                   &mFaultTolerantWriteDriver
518                   );
519   ASSERT_EFI_ERROR (Status);
520 
521   Status = gBS->CloseEvent (Event);
522   ASSERT_EFI_ERROR (Status);
523 }
524 
525 
526 /**
527   The driver entry point for Fault Tolerant Write driver.
528 
529   The function does the necessary initialization work.
530 
531   @param[in]  ImageHandle       The firmware allocated handle for the UEFI image.
532   @param[in]  SystemTable       A pointer to the EFI system table.
533 
534   @retval     EFI_SUCCESS       This funtion always return EFI_SUCCESS.
535 
536 **/
537 EFI_STATUS
538 EFIAPI
FaultTolerantWriteSmmInitialize(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)539 FaultTolerantWriteSmmInitialize (
540   IN EFI_HANDLE                             ImageHandle,
541   IN EFI_SYSTEM_TABLE                       *SystemTable
542   )
543 {
544   VOID                                      *SmmFtwRegistration;
545 
546   //
547   // Smm FTW driver is ready
548   //
549   EfiCreateProtocolNotifyEvent (
550     &gEfiSmmFaultTolerantWriteProtocolGuid,
551     TPL_CALLBACK,
552     SmmFtwReady,
553     NULL,
554     &SmmFtwRegistration
555     );
556 
557   return EFI_SUCCESS;
558 }
559 
560