]> git.proxmox.com Git - mirror_edk2.git/commitdiff
Add SMM Variable implementation.
authorgdong1 <gdong1@6f19259b-4bc3-4df7-8a09-765794883524>
Fri, 10 Dec 2010 09:27:54 +0000 (09:27 +0000)
committergdong1 <gdong1@6f19259b-4bc3-4df7-8a09-765794883524>
Fri, 10 Dec 2010 09:27:54 +0000 (09:27 +0000)
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@11151 6f19259b-4bc3-4df7-8a09-765794883524

24 files changed:
MdeModulePkg/Include/Guid/VariableFormat.h
MdeModulePkg/Include/Protocol/SmmFaultTolerantWrite.h [new file with mode: 0644]
MdeModulePkg/Include/Protocol/SmmFirmwareVolumeBlock.h [new file with mode: 0644]
MdeModulePkg/Include/Protocol/SmmSwapAddressRange.h [new file with mode: 0644]
MdeModulePkg/Include/Protocol/SmmVariable.h [new file with mode: 0644]
MdeModulePkg/MdeModulePkg.dec
MdeModulePkg/MdeModulePkg.dsc
MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWrite.c
MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWrite.h
MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.c [new file with mode: 0644]
MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf
MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.c [new file with mode: 0644]
MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.inf [new file with mode: 0644]
MdeModulePkg/Universal/FaultTolerantWriteDxe/FtwMisc.c
MdeModulePkg/Universal/Variable/RuntimeDxe/Reclaim.c
MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c
MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c [new file with mode: 0644]
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c [new file with mode: 0644]
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf [new file with mode: 0644]
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmCommon.h [new file with mode: 0644]
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c [new file with mode: 0644]
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf [new file with mode: 0644]

index 2276262a3b9a9c4b420d155ff89c9e8c2934160b..0db3a22f34ff4b409d9cd9be5ad09237d87a15c7 100644 (file)
@@ -157,4 +157,90 @@ struct _VARIABLE_INFO_ENTRY {
   BOOLEAN             Volatile;    ///< TRUE if volatile, FALSE if non-volatile.\r
 };\r
 \r
   BOOLEAN             Volatile;    ///< TRUE if volatile, FALSE if non-volatile.\r
 };\r
 \r
+//\r
+// This structure is used for SMM variable. the collected statistics data is saved in SMRAM. It can be got from \r
+// SMI handler. The communication buffer should be: \r
+// EFI_SMM_COMMUNICATE_HEADER + SMM_VARIABLE_COMMUNICATE_HEADER + payload.\r
+//\r
+typedef struct {\r
+  UINTN       Function;\r
+  EFI_STATUS  ReturnStatus;\r
+  UINT8       Data[1];\r
+} SMM_VARIABLE_COMMUNICATE_HEADER;\r
+\r
+//\r
+// The payload for this function is SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE.\r
+//\r
+#define SMM_VARIABLE_FUNCTION_GET_VARIABLE            1\r
+//\r
+// The payload for this function is SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME.\r
+// \r
+#define SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME  2\r
+//\r
+// The payload for this function is SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE.\r
+// \r
+#define SMM_VARIABLE_FUNCTION_SET_VARIABLE            3\r
+//\r
+// The payload for this function is SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO.\r
+// \r
+#define SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO     4\r
+//\r
+// It is a notify event, no extra payload for this function.\r
+// \r
+#define SMM_VARIABLE_FUNCTION_READY_TO_BOOT           5\r
+//\r
+// It is a notify event, no extra payload for this function.\r
+// \r
+#define SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE       6\r
+//\r
+// The payload for this function is VARIABLE_INFO_ENTRY. The GUID in EFI_SMM_COMMUNICATE_HEADER \r
+// is gEfiSmmVariableProtocolGuid.\r
+//\r
+#define SMM_VARIABLE_FUNCTION_GET_STATISTICS          7\r
+\r
+///\r
+/// Size of SMM communicate header, without including the payload.\r
+///\r
+#define SMM_COMMUNICATE_HEADER_SIZE  (OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data))\r
+\r
+///\r
+/// Size of SMM variable communicate header, without including the payload.\r
+///\r
+#define SMM_VARIABLE_COMMUNICATE_HEADER_SIZE  (OFFSET_OF (SMM_VARIABLE_COMMUNICATE_HEADER, Data))\r
+\r
+///\r
+/// This structure is used to communicate with SMI handler by SetVariable and GetVariable.\r
+///\r
+typedef struct {\r
+  EFI_GUID    Guid;\r
+  UINTN       DataSize;\r
+  UINTN       NameSize;\r
+  UINT32      Attributes;  \r
+  CHAR16      Name[1];\r
+} SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE;\r
+\r
+///\r
+/// This structure is used to communicate with SMI handler by GetNextVariableName.\r
+///\r
+typedef struct {\r
+  EFI_GUID    Guid;\r
+  UINTN       NameSize;\r
+  CHAR16      Name[1];\r
+} SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME;\r
+\r
+///\r
+/// This structure is used to communicate with SMI handler by QueryVariableInfo.\r
+///\r
+typedef struct {\r
+  UINT64          MaximumVariableStorageSize;\r
+  UINT64          RemainingVariableStorageSize;\r
+  UINT64          MaximumVariableSize;\r
+  UINT32          Attributes; \r
+} SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO;\r
+\r
+///\r
+/// This structure is used to communicate with SMI handler to get variable statistics information.\r
+///\r
+typedef VARIABLE_INFO_ENTRY  SMM_VARIABLE_COMMUNICATE_VARIABLE_INFO_ENTRY;\r
+\r
 #endif // _EFI_VARIABLE_H_\r
 #endif // _EFI_VARIABLE_H_\r
diff --git a/MdeModulePkg/Include/Protocol/SmmFaultTolerantWrite.h b/MdeModulePkg/Include/Protocol/SmmFaultTolerantWrite.h
new file mode 100644 (file)
index 0000000..a12e53b
--- /dev/null
@@ -0,0 +1,38 @@
+/** @file\r
+  SMM Fault Tolerant Write protocol is related to EDK II-specific implementation of FTW,\r
+  provides boot-time service for fault tolerant write capability for block devices in \r
+  EFI SMM environment.  The protocol provides for non-volatile storage of the intermediate \r
+  data and private information a caller would need to recover from a critical fault, \r
+  such as a power failure.   \r
+\r
+Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials are licensed and made available under \r
+the terms and conditions of the BSD License that accompanies this distribution.  \r
+The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php.                                            \r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
+\r
+**/\r
+\r
+#ifndef __SMM_FAULT_TOLERANT_WRITE_H__\r
+#define __SMM_FAULT_TOLERANT_WRITE_H__\r
+\r
+#include <Protocol/FaultTolerantWrite.h>\r
+\r
+#define EFI_SMM_FAULT_TOLERANT_WRITE_PROTOCOL_GUID \\r
+  { \\r
+    0x3868fc3b, 0x7e45, 0x43a7, { 0x90, 0x6c, 0x4b, 0xa4, 0x7d, 0xe1, 0x75, 0x4d } \\r
+  }\r
+\r
+//\r
+// SMM Fault Tolerant Write protocol structure is the same as Fault Tolerant Write protocol.  \r
+// The SMM one is intend to run in SMM environment, which means it can be used by \r
+// SMM drivers after ExitPmAuth. \r
+// \r
+typedef EFI_FAULT_TOLERANT_WRITE_PROTOCOL EFI_SMM_FAULT_TOLERANT_WRITE_PROTOCOL;\r
+\r
+extern EFI_GUID gEfiSmmFaultTolerantWriteProtocolGuid;\r
+\r
+#endif\r
diff --git a/MdeModulePkg/Include/Protocol/SmmFirmwareVolumeBlock.h b/MdeModulePkg/Include/Protocol/SmmFirmwareVolumeBlock.h
new file mode 100644 (file)
index 0000000..b04762b
--- /dev/null
@@ -0,0 +1,36 @@
+/** @file\r
+  SMM Firmware Volume Block protocol is related to EDK II-specific implementation of\r
+  FVB driver, provides control over block-oriented firmware devices and is intended \r
+  to use in the EFI SMM environment.\r
+\r
+Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials are licensed and made available under \r
+the terms and conditions of the BSD License that accompanies this distribution.  \r
+The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php.                                          \r
+    \r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             \r
+\r
+**/\r
+\r
+#ifndef __SMM_FIRMWARE_VOLUME_BLOCK_H__\r
+#define __SMM_FIRMWARE_VOLUME_BLOCK_H__\r
+\r
+#include <Protocol/FirmwareVolumeBlock.h>\r
+\r
+#define EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL_GUID \\r
+  { \\r
+    0xf52fc9ff, 0x8025, 0x4432, { 0xa5, 0x3b, 0xb4, 0x7b, 0x5e, 0x9, 0xdb, 0xf9 } \\r
+  }\r
+\r
+//\r
+// SMM Firmware Volume Block protocol structure is the same as Firmware Volume Block \r
+// protocol. The SMM one is intend to run in SMM environment, which means it can be  \r
+// used by SMM drivers after ExitPmAuth. \r
+// \r
+typedef EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL;\r
+\r
+extern EFI_GUID gEfiSmmFirmwareVolumeBlockProtocolGuid;\r
+\r
+#endif\r
diff --git a/MdeModulePkg/Include/Protocol/SmmSwapAddressRange.h b/MdeModulePkg/Include/Protocol/SmmSwapAddressRange.h
new file mode 100644 (file)
index 0000000..60a0a2c
--- /dev/null
@@ -0,0 +1,40 @@
+/** @file\r
+  The EFI_SMM_SWAP_ADDRESS_RANGE_PROTOCOL is related to EDK II-specific implementation \r
+  and used to abstract the swap operation of boot block and backup block of FV in EFI \r
+  SMM environment. This swap is especially needed when updating the boot block of FV. \r
+  If a power failure happens during the boot block update, the swapped backup block \r
+  (now the boot block) can boot the machine with the old boot block backed up in it. \r
+  The swap operation is platform dependent, so other protocols such as SMM FTW (Fault \r
+  Tolerant Write) should use this protocol instead of handling hardware directly.\r
+\r
+Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials are licensed and made available under \r
+the terms and conditions of the BSD License that accompanies this distribution.  \r
+The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php.                                            \r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
+\r
+**/\r
+\r
+#ifndef __SMM_SWAP_ADDRESS_RANGE_H__\r
+#define __SMM_SWAP_ADDRESS_RANGE_H__\r
+\r
+#include <Protocol/SwapAddressRange.h>\r
+\r
+#define EFI_SMM_SWAP_ADDRESS_RANGE_PROTOCOL_GUID \\r
+  { \\r
+    0x67c4f112, 0x3385, 0x4e55, { 0x9c, 0x5b, 0xc0, 0x5b, 0x71, 0x7c, 0x42, 0x28 } \\r
+  }\r
+\r
+//\r
+// SMM Swap Address Range protocol structure is the same as Swap Address Range protocol.  \r
+// The SMM one is intend to run in SMM environment, which means it can be used by \r
+// SMM drivers after ExitPmAuth. \r
+// \r
+typedef EFI_SWAP_ADDRESS_RANGE_PROTOCOL EFI_SMM_SWAP_ADDRESS_RANGE_PROTOCOL;\r
+\r
+extern EFI_GUID gEfiSmmSwapAddressRangeProtocolGuid;\r
+\r
+#endif\r
diff --git a/MdeModulePkg/Include/Protocol/SmmVariable.h b/MdeModulePkg/Include/Protocol/SmmVariable.h
new file mode 100644 (file)
index 0000000..75ab6c3
--- /dev/null
@@ -0,0 +1,39 @@
+/** @file\r
+  EFI SMM Variable Protocol is related to EDK II-specific implementation of variables\r
+  and intended for use as a means to store data in the EFI SMM environment.\r
+\r
+  Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials                          \r
+  are licensed and made available under the terms and conditions of the BSD License         \r
+  which accompanies this distribution.  The full text of the license may be found at        \r
+  http://opensource.org/licenses/bsd-license.php                                            \r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             \r
+\r
+**/\r
+\r
+#ifndef __SMM_VARIABLE_H__\r
+#define __SMM_VARIABLE_H__\r
+\r
+#define EFI_SMM_VARIABLE_PROTOCOL_GUID \\r
+  { \\r
+    0xed32d533, 0x99e6, 0x4209, { 0x9c, 0xc0, 0x2d, 0x72, 0xcd, 0xd9, 0x98, 0xa7 } \\r
+  }\r
+\r
+typedef struct _EFI_SMM_VARIABLE_PROTOCOL  EFI_SMM_VARIABLE_PROTOCOL;\r
+\r
+///\r
+/// EFI SMM Variable Protocol is intended for use as a means \r
+/// to store data in the EFI SMM environment.\r
+///\r
+struct _EFI_SMM_VARIABLE_PROTOCOL {\r
+  EFI_GET_VARIABLE            SmmGetVariable;\r
+  EFI_GET_NEXT_VARIABLE_NAME  SmmGetNextVariableName;\r
+  EFI_SET_VARIABLE            SmmSetVariable;\r
+  EFI_QUERY_VARIABLE_INFO     SmmQueryVariableInfo;\r
+};\r
+\r
+extern EFI_GUID gEfiSmmVariableProtocolGuid;\r
+\r
+#endif  \r
index 29aec9348b0a1905ed5c51a47f141f6fd2624a8d..0530f91180f1d076f0bc5a1baee6a404de543650 100644 (file)
   #  Include/Protocol/FaultTolerantWrite.h\r
   gEfiFaultTolerantWriteProtocolGuid = { 0x3EBD9E82, 0x2C78, 0x4DE6, { 0x97, 0x86, 0x8D, 0x4B, 0xFC, 0xB7, 0xC8, 0x81 }}\r
 \r
   #  Include/Protocol/FaultTolerantWrite.h\r
   gEfiFaultTolerantWriteProtocolGuid = { 0x3EBD9E82, 0x2C78, 0x4DE6, { 0x97, 0x86, 0x8D, 0x4B, 0xFC, 0xB7, 0xC8, 0x81 }}\r
 \r
+  ## This protocol provides boot-time service to do fault tolerant write capability for block devices in SMM environment.\r
+  #  Include/Protocol/SmmFaultTolerantWrite.h\r
+  gEfiSmmFaultTolerantWriteProtocolGuid = { 0x3868fc3b, 0x7e45, 0x43a7, { 0x90, 0x6c, 0x4b, 0xa4, 0x7d, 0xe1, 0x75, 0x4d }}\r
+  \r
   ## This protocol is used to abstract the swap operation of boot block and backup block of boot FV.\r
   #  Include/Protocol/SwapAddressRange.h\r
   gEfiSwapAddressRangeProtocolGuid = { 0x1259F60D, 0xB754, 0x468E, { 0xA7, 0x89, 0x4D, 0xB8, 0x5D, 0x55, 0xE8, 0x7E }}\r
   ## This protocol is used to abstract the swap operation of boot block and backup block of boot FV.\r
   #  Include/Protocol/SwapAddressRange.h\r
   gEfiSwapAddressRangeProtocolGuid = { 0x1259F60D, 0xB754, 0x468E, { 0xA7, 0x89, 0x4D, 0xB8, 0x5D, 0x55, 0xE8, 0x7E }}\r
+  \r
+  ## This protocol is used to abstract the swap operation of boot block and backup block of boot FV in SMM environment.\r
+  #  Include/Protocol/SmmSwapAddressRange.h\r
+  gEfiSmmSwapAddressRangeProtocolGuid = { 0x67c4f112, 0x3385, 0x4e55, { 0x9c, 0x5b, 0xc0, 0x5b, 0x71, 0x7c, 0x42, 0x28 }}\r
+  \r
+  ## This protocol is intended for use as a means to store data in the EFI SMM environment.\r
+  #  Include/Protocol/SmmVariableProtocol.h\r
+  gEfiSmmVariableProtocolGuid = { 0xed32d533, 0x99e6, 0x4209, { 0x9c, 0xc0, 0x2d, 0x72, 0xcd, 0xd9, 0x98, 0xa7 }}\r
+\r
+  ## This protocol is similar with DXE FVB protocol and used in the UEFI SMM evvironment.\r
+  #  Include/Protocol/SmmFirmwareVolumeBlock.h\r
+  gEfiSmmFirmwareVolumeBlockProtocolGuid = { 0xd326d041, 0xbd31, 0x4c01, { 0xb5, 0xa8, 0x62, 0x8b, 0xe8, 0x7f, 0x6, 0x53 }}\r
 \r
 [PcdsFeatureFlag]\r
   ## Indicate whether platform can support update capsule across a system reset\r
 \r
 [PcdsFeatureFlag]\r
   ## Indicate whether platform can support update capsule across a system reset\r
   #  interrupt to access usb device in the case of absence of usb stack. \r
   #  DUET platform requires the token to be TRUE.\r
   gEfiMdeModulePkgTokenSpaceGuid.PcdTurnOffUsbLegacySupport|FALSE|BOOLEAN|0x00010047\r
   #  interrupt to access usb device in the case of absence of usb stack. \r
   #  DUET platform requires the token to be TRUE.\r
   gEfiMdeModulePkgTokenSpaceGuid.PcdTurnOffUsbLegacySupport|FALSE|BOOLEAN|0x00010047\r
+  \r
+  ## If TRUE, the variable services are provided in DXE_SMM. The SMM driver can use SMM variable protocol \r
+  #  to access variable. Otherwise the variable services are provided in DXE_RUNTIME.\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSmmVariableEnable|TRUE|BOOLEAN|0x00010048\r
 \r
   ## If TRUE, HiiImageProtocol will be installed.\r
   #  FALSE is for size reduction.\r
 \r
   ## If TRUE, HiiImageProtocol will be installed.\r
   #  FALSE is for size reduction.\r
index 0f2fbd7975ccaaf0e7e7780dc48da98df128e122..d8a3826ef762b3d49ab31563504f437d69355593 100644 (file)
   MdeModulePkg/Universal/Variable/Pei/VariablePei.inf\r
   MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimer.inf\r
   MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf\r
   MdeModulePkg/Universal/Variable/Pei/VariablePei.inf\r
   MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimer.inf\r
   MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf\r
+  MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.inf\r
 \r
   MdeModulePkg/Universal/Acpi/AcpiPlatformDxe/AcpiPlatformDxe.inf\r
   MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableDxe.inf\r
 \r
   MdeModulePkg/Universal/Acpi/AcpiPlatformDxe/AcpiPlatformDxe.inf\r
   MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableDxe.inf\r
 [Components.IA32, Components.X64]\r
   MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf\r
   MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf\r
 [Components.IA32, Components.X64]\r
   MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf\r
   MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf\r
+  MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf\r
+  MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf\r
   MdeModulePkg/Library/SmmReportStatusCodeLib/SmmReportStatusCodeLib.inf\r
   MdeModulePkg/Universal/StatusCodeHandler/Smm/StatusCodeHandlerSmm.inf\r
   MdeModulePkg/Universal/ReportStatusCodeRouter/Smm/ReportStatusCodeRouterSmm.inf\r
   MdeModulePkg/Library/SmmReportStatusCodeLib/SmmReportStatusCodeLib.inf\r
   MdeModulePkg/Universal/StatusCodeHandler/Smm/StatusCodeHandlerSmm.inf\r
   MdeModulePkg/Universal/ReportStatusCodeRouter/Smm/ReportStatusCodeRouterSmm.inf\r
index cf726097775f882e8cbc9e33f39736f985880e78..625737eac018affcae37b9f9e6843d9e93bfc1f7 100644 (file)
@@ -1,44 +1,7 @@
 /** @file\r
 \r
 /** @file\r
 \r
-  This is a simple fault tolerant write driver.\r
-\r
-  This boot service protocol only provides fault tolerant write capability for \r
-  block devices.  The protocol has internal non-volatile intermediate storage \r
-  of the data and private information. It should be able to recover \r
-  automatically from a critical fault, such as power failure. \r
-\r
-  The implementation uses an FTW (Fault Tolerant Write) Work Space. \r
-  This work space is a memory copy of the work space on the Working Block,\r
-  the size of the work space is the FTW_WORK_SPACE_SIZE bytes.\r
-  \r
-  The work space stores each write record as EFI_FTW_RECORD structure.\r
-  The spare block stores the write buffer before write to the target block.\r
-  \r
-  The write record has three states to specify the different phase of write operation.\r
-  1) WRITE_ALLOCATED is that the record is allocated in write space.\r
-     The information of write operation is stored in write record structure.\r
-  2) SPARE_COMPLETED is that the data from write buffer is writed into the spare block as the backup.\r
-  3) WRITE_COMPLETED is that the data is copied from the spare block to the target block.\r
-\r
-  This driver operates the data as the whole size of spare block.\r
-  It first read the SpareAreaLength data from the target block into the spare memory buffer.\r
-  Then copy the write buffer data into the spare memory buffer.\r
-  Then write the spare memory buffer into the spare block.\r
-  Final copy the data from the spare block to the target block.\r
-\r
-  To make this drive work well, the following conditions must be satisfied:\r
-  1. The write NumBytes data must be fit within Spare area. \r
-     Offset + NumBytes <= SpareAreaLength\r
-  2. The whole flash range has the same block size.\r
-  3. Working block is an area which contains working space in its last block and has the same size as spare block.\r
-  4. Working Block area must be in the single one Firmware Volume Block range which FVB protocol is produced on.  \r
-  5. Spare area must be in the single one Firmware Volume Block range which FVB protocol is produced on.\r
-  6. Any write data area (SpareAreaLength Area) which the data will be written into must be \r
-     in the single one Firmware Volume Block range which FVB protocol is produced on.\r
-  7. If write data area (such as Variable range) is enlarged, the spare area range must be enlarged.\r
-     The spare area must be enough large to store the write data before write them into the target range.\r
-  If one of them is not satisfied, FtwWrite may fail.\r
-  Usually, Spare area only takes one block. That's SpareAreaLength = BlockSize, NumberOfSpareBlock = 1.\r
+  These are the common Fault Tolerant Write (FTW) functions that are shared \r
+  by DXE FTW driver and SMM FTW driver.\r
 \r
 Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
 This program and the accompanying materials                          \r
 \r
 Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
 This program and the accompanying materials                          \r
@@ -53,8 +16,6 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 \r
 #include "FaultTolerantWrite.h"\r
 \r
 \r
 #include "FaultTolerantWrite.h"\r
 \r
-EFI_EVENT          mFvbRegistration = NULL;\r
-\r
 //\r
 // Fault Tolerant Write Protocol API\r
 //\r
 //\r
 // Fault Tolerant Write Protocol API\r
 //\r
@@ -237,7 +198,7 @@ FtwWriteRecord (
 \r
   //\r
   // Spare Complete but Destination not complete,\r
 \r
   //\r
   // Spare Complete but Destination not complete,\r
-  // Recover the targt block with the spare block.\r
+  // Recover the target block with the spare block.\r
   //\r
   Header  = FtwDevice->FtwLastWriteHeader;\r
   Record  = FtwDevice->FtwLastWriteRecord;\r
   //\r
   Header  = FtwDevice->FtwLastWriteHeader;\r
   Record  = FtwDevice->FtwLastWriteRecord;\r
@@ -864,390 +825,3 @@ FtwGetLastWrite (
   return Status;\r
 }\r
 \r
   return Status;\r
 }\r
 \r
-/**\r
-  Firmware Volume Block Protocol notification event handler.\r
-\r
-  Initialization for Fault Tolerant Write is done in this handler.\r
-\r
-  @param[in] Event    Event whose notification function is being invoked.\r
-  @param[in] Context  Pointer to the notification function's context.\r
-**/\r
-VOID\r
-EFIAPI\r
-FvbNotificationEvent (\r
-  IN  EFI_EVENT       Event,\r
-  IN  VOID            *Context\r
-  )\r
-{\r
-  EFI_STATUS                          Status;\r
-  EFI_HANDLE                          *HandleBuffer;\r
-  UINTN                               HandleCount;\r
-  UINTN                               Index;\r
-  EFI_PHYSICAL_ADDRESS                FvbBaseAddress;\r
-  EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *Fvb;\r
-  EFI_FIRMWARE_VOLUME_HEADER          *FwVolHeader;\r
-  EFI_FVB_ATTRIBUTES_2                Attributes;\r
-  EFI_FTW_DEVICE                      *FtwDevice;\r
-  EFI_FV_BLOCK_MAP_ENTRY              *FvbMapEntry;\r
-  UINT32                              LbaIndex;\r
-  UINTN                               Length;\r
-  EFI_FAULT_TOLERANT_WRITE_HEADER     *FtwHeader;\r
-  UINTN                               Offset;\r
-  EFI_HANDLE                          FvbHandle;\r
-\r
-  FtwDevice = (EFI_FTW_DEVICE *)Context;\r
-  FvbHandle = NULL;\r
-  Fvb       = NULL;\r
-\r
-  FtwDevice->WorkSpaceAddress = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageFtwWorkingBase64);\r
-  if (FtwDevice->WorkSpaceAddress == 0) {\r
-    FtwDevice->WorkSpaceAddress = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageFtwWorkingBase);\r
-  }\r
-  \r
-  FtwDevice->SpareAreaAddress = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageFtwSpareBase64);\r
-  if (FtwDevice->SpareAreaAddress == 0) {\r
-    FtwDevice->SpareAreaAddress = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageFtwSpareBase);\r
-  }\r
-  \r
-  \r
-  //\r
-  // Locate all handles of Fvb protocol\r
-  //\r
-  Status = gBS->LocateHandleBuffer (\r
-                ByProtocol,\r
-                &gEfiFirmwareVolumeBlockProtocolGuid,\r
-                NULL,\r
-                &HandleCount,\r
-                &HandleBuffer\r
-                );\r
-  if (EFI_ERROR (Status)) {\r
-    return;\r
-  }\r
-\r
-  //\r
-  // Get the FVB to access variable store\r
-  //\r
-  for (Index = 0; Index < HandleCount; Index += 1) {\r
-    Status = gBS->HandleProtocol (\r
-                  HandleBuffer[Index],\r
-                  &gEfiFirmwareVolumeBlockProtocolGuid,\r
-                  (VOID **) &Fvb\r
-                  );\r
-    if (EFI_ERROR (Status)) {\r
-      Status = EFI_NOT_FOUND;\r
-      break;\r
-    }\r
-\r
-    //\r
-    // Ensure this FVB protocol supported Write operation.\r
-    //\r
-    Status = Fvb->GetAttributes (Fvb, &Attributes);\r
-    if (EFI_ERROR (Status) || ((Attributes & EFI_FVB2_WRITE_STATUS) == 0)) {\r
-      continue;     \r
-    }\r
-    //\r
-    // Compare the address and select the right one\r
-    //\r
-    Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress);\r
-    if (EFI_ERROR (Status)) {\r
-      continue;\r
-    }\r
-\r
-    FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvbBaseAddress);\r
-    if ((FtwDevice->FtwFvBlock == NULL) && (FtwDevice->WorkSpaceAddress >= FvbBaseAddress) &&\r
-      ((FtwDevice->WorkSpaceAddress + FtwDevice->WorkSpaceLength) <= (FvbBaseAddress + FwVolHeader->FvLength))\r
-      ) {\r
-      FtwDevice->FtwFvBlock = Fvb;\r
-      //\r
-      // To get the LBA of work space\r
-      //\r
-      if ((FwVolHeader->FvLength) > (FwVolHeader->HeaderLength)) {\r
-        //\r
-        // Now, one FV has one type of BlockLength\r
-        //\r
-        FvbMapEntry = &FwVolHeader->BlockMap[0];\r
-        for (LbaIndex = 1; LbaIndex <= FvbMapEntry->NumBlocks; LbaIndex += 1) {\r
-          if ((FtwDevice->WorkSpaceAddress >= (FvbBaseAddress + FvbMapEntry->Length * (LbaIndex - 1)))\r
-              && (FtwDevice->WorkSpaceAddress < (FvbBaseAddress + FvbMapEntry->Length * LbaIndex))) {\r
-            FtwDevice->FtwWorkSpaceLba = LbaIndex - 1;\r
-            //\r
-            // Get the Work space size and Base(Offset)\r
-            //\r
-            FtwDevice->FtwWorkSpaceSize = FtwDevice->WorkSpaceLength;\r
-            FtwDevice->FtwWorkSpaceBase = (UINTN) (FtwDevice->WorkSpaceAddress - (FvbBaseAddress + FvbMapEntry->Length * (LbaIndex - 1)));\r
-            break;\r
-          }\r
-        }\r
-      }\r
-    }\r
-    \r
-    if ((FtwDevice->FtwBackupFvb == NULL) && (FtwDevice->SpareAreaAddress >= FvbBaseAddress) &&\r
-      ((FtwDevice->SpareAreaAddress + FtwDevice->SpareAreaLength) <= (FvbBaseAddress + FwVolHeader->FvLength))\r
-      ) {\r
-      FtwDevice->FtwBackupFvb = Fvb;\r
-      //\r
-      // To get the LBA of spare\r
-      //\r
-      if ((FwVolHeader->FvLength) > (FwVolHeader->HeaderLength)) {\r
-        //\r
-        // Now, one FV has one type of BlockLength\r
-        //\r
-        FvbMapEntry = &FwVolHeader->BlockMap[0];\r
-        for (LbaIndex = 1; LbaIndex <= FvbMapEntry->NumBlocks; LbaIndex += 1) {\r
-          if ((FtwDevice->SpareAreaAddress >= (FvbBaseAddress + FvbMapEntry->Length * (LbaIndex - 1)))\r
-              && (FtwDevice->SpareAreaAddress < (FvbBaseAddress + FvbMapEntry->Length * LbaIndex))) {\r
-            //\r
-            // Get the NumberOfSpareBlock and BlockSize\r
-            //\r
-            FtwDevice->FtwSpareLba   = LbaIndex - 1;\r
-            FtwDevice->BlockSize     = FvbMapEntry->Length;\r
-            FtwDevice->NumberOfSpareBlock = FtwDevice->SpareAreaLength / FtwDevice->BlockSize;\r
-            //\r
-            // Check the range of spare area to make sure that it's in FV range\r
-            //\r
-            if ((FtwDevice->FtwSpareLba + FtwDevice->NumberOfSpareBlock) > FvbMapEntry->NumBlocks) {\r
-              DEBUG ((EFI_D_ERROR, "Ftw: Spare area is out of FV range\n"));\r
-              ASSERT (FALSE);\r
-              return;\r
-            }\r
-            break;\r
-          }\r
-        }\r
-      }\r
-    }\r
-  }\r
-\r
-  if ((FtwDevice->FtwBackupFvb == NULL) || (FtwDevice->FtwFvBlock == NULL) ||\r
-    (FtwDevice->FtwWorkSpaceLba == (EFI_LBA) (-1)) || (FtwDevice->FtwSpareLba == (EFI_LBA) (-1))) {\r
-    return;\r
-  }\r
-\r
-  DEBUG ((EFI_D_INFO, "Ftw: Working and spare FVB is ready\n"));\r
-  //\r
-  // Calculate the start LBA of working block. Working block is an area which\r
-  // contains working space in its last block and has the same size as spare\r
-  // block, unless there are not enough blocks before the block that contains\r
-  // working space.\r
-  //\r
-  FtwDevice->FtwWorkBlockLba = FtwDevice->FtwWorkSpaceLba - FtwDevice->NumberOfSpareBlock + 1;\r
-  ASSERT ((INT64) (FtwDevice->FtwWorkBlockLba) >= 0); \r
-\r
-  //\r
-  // Initialize other parameters, and set WorkSpace as FTW_ERASED_BYTE.\r
-  //\r
-  FtwDevice->FtwWorkSpace = (UINT8 *) (FtwDevice + 1);\r
-  FtwDevice->FtwWorkSpaceHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *) FtwDevice->FtwWorkSpace;\r
-\r
-  FtwDevice->FtwLastWriteHeader = NULL;\r
-  FtwDevice->FtwLastWriteRecord = NULL;\r
-\r
-  //\r
-  // Refresh the working space data from working block\r
-  //\r
-  Status = WorkSpaceRefresh (FtwDevice);\r
-  ASSERT_EFI_ERROR (Status);\r
-  //\r
-  // If the working block workspace is not valid, try the spare block\r
-  //\r
-  if (!IsValidWorkSpace (FtwDevice->FtwWorkSpaceHeader)) {\r
-    //\r
-    // Read from spare block\r
-    //\r
-    Length = FtwDevice->FtwWorkSpaceSize;\r
-    Status = FtwDevice->FtwBackupFvb->Read (\r
-                    FtwDevice->FtwBackupFvb,\r
-                    FtwDevice->FtwSpareLba,\r
-                    FtwDevice->FtwWorkSpaceBase,\r
-                    &Length,\r
-                    FtwDevice->FtwWorkSpace\r
-                    );\r
-    ASSERT_EFI_ERROR (Status);\r
-\r
-    //\r
-    // If spare block is valid, then replace working block content.\r
-    //\r
-    if (IsValidWorkSpace (FtwDevice->FtwWorkSpaceHeader)) {\r
-      Status = FlushSpareBlockToWorkingBlock (FtwDevice);\r
-      DEBUG ((EFI_D_ERROR, "Ftw: Restart working block update in Init() - %r\n", Status));\r
-      FtwAbort (&FtwDevice->FtwInstance);\r
-      //\r
-      // Refresh work space.\r
-      //\r
-      Status = WorkSpaceRefresh (FtwDevice);\r
-      ASSERT_EFI_ERROR (Status);\r
-    } else {\r
-      DEBUG ((EFI_D_ERROR, "Ftw: Both are invalid, init workspace\n"));\r
-      //\r
-      // If both are invalid, then initialize work space.\r
-      //\r
-      SetMem (\r
-        FtwDevice->FtwWorkSpace,\r
-        FtwDevice->FtwWorkSpaceSize,\r
-        FTW_ERASED_BYTE\r
-        );\r
-      InitWorkSpaceHeader (FtwDevice->FtwWorkSpaceHeader);\r
-      //\r
-      // Initialize the work space\r
-      //\r
-      Status = FtwReclaimWorkSpace (FtwDevice, FALSE);\r
-      ASSERT_EFI_ERROR (Status);\r
-    }\r
-  }\r
-  //\r
-  // If the FtwDevice->FtwLastWriteRecord is 1st record of write header &&\r
-  // (! SpareComplete) THEN call Abort().\r
-  //\r
-  if ((FtwDevice->FtwLastWriteHeader->HeaderAllocated == FTW_VALID_STATE) &&\r
-    (FtwDevice->FtwLastWriteRecord->SpareComplete != FTW_VALID_STATE) &&\r
-    IsFirstRecordOfWrites (FtwDevice->FtwLastWriteHeader, FtwDevice->FtwLastWriteRecord)\r
-    ) {\r
-    DEBUG ((EFI_D_ERROR, "Ftw: Init.. find first record not SpareCompleted, abort()\n"));\r
-    FtwAbort (&FtwDevice->FtwInstance);\r
-  }\r
-  //\r
-  // If Header is incompleted and the last record has completed, then\r
-  // call Abort() to set the Header->Complete FLAG.\r
-  //\r
-  if ((FtwDevice->FtwLastWriteHeader->Complete != FTW_VALID_STATE) &&\r
-    (FtwDevice->FtwLastWriteRecord->DestinationComplete == FTW_VALID_STATE) &&\r
-    IsLastRecordOfWrites (FtwDevice->FtwLastWriteHeader, FtwDevice->FtwLastWriteRecord)\r
-    ) {\r
-    DEBUG ((EFI_D_ERROR, "Ftw: Init.. find last record completed but header not, abort()\n"));\r
-    FtwAbort (&FtwDevice->FtwInstance);\r
-  }\r
-  //\r
-  // To check the workspace buffer following last Write header/records is EMPTY or not.\r
-  // If it's not EMPTY, FTW also need to call reclaim().\r
-  //\r
-  FtwHeader = FtwDevice->FtwLastWriteHeader;\r
-  Offset    = (UINT8 *) FtwHeader - FtwDevice->FtwWorkSpace;\r
-  if (FtwDevice->FtwWorkSpace[Offset] != FTW_ERASED_BYTE) {\r
-    Offset += WRITE_TOTAL_SIZE (FtwHeader->NumberOfWrites, FtwHeader->PrivateDataSize);\r
-  }\r
-  \r
-  if (!IsErasedFlashBuffer (FtwDevice->FtwWorkSpace + Offset, FtwDevice->FtwWorkSpaceSize - Offset)) {\r
-    Status = FtwReclaimWorkSpace (FtwDevice, TRUE);\r
-    ASSERT_EFI_ERROR (Status);\r
-  }\r
-\r
-  //\r
-  // Restart if it's boot block\r
-  //\r
-  if ((FtwDevice->FtwLastWriteHeader->Complete != FTW_VALID_STATE) &&\r
-    (FtwDevice->FtwLastWriteRecord->SpareComplete == FTW_VALID_STATE)\r
-    ) {\r
-    if (FtwDevice->FtwLastWriteRecord->BootBlockUpdate == FTW_VALID_STATE) {\r
-      Status = FlushSpareBlockToBootBlock (FtwDevice);\r
-      DEBUG ((EFI_D_ERROR, "Ftw: Restart boot block update - %r\n", Status));\r
-      ASSERT_EFI_ERROR (Status);\r
-      FtwAbort (&FtwDevice->FtwInstance);\r
-    } else {\r
-      //\r
-      // if (SpareCompleted) THEN  Restart to fault tolerant write.\r
-      //\r
-      FvbHandle = GetFvbByAddress (FtwDevice->FtwLastWriteRecord->FvBaseAddress, &Fvb);\r
-      if (FvbHandle != NULL) {\r
-        Status = FtwRestart (&FtwDevice->FtwInstance, FvbHandle);\r
-        DEBUG ((EFI_D_ERROR, "FtwLite: Restart last write - %r\n", Status));\r
-        ASSERT_EFI_ERROR (Status);\r
-      }\r
-      FtwAbort (&FtwDevice->FtwInstance);\r
-    }\r
-  }\r
-  //\r
-  // Hook the protocol API\r
-  //\r
-  FtwDevice->FtwInstance.GetMaxBlockSize = FtwGetMaxBlockSize;\r
-  FtwDevice->FtwInstance.Allocate        = FtwAllocate;\r
-  FtwDevice->FtwInstance.Write           = FtwWrite;\r
-  FtwDevice->FtwInstance.Restart         = FtwRestart;\r
-  FtwDevice->FtwInstance.Abort           = FtwAbort;\r
-  FtwDevice->FtwInstance.GetLastWrite    = FtwGetLastWrite;\r
-  \r
-  //\r
-  // Install protocol interface\r
-  //\r
-  Status = gBS->InstallProtocolInterface (\r
-            &FtwDevice->Handle,\r
-            &gEfiFaultTolerantWriteProtocolGuid,\r
-            EFI_NATIVE_INTERFACE,\r
-            &FtwDevice->FtwInstance\r
-            );\r
-\r
-  ASSERT_EFI_ERROR (Status);\r
-  \r
-  //\r
-  // Close the notify event to avoid install FaultTolerantWriteProtocol again.\r
-  //\r
-  Status = gBS->CloseEvent (Event);    \r
-  ASSERT_EFI_ERROR (Status);\r
-  \r
-  return;\r
-}\r
-\r
-/**\r
-  This function is the entry point of the Fault Tolerant Write driver.\r
-\r
-  @param ImageHandle     A handle for the image that is initializing this driver\r
-  @param SystemTable     A pointer to the EFI system table\r
-\r
-  @return EFI_SUCCESS           FTW has finished the initialization\r
-  @retval EFI_NOT_FOUND         Locate FVB protocol error\r
-  @retval EFI_OUT_OF_RESOURCES  Allocate memory error\r
-  @retval EFI_VOLUME_CORRUPTED  Firmware volume is error\r
-  @retval EFI_ABORTED           FTW initialization error\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-InitializeFaultTolerantWrite (\r
-  IN EFI_HANDLE         ImageHandle,\r
-  IN EFI_SYSTEM_TABLE   *SystemTable\r
-  )\r
-{\r
-  EFI_FTW_DEVICE                      *FtwDevice;\r
-\r
-  //\r
-  // Allocate Private data of this driver,\r
-  // INCLUDING THE FtwWorkSpace[FTW_WORK_SPACE_SIZE].\r
-  //\r
-  FtwDevice = NULL;\r
-  FtwDevice = AllocateZeroPool (sizeof (EFI_FTW_DEVICE) + PcdGet32 (PcdFlashNvStorageFtwWorkingSize));\r
-  if (FtwDevice == NULL) {\r
-    return EFI_OUT_OF_RESOURCES;\r
-  }\r
-\r
-  ZeroMem (FtwDevice, sizeof (EFI_FTW_DEVICE));\r
-  FtwDevice->Signature = FTW_DEVICE_SIGNATURE;\r
-\r
-  //\r
-  // Initialize other parameters, and set WorkSpace as FTW_ERASED_BYTE.\r
-  //\r
-\r
-  FtwDevice->WorkSpaceLength  = (UINTN) PcdGet32 (PcdFlashNvStorageFtwWorkingSize);\r
-\r
-  FtwDevice->SpareAreaLength  = (UINTN) PcdGet32 (PcdFlashNvStorageFtwSpareSize);\r
-\r
-  if ((FtwDevice->WorkSpaceLength == 0) || (FtwDevice->SpareAreaLength == 0)) {\r
-    DEBUG ((EFI_D_ERROR, "Ftw: Workspace or Spare block does not exist!\n"));\r
-    FreePool (FtwDevice);\r
-    return EFI_OUT_OF_RESOURCES;\r
-  }\r
-  FtwDevice->FtwFvBlock       = NULL;\r
-  FtwDevice->FtwBackupFvb     = NULL;\r
-  FtwDevice->FtwWorkSpaceLba  = (EFI_LBA) (-1);\r
-  FtwDevice->FtwSpareLba      = (EFI_LBA) (-1);\r
-\r
-  //\r
-  // Register FvbNotificationEvent () notify function.\r
-  // \r
-  EfiCreateProtocolNotifyEvent (\r
-    &gEfiFirmwareVolumeBlockProtocolGuid,\r
-    TPL_CALLBACK,\r
-    FvbNotificationEvent,\r
-    (VOID *)FtwDevice,\r
-    &mFvbRegistration\r
-    );\r
-\r
-  return EFI_SUCCESS;\r
-}\r
index a75db426fd7abc3600f9089088bb16fca2d0c9fa..00ac5c9c987221c79db4264956423b0cba31e0f0 100644 (file)
@@ -3,7 +3,7 @@
   The internal header file includes the common header files, defines\r
   internal structure and functions used by FtwLite module.\r
 \r
   The internal header file includes the common header files, defines\r
   internal structure and functions used by FtwLite module.\r
 \r
-Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
 This program and the accompanying materials                          \r
 are licensed and made available under the terms and conditions of the BSD License         \r
 which accompanies this distribution.  The full text of the license may be found at        \r
 This program and the accompanying materials                          \r
 are licensed and made available under the terms and conditions of the BSD License         \r
 which accompanies this distribution.  The full text of the license may be found at        \r
@@ -670,4 +670,71 @@ GetFvbByAddress (
   OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvBlock\r
   );\r
 \r
   OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvBlock\r
   );\r
 \r
+/**\r
+  Retrive the proper Swap Address Range protocol interface.\r
+\r
+  @param[out] SarProtocol       The interface of SAR protocol\r
+\r
+  @retval EFI_SUCCESS           The SAR protocol instance was found and returned in SarProtocol.\r
+  @retval EFI_NOT_FOUND         The SAR protocol instance was not found.\r
+  @retval EFI_INVALID_PARAMETER SarProtocol is NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+FtwGetSarProtocol (\r
+  OUT VOID                                **SarProtocol\r
+  );\r
+  \r
+/**\r
+  Function returns an array of handles that support the FVB protocol\r
+  in a buffer allocated from pool. \r
+\r
+  @param[out]  NumberHandles    The number of handles returned in Buffer.\r
+  @param[out]  Buffer           A pointer to the buffer to return the requested\r
+                                array of  handles that support FVB protocol.\r
+\r
+  @retval EFI_SUCCESS           The array of handles was returned in Buffer, and the number of\r
+                                handles in Buffer was returned in NumberHandles.\r
+  @retval EFI_NOT_FOUND         No FVB handle was found.\r
+  @retval EFI_OUT_OF_RESOURCES  There is not enough pool memory to store the matching results.\r
+  @retval EFI_INVALID_PARAMETER NumberHandles is NULL or Buffer is NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+GetFvbCountAndBuffer (\r
+  OUT UINTN                               *NumberHandles,\r
+  OUT EFI_HANDLE                          **Buffer\r
+  );\r
+\r
+\r
+/**\r
+  Allocate private data for FTW driver and initialize it.\r
+\r
+  @param[out] FtwData           Pointer to the FTW device structure\r
+\r
+  @retval EFI_SUCCESS           Initialize the FTW device successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  Allocate memory error\r
+  @retval EFI_INVALID_PARAMETER Workspace or Spare block does not exist\r
+\r
+**/\r
+EFI_STATUS\r
+InitFtwDevice (\r
+  OUT EFI_FTW_DEVICE               **FtwData \r
+  );\r
+\r
+\r
+/**\r
+  Initialization for Fault Tolerant Write is done in this handler.\r
+\r
+  @param[in,out] FtwData        Pointer to the FTW device structure\r
+\r
+  @retval EFI_SUCCESS           Initialize the FTW protocol successfully.\r
+  @retval EFI_NOT_FOUND         No proper FVB protocol was found.\r
+  \r
+**/\r
+EFI_STATUS\r
+InitFtwProtocol (\r
+  IN OUT EFI_FTW_DEVICE               *FtwDevice\r
+  );\r
\r
 #endif\r
 #endif\r
diff --git a/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.c b/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.c
new file mode 100644 (file)
index 0000000..5f998c0
--- /dev/null
@@ -0,0 +1,250 @@
+/** @file\r
+\r
+  This is a simple fault tolerant write driver.\r
+\r
+  This boot service protocol only provides fault tolerant write capability for \r
+  block devices.  The protocol has internal non-volatile intermediate storage \r
+  of the data and private information. It should be able to recover \r
+  automatically from a critical fault, such as power failure. \r
+\r
+  The implementation uses an FTW (Fault Tolerant Write) Work Space. \r
+  This work space is a memory copy of the work space on the Working Block,\r
+  the size of the work space is the FTW_WORK_SPACE_SIZE bytes.\r
+  \r
+  The work space stores each write record as EFI_FTW_RECORD structure.\r
+  The spare block stores the write buffer before write to the target block.\r
+  \r
+  The write record has three states to specify the different phase of write operation.\r
+  1) WRITE_ALLOCATED is that the record is allocated in write space.\r
+     The information of write operation is stored in write record structure.\r
+  2) SPARE_COMPLETED is that the data from write buffer is writed into the spare block as the backup.\r
+  3) WRITE_COMPLETED is that the data is copied from the spare block to the target block.\r
+\r
+  This driver operates the data as the whole size of spare block.\r
+  It first read the SpareAreaLength data from the target block into the spare memory buffer.\r
+  Then copy the write buffer data into the spare memory buffer.\r
+  Then write the spare memory buffer into the spare block.\r
+  Final copy the data from the spare block to the target block.\r
+\r
+  To make this drive work well, the following conditions must be satisfied:\r
+  1. The write NumBytes data must be fit within Spare area. \r
+     Offset + NumBytes <= SpareAreaLength\r
+  2. The whole flash range has the same block size.\r
+  3. Working block is an area which contains working space in its last block and has the same size as spare block.\r
+  4. Working Block area must be in the single one Firmware Volume Block range which FVB protocol is produced on.  \r
+  5. Spare area must be in the single one Firmware Volume Block range which FVB protocol is produced on.\r
+  6. Any write data area (SpareAreaLength Area) which the data will be written into must be \r
+     in the single one Firmware Volume Block range which FVB protocol is produced on.\r
+  7. If write data area (such as Variable range) is enlarged, the spare area range must be enlarged.\r
+     The spare area must be enough large to store the write data before write them into the target range.\r
+  If one of them is not satisfied, FtwWrite may fail.\r
+  Usually, Spare area only takes one block. That's SpareAreaLength = BlockSize, NumberOfSpareBlock = 1.\r
+\r
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials                          \r
+are licensed and made available under the terms and conditions of the BSD License         \r
+which accompanies this distribution.  The full text of the license may be found at        \r
+http://opensource.org/licenses/bsd-license.php                                            \r
+                                                                                          \r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.  \r
+\r
+**/\r
+\r
+#include "FaultTolerantWrite.h"\r
+EFI_EVENT                                 mFvbRegistration = NULL;\r
+\r
+\r
+/**\r
+  Retrive the FVB protocol interface by HANDLE.\r
+\r
+  @param[in]  FvBlockHandle     The handle of FVB protocol that provides services for\r
+                                reading, writing, and erasing the target block.\r
+  @param[out] FvBlock           The interface of FVB protocol\r
+\r
+  @retval EFI_SUCCESS           The interface information for the specified protocol was returned.\r
+  @retval EFI_UNSUPPORTED       The device does not support the FVB protocol.\r
+  @retval EFI_INVALID_PARAMETER FvBlockHandle is not a valid EFI_HANDLE or FvBlock is NULL.\r
+  \r
+**/\r
+EFI_STATUS\r
+FtwGetFvbByHandle (\r
+  IN  EFI_HANDLE                          FvBlockHandle,\r
+  OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  **FvBlock\r
+  )\r
+{\r
+  //\r
+  // To get the FVB protocol interface on the handle\r
+  //\r
+  return gBS->HandleProtocol (\r
+                FvBlockHandle,\r
+                &gEfiFirmwareVolumeBlockProtocolGuid,\r
+                (VOID **) FvBlock\r
+                );\r
+}\r
+\r
+/**\r
+  Retrive the Swap Address Range protocol interface.\r
+\r
+  @param[out] SarProtocol       The interface of SAR protocol\r
+\r
+  @retval EFI_SUCCESS           The SAR protocol instance was found and returned in SarProtocol.\r
+  @retval EFI_NOT_FOUND         The SAR protocol instance was not found.\r
+  @retval EFI_INVALID_PARAMETER SarProtocol is NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+FtwGetSarProtocol (\r
+  OUT VOID                                **SarProtocol\r
+  )\r
+{\r
+  EFI_STATUS                              Status;\r
+\r
+  //\r
+  // Locate Swap Address Range protocol\r
+  //\r
+  Status = gBS->LocateProtocol (\r
+                  &gEfiSwapAddressRangeProtocolGuid, \r
+                  NULL, \r
+                  SarProtocol\r
+                  );\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Function returns an array of handles that support the FVB protocol\r
+  in a buffer allocated from pool. \r
+\r
+  @param[out]  NumberHandles    The number of handles returned in Buffer.\r
+  @param[out]  Buffer           A pointer to the buffer to return the requested\r
+                                array of  handles that support FVB protocol.\r
+\r
+  @retval EFI_SUCCESS           The array of handles was returned in Buffer, and the number of\r
+                                handles in Buffer was returned in NumberHandles.\r
+  @retval EFI_NOT_FOUND         No FVB handle was found.\r
+  @retval EFI_OUT_OF_RESOURCES  There is not enough pool memory to store the matching results.\r
+  @retval EFI_INVALID_PARAMETER NumberHandles is NULL or Buffer is NULL.\r
+  \r
+**/\r
+EFI_STATUS\r
+GetFvbCountAndBuffer (\r
+  OUT UINTN                               *NumberHandles,\r
+  OUT EFI_HANDLE                          **Buffer\r
+  )\r
+{\r
+  EFI_STATUS                              Status;\r
+\r
+  //\r
+  // Locate all handles of Fvb protocol\r
+  //\r
+  Status = gBS->LocateHandleBuffer (\r
+                  ByProtocol,\r
+                  &gEfiFirmwareVolumeBlockProtocolGuid,\r
+                  NULL,\r
+                  NumberHandles,\r
+                  Buffer\r
+                  );\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Firmware Volume Block Protocol notification event handler.\r
+\r
+  @param[in] Event    Event whose notification function is being invoked.\r
+  @param[in] Context  Pointer to the notification function's context.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+FvbNotificationEvent (\r
+  IN  EFI_EVENT                           Event,\r
+  IN  VOID                                *Context\r
+  )\r
+{\r
+  EFI_STATUS                              Status;\r
+  EFI_FAULT_TOLERANT_WRITE_PROTOCOL       *FtwProtocol;\r
+  EFI_FTW_DEVICE                          *FtwDevice;\r
+\r
+  //\r
+  // Just return to avoid install SMM FaultTolerantWriteProtocol again\r
+  // if Fault Tolerant Write protocol had been installed.\r
+  //  \r
+  Status = gBS->LocateProtocol (\r
+                  &gEfiFaultTolerantWriteProtocolGuid, \r
+                  NULL, \r
+                  (VOID **) &FtwProtocol\r
+                  );\r
+  if (!EFI_ERROR (Status)) {\r
+    return ;\r
+  }\r
+\r
+  //\r
+  // Found proper FVB protocol and initialize FtwDevice for protocol installation\r
+  //\r
+  FtwDevice = (EFI_FTW_DEVICE *)Context;\r
+  Status = InitFtwProtocol (FtwDevice);\r
+  if (EFI_ERROR(Status)) {\r
+    return ;\r
+  }                          \r
+    \r
+  //\r
+  // Install protocol interface\r
+  //\r
+  Status = gBS->InstallProtocolInterface (\r
+                  &FtwDevice->Handle,\r
+                  &gEfiFaultTolerantWriteProtocolGuid,\r
+                  EFI_NATIVE_INTERFACE,\r
+                  &FtwDevice->FtwInstance\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+  \r
+  Status = gBS->CloseEvent (Event);\r
+  ASSERT_EFI_ERROR (Status);\r
+  \r
+  return;\r
+}\r
+\r
+\r
+/**\r
+  This function is the entry point of the Fault Tolerant Write driver.\r
+\r
+  @param[in] ImageHandle        A handle for the image that is initializing this driver\r
+  @param[in] SystemTable        A pointer to the EFI system table\r
+\r
+  @retval EFI_SUCCESS           The initialization finished successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  Allocate memory error\r
+  @retval EFI_INVALID_PARAMETER Workspace or Spare block does not exist\r
+  \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FaultTolerantWriteInitialize (\r
+  IN EFI_HANDLE                           ImageHandle,\r
+  IN EFI_SYSTEM_TABLE                     *SystemTable\r
+  )\r
+{\r
+  EFI_STATUS                              Status;\r
+  EFI_FTW_DEVICE                          *FtwDevice;\r
+\r
+  //\r
+  // Allocate private data structure for FTW protocol and do some initialization\r
+  //\r
+  Status = InitFtwDevice (&FtwDevice);\r
+  if (EFI_ERROR(Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Register FvbNotificationEvent () notify function.\r
+  // \r
+  EfiCreateProtocolNotifyEvent (\r
+    &gEfiFirmwareVolumeBlockProtocolGuid,\r
+    TPL_CALLBACK,\r
+    FvbNotificationEvent,\r
+    (VOID *)FtwDevice,\r
+    &mFvbRegistration\r
+    );\r
+  \r
+  return EFI_SUCCESS;\r
+}\r
index 137695916387695b57e336eca190e0cbdf3011e8..61139d486fab5b01b5eec395ae7cf15ee6371638 100644 (file)
@@ -20,7 +20,7 @@
   FILE_GUID                      = FE5CEA76-4F72-49e8-986F-2CD899DFFE5D\r
   MODULE_TYPE                    = DXE_DRIVER\r
   VERSION_STRING                 = 1.0\r
   FILE_GUID                      = FE5CEA76-4F72-49e8-986F-2CD899DFFE5D\r
   MODULE_TYPE                    = DXE_DRIVER\r
   VERSION_STRING                 = 1.0\r
-  ENTRY_POINT                    = InitializeFaultTolerantWrite\r
+  ENTRY_POINT                    = FaultTolerantWriteInitialize\r
 \r
 #\r
 # The following information is for reference only and not required by the build tools.\r
 \r
 #\r
 # The following information is for reference only and not required by the build tools.\r
@@ -32,6 +32,7 @@
   FtwMisc.c\r
   UpdateWorkingBlock.c\r
   FaultTolerantWrite.c\r
   FtwMisc.c\r
   UpdateWorkingBlock.c\r
   FaultTolerantWrite.c\r
+  FaultTolerantWriteDxe.c\r
   FaultTolerantWrite.h\r
 \r
 [Packages]\r
   FaultTolerantWrite.h\r
 \r
 [Packages]\r
diff --git a/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.c b/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.c
new file mode 100644 (file)
index 0000000..ffa7cb9
--- /dev/null
@@ -0,0 +1,281 @@
+/** @file\r
+\r
+  This is a simple fault tolerant write driver that is intended to use in the SMM environment.\r
+\r
+  This boot service protocol only provides fault tolerant write capability for \r
+  block devices.  The protocol has internal non-volatile intermediate storage \r
+  of the data and private information. It should be able to recover \r
+  automatically from a critical fault, such as power failure. \r
+\r
+  The implementation uses an FTW (Fault Tolerant Write) Work Space. \r
+  This work space is a memory copy of the work space on the Working Block,\r
+  the size of the work space is the FTW_WORK_SPACE_SIZE bytes.\r
+  \r
+  The work space stores each write record as EFI_FTW_RECORD structure.\r
+  The spare block stores the write buffer before write to the target block.\r
+  \r
+  The write record has three states to specify the different phase of write operation.\r
+  1) WRITE_ALLOCATED is that the record is allocated in write space.\r
+     The information of write operation is stored in write record structure.\r
+  2) SPARE_COMPLETED is that the data from write buffer is writed into the spare block as the backup.\r
+  3) WRITE_COMPLETED is that the data is copied from the spare block to the target block.\r
+\r
+  This driver operates the data as the whole size of spare block.\r
+  It first read the SpareAreaLength data from the target block into the spare memory buffer.\r
+  Then copy the write buffer data into the spare memory buffer.\r
+  Then write the spare memory buffer into the spare block.\r
+  Final copy the data from the spare block to the target block.\r
+\r
+  To make this drive work well, the following conditions must be satisfied:\r
+  1. The write NumBytes data must be fit within Spare area. \r
+     Offset + NumBytes <= SpareAreaLength\r
+  2. The whole flash range has the same block size.\r
+  3. Working block is an area which contains working space in its last block and has the same size as spare block.\r
+  4. Working Block area must be in the single one Firmware Volume Block range which FVB protocol is produced on.  \r
+  5. Spare area must be in the single one Firmware Volume Block range which FVB protocol is produced on.\r
+  6. Any write data area (SpareAreaLength Area) which the data will be written into must be \r
+     in the single one Firmware Volume Block range which FVB protocol is produced on.\r
+  7. If write data area (such as Variable range) is enlarged, the spare area range must be enlarged.\r
+     The spare area must be enough large to store the write data before write them into the target range.\r
+  If one of them is not satisfied, FtwWrite may fail.\r
+  Usually, Spare area only takes one block. That's SpareAreaLength = BlockSize, NumberOfSpareBlock = 1.\r
+\r
+Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials                          \r
+are licensed and made available under the terms and conditions of the BSD License         \r
+which accompanies this distribution.  The full text of the license may be found at        \r
+http://opensource.org/licenses/bsd-license.php                                            \r
+                                                                                          \r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.  \r
+\r
+**/\r
+\r
+#include <Library/SmmServicesTableLib.h>\r
+#include "FaultTolerantWrite.h"\r
+#include <Protocol/SmmFirmwareVolumeBlock.h>\r
+#include <Protocol/SmmSwapAddressRange.h>\r
+#include <Protocol/SmmFaultTolerantWrite.h>\r
+\r
+EFI_EVENT                                 mFvbRegistration = NULL;\r
+EFI_FTW_DEVICE                            *gFtwDevice      = NULL;\r
+\r
+/**\r
+  Retrive the SMM FVB protocol interface by HANDLE.\r
+\r
+  @param[in]  FvBlockHandle     The handle of SMM FVB protocol that provides services for\r
+                                reading, writing, and erasing the target block.\r
+  @param[out] FvBlock           The interface of SMM FVB protocol\r
+\r
+  @retval EFI_SUCCESS           The interface information for the specified protocol was returned.\r
+  @retval EFI_UNSUPPORTED       The device does not support the SMM FVB protocol.\r
+  @retval EFI_INVALID_PARAMETER FvBlockHandle is not a valid EFI_HANDLE or FvBlock is NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+FtwGetFvbByHandle (\r
+  IN  EFI_HANDLE                          FvBlockHandle,\r
+  OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  **FvBlock\r
+  )\r
+{\r
+  //\r
+  // To get the SMM FVB protocol interface on the handle\r
+  //\r
+  return gSmst->SmmHandleProtocol (\r
+                  FvBlockHandle,\r
+                  &gEfiSmmFirmwareVolumeBlockProtocolGuid,\r
+                  (VOID **) FvBlock\r
+                  );\r
+}\r
+\r
+/**\r
+  Retrive the SMM Swap Address Range protocol interface.\r
+\r
+  @param[out] SarProtocol       The interface of SMM SAR protocol\r
+\r
+  @retval EFI_SUCCESS           The SMM SAR protocol instance was found and returned in SarProtocol.\r
+  @retval EFI_NOT_FOUND         The SMM SAR protocol instance was not found.\r
+  @retval EFI_INVALID_PARAMETER SarProtocol is NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+FtwGetSarProtocol (\r
+  OUT VOID                                **SarProtocol\r
+  )\r
+{\r
+  EFI_STATUS                              Status;\r
+\r
+  //\r
+  // Locate Smm Swap Address Range protocol\r
+  //\r
+  Status = gSmst->SmmLocateProtocol (\r
+                    &gEfiSmmSwapAddressRangeProtocolGuid, \r
+                    NULL, \r
+                    SarProtocol\r
+                    );\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Function returns an array of handles that support the SMM FVB protocol\r
+  in a buffer allocated from pool. \r
+\r
+  @param[out]  NumberHandles    The number of handles returned in Buffer.\r
+  @param[out]  Buffer           A pointer to the buffer to return the requested\r
+                                array of  handles that support SMM FVB protocol.\r
+\r
+  @retval EFI_SUCCESS           The array of handles was returned in Buffer, and the number of\r
+                                handles in Buffer was returned in NumberHandles.\r
+  @retval EFI_NOT_FOUND         No SMM FVB handle was found.\r
+  @retval EFI_OUT_OF_RESOURCES  There is not enough pool memory to store the matching results.\r
+  @retval EFI_INVALID_PARAMETER NumberHandles is NULL or Buffer is NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+GetFvbCountAndBuffer (\r
+  OUT UINTN                               *NumberHandles,\r
+  OUT EFI_HANDLE                          **Buffer\r
+  )\r
+{\r
+  EFI_STATUS                              Status;\r
+  UINTN                                   BufferSize;\r
+\r
+  if ((NumberHandles == NULL) || (Buffer == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  BufferSize     = 0;\r
+  *NumberHandles = 0;\r
+  *Buffer        = NULL;\r
+  Status = gSmst->SmmLocateHandle (\r
+                    ByProtocol,\r
+                    &gEfiSmmFirmwareVolumeBlockProtocolGuid,\r
+                    NULL,\r
+                    &BufferSize,\r
+                    *Buffer\r
+                    );\r
+  if (EFI_ERROR(Status) && Status != EFI_BUFFER_TOO_SMALL) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  *Buffer = AllocatePool (BufferSize);\r
+  if (*Buffer == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Status = gSmst->SmmLocateHandle (\r
+                    ByProtocol,\r
+                    &gEfiSmmFirmwareVolumeBlockProtocolGuid,\r
+                    NULL,\r
+                    &BufferSize,\r
+                    *Buffer\r
+                    );\r
+\r
+  *NumberHandles = BufferSize / sizeof(EFI_HANDLE);\r
+  if (EFI_ERROR(Status)) {\r
+    *NumberHandles = 0;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  SMM Firmware Volume Block Protocol notification event handler.\r
+  \r
+  @param[in]  Protocol      Points to the protocol's unique identifier\r
+  @param[in]  Interface     Points to the interface instance\r
+  @param[in]  Handle        The handle on which the interface was installed\r
+\r
+  @retval EFI_SUCCESS       SmmEventCallback runs successfully\r
+  \r
+ **/\r
+EFI_STATUS\r
+EFIAPI\r
+FvbNotificationEvent (\r
+  IN CONST EFI_GUID                       *Protocol,\r
+  IN VOID                                 *Interface,\r
+  IN EFI_HANDLE                           Handle\r
+  )\r
+{\r
+  EFI_STATUS                              Status;\r
+  EFI_SMM_FAULT_TOLERANT_WRITE_PROTOCOL   *FtwProtocol;\r
+  \r
+  //\r
+  // Just return to avoid install SMM FaultTolerantWriteProtocol again\r
+  // if SMM Fault Tolerant Write protocol had been installed.\r
+  //  \r
+  Status = gSmst->SmmLocateProtocol (\r
+                    &gEfiSmmFaultTolerantWriteProtocolGuid, \r
+                    NULL, \r
+                    (VOID **) &FtwProtocol\r
+                    );\r
+  if (!EFI_ERROR (Status)) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // Found proper FVB protocol and initialize FtwDevice for protocol installation\r
+  //\r
+  Status = InitFtwProtocol (gFtwDevice);\r
+  if (EFI_ERROR(Status)) {\r
+    return Status;\r
+  }\r
+  \r
+  //\r
+  // Install protocol interface\r
+  //\r
+  Status = gSmst->SmmInstallProtocolInterface (\r
+                    &gFtwDevice->Handle,\r
+                    &gEfiSmmFaultTolerantWriteProtocolGuid,\r
+                    EFI_NATIVE_INTERFACE,\r
+                    &gFtwDevice->FtwInstance\r
+                    );\r
+  ASSERT_EFI_ERROR (Status); \r
+  \r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  This function is the entry point of the Fault Tolerant Write driver.\r
+\r
+  @param[in] ImageHandle        A handle for the image that is initializing this driver\r
+  @param[in] SystemTable        A pointer to the EFI system table\r
+\r
+  @retval EFI_SUCCESS           The initialization finished successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  Allocate memory error\r
+  @retval EFI_INVALID_PARAMETER Workspace or Spare block does not exist\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmFaultTolerantWriteInitialize (\r
+  IN EFI_HANDLE                           ImageHandle,\r
+  IN EFI_SYSTEM_TABLE                     *SystemTable\r
+  )\r
+{\r
+  EFI_STATUS                              Status;\r
+\r
+  //\r
+  // Allocate private data structure for SMM FTW protocol and do some initialization\r
+  //\r
+  Status = InitFtwDevice (&gFtwDevice);\r
+  if (EFI_ERROR(Status)) {\r
+    return Status;\r
+  }\r
+  \r
+  //\r
+  // Register FvbNotificationEvent () notify function.\r
+  // \r
+  Status = gSmst->SmmRegisterProtocolNotify (\r
+                    &gEfiSmmFirmwareVolumeBlockProtocolGuid,\r
+                    FvbNotificationEvent,\r
+                    &mFvbRegistration\r
+                    );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  FvbNotificationEvent (NULL, NULL, NULL);\r
+  \r
+  return EFI_SUCCESS;\r
+}\r
diff --git a/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.inf b/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.inf
new file mode 100644 (file)
index 0000000..3561721
--- /dev/null
@@ -0,0 +1,73 @@
+## @file\r
+#   This driver installs SMM Fault Tolerant Write (FTW) protocol, which provides fault \r
+#   tolerant write capability in SMM environment for block devices. Its implementation \r
+#   depends on the full functionality SMM FVB protocol that support read, write/erase \r
+#   flash access.\r
+#\r
+# Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>\r
+#\r
+#  This program and the accompanying materials\r
+#  are licensed and made available under the terms and conditions of the BSD License\r
+#  which accompanies this distribution. The full text of the license may be found at\r
+#  http://opensource.org/licenses/bsd-license.php\r
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = SmmFaultTolerantWriteDxe\r
+  FILE_GUID                      = 470CB248-E8AC-473c-BB4F-81069A1FE6FD\r
+  MODULE_TYPE                    = DXE_SMM_DRIVER\r
+  VERSION_STRING                 = 1.0\r
+  PI_SPECIFICATION_VERSION       = 0x0001000A\r
+  ENTRY_POINT                    = SmmFaultTolerantWriteInitialize\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64\r
+#\r
+\r
+[Sources]\r
+  FtwMisc.c\r
+  UpdateWorkingBlock.c\r
+  FaultTolerantWrite.c\r
+  FaultTolerantWriteSmm.c\r
+  FaultTolerantWrite.h\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+\r
+[LibraryClasses]\r
+  SmmServicesTableLib\r
+  MemoryAllocationLib\r
+  BaseMemoryLib\r
+  UefiDriverEntryPoint\r
+  DebugLib\r
+  UefiLib\r
+\r
+[Guids]\r
+  gEfiSystemNvDataFvGuid                        ## CONSUMES ## FV Signature of Working Space Header\r
+\r
+[Protocols]\r
+  gEfiSmmSwapAddressRangeProtocolGuid     | PcdFullFtwServiceEnable          ## CONSUMES\r
+  gEfiSmmFirmwareVolumeBlockProtocolGuid           ## CONSUMES\r
+  gEfiSmmFaultTolerantWriteProtocolGuid            ## PRODUCES\r
+\r
+[FeaturePcd]\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFullFtwServiceEnable\r
+\r
+[Pcd]\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase64\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase64\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize\r
+\r
+[Depex]\r
+  gEfiSmmFirmwareVolumeBlockProtocolGuid\r
+\r
index b8550f5d865b2a530a64d3bec0d65132939af7e7..7a32f4db83fc890ecb420f0431dc5831dcebde3a 100644 (file)
@@ -2,7 +2,7 @@
 \r
   Internal generic functions to operate flash block.\r
 \r
 \r
   Internal generic functions to operate flash block.\r
 \r
-Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
 This program and the accompanying materials                          \r
 are licensed and made available under the terms and conditions of the BSD License         \r
 which accompanies this distribution.  The full text of the license may be found at        \r
 This program and the accompanying materials                          \r
 are licensed and made available under the terms and conditions of the BSD License         \r
 which accompanies this distribution.  The full text of the license may be found at        \r
@@ -104,34 +104,6 @@ FtwEraseSpareBlock (
                                     );\r
 }\r
 \r
                                     );\r
 }\r
 \r
-/**\r
-  Retrive the proper FVB protocol interface by HANDLE.\r
-\r
-\r
-  @param FvBlockHandle   The handle of FVB protocol that provides services for\r
-                         reading, writing, and erasing the target block.\r
-  @param FvBlock         The interface of FVB protocol\r
-\r
-  @retval  EFI_SUCCESS   The function completed successfully\r
-  @retval  EFI_ABORTED   The function could not complete successfully\r
-\r
-**/\r
-EFI_STATUS\r
-FtwGetFvbByHandle (\r
-  IN EFI_HANDLE                           FvBlockHandle,\r
-  OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  **FvBlock\r
-  )\r
-{\r
-  //\r
-  // To get the FVB protocol interface on the handle\r
-  //\r
-  return gBS->HandleProtocol (\r
-                FvBlockHandle,\r
-                &gEfiFirmwareVolumeBlockProtocolGuid,\r
-                (VOID **) FvBlock\r
-                );\r
-}\r
-\r
 /**\r
 \r
   Is it in working block?\r
 /**\r
 \r
   Is it in working block?\r
@@ -195,13 +167,7 @@ GetFvbByAddress (
   //\r
   // Locate all handles of Fvb protocol\r
   //\r
   //\r
   // Locate all handles of Fvb protocol\r
   //\r
-  Status = gBS->LocateHandleBuffer (\r
-                  ByProtocol,\r
-                  &gEfiFirmwareVolumeBlockProtocolGuid,\r
-                  NULL,\r
-                  &HandleCount,\r
-                  &HandleBuffer\r
-                  );\r
+  Status = GetFvbCountAndBuffer (&HandleCount, &HandleBuffer);\r
   if (EFI_ERROR (Status)) {\r
     return NULL;\r
   }\r
   if (EFI_ERROR (Status)) {\r
     return NULL;\r
   }\r
@@ -209,11 +175,7 @@ GetFvbByAddress (
   // Get the FVB to access variable store\r
   //\r
   for (Index = 0; Index < HandleCount; Index += 1) {\r
   // Get the FVB to access variable store\r
   //\r
   for (Index = 0; Index < HandleCount; Index += 1) {\r
-    Status = gBS->HandleProtocol (\r
-                    HandleBuffer[Index],\r
-                    &gEfiFirmwareVolumeBlockProtocolGuid,\r
-                    (VOID **) &Fvb\r
-                    );\r
+    Status = FtwGetFvbByHandle (HandleBuffer[Index], &Fvb);\r
     if (EFI_ERROR (Status)) {\r
       break;\r
     }\r
     if (EFI_ERROR (Status)) {\r
       break;\r
     }\r
@@ -269,7 +231,7 @@ IsBootBlock (
     return FALSE;\r
   }\r
 \r
     return FALSE;\r
   }\r
 \r
-  Status = gBS->LocateProtocol (&gEfiSwapAddressRangeProtocolGuid, NULL, (VOID **) &SarProtocol);\r
+  Status = FtwGetSarProtocol ((VOID **) &SarProtocol);\r
   if (EFI_ERROR (Status)) {\r
     return FALSE;\r
   }\r
   if (EFI_ERROR (Status)) {\r
     return FALSE;\r
   }\r
@@ -358,7 +320,7 @@ FlushSpareBlockToBootBlock (
   //\r
   // Locate swap address range protocol\r
   //\r
   //\r
   // Locate swap address range protocol\r
   //\r
-  Status = gBS->LocateProtocol (&gEfiSwapAddressRangeProtocolGuid, NULL, (VOID **) &SarProtocol);\r
+  Status = FtwGetSarProtocol ((VOID **) &SarProtocol);\r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
@@ -969,3 +931,371 @@ GetPreviousRecordOfWrites (
   *FtwRecord = (EFI_FAULT_TOLERANT_WRITE_RECORD *) Ptr;\r
   return EFI_SUCCESS;\r
 }\r
   *FtwRecord = (EFI_FAULT_TOLERANT_WRITE_RECORD *) Ptr;\r
   return EFI_SUCCESS;\r
 }\r
+\r
+/**\r
+  Allocate private data for FTW driver and initialize it.\r
+\r
+  @param[out] FtwData           Pointer to the FTW device structure\r
+\r
+  @retval EFI_SUCCESS           Initialize the FTW device successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  Allocate memory error\r
+  @retval EFI_INVALID_PARAMETER Workspace or Spare block does not exist\r
+\r
+**/\r
+EFI_STATUS\r
+InitFtwDevice (\r
+  OUT EFI_FTW_DEVICE               **FtwData \r
+  )\r
+{\r
+  EFI_FTW_DEVICE                   *FtwDevice;\r
+  \r
+  //\r
+  // Allocate private data of this driver,\r
+  // Including the FtwWorkSpace[FTW_WORK_SPACE_SIZE].\r
+  //\r
+  FtwDevice = AllocateZeroPool (sizeof (EFI_FTW_DEVICE) + PcdGet32 (PcdFlashNvStorageFtwWorkingSize));\r
+  if (FtwDevice == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  //\r
+  // Initialize other parameters, and set WorkSpace as FTW_ERASED_BYTE.\r
+  //\r
+  FtwDevice->WorkSpaceLength  = (UINTN) PcdGet32 (PcdFlashNvStorageFtwWorkingSize);\r
+  FtwDevice->SpareAreaLength  = (UINTN) PcdGet32 (PcdFlashNvStorageFtwSpareSize);\r
+  if ((FtwDevice->WorkSpaceLength == 0) || (FtwDevice->SpareAreaLength == 0)) {\r
+    DEBUG ((EFI_D_ERROR, "Ftw: Workspace or Spare block does not exist!\n"));\r
+    FreePool (FtwDevice);\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  FtwDevice->Signature        = FTW_DEVICE_SIGNATURE;\r
+  FtwDevice->FtwFvBlock       = NULL;\r
+  FtwDevice->FtwBackupFvb     = NULL;\r
+  FtwDevice->FtwWorkSpaceLba  = (EFI_LBA) (-1);\r
+  FtwDevice->FtwSpareLba      = (EFI_LBA) (-1);\r
+\r
+  FtwDevice->WorkSpaceAddress = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageFtwWorkingBase64);\r
+  if (FtwDevice->WorkSpaceAddress == 0) {\r
+    FtwDevice->WorkSpaceAddress = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageFtwWorkingBase);\r
+  }\r
+  \r
+  FtwDevice->SpareAreaAddress = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageFtwSpareBase64);\r
+  if (FtwDevice->SpareAreaAddress == 0) {\r
+    FtwDevice->SpareAreaAddress = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageFtwSpareBase);\r
+  }  \r
+\r
+  *FtwData = FtwDevice;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Initialization for Fault Tolerant Write is done in this handler.\r
+\r
+  @param[in,out] FtwData        Pointer to the FTW device structure\r
+\r
+  @retval EFI_SUCCESS           Initialize the FTW device successfully.\r
+  @retval EFI_NOT_FOUND         No proper FVB protocol was found.\r
+  @retval EFI_ABORTED           Some data can not be got or be invalid.\r
+  \r
+**/\r
+EFI_STATUS\r
+FindFvbForFtw (\r
+  IN OUT EFI_FTW_DEVICE               *FtwDevice\r
+  )\r
+{\r
+  EFI_STATUS                          Status;\r
+  EFI_HANDLE                          *HandleBuffer;\r
+  UINTN                               HandleCount;\r
+  UINTN                               Index;\r
+  EFI_PHYSICAL_ADDRESS                FvbBaseAddress;\r
+  EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *Fvb;\r
+  EFI_FIRMWARE_VOLUME_HEADER          *FwVolHeader;\r
+  EFI_FVB_ATTRIBUTES_2                Attributes;\r
+  EFI_FV_BLOCK_MAP_ENTRY              *FvbMapEntry;\r
+  UINT32                              LbaIndex;\r
+\r
+  //\r
+  // Get all FVB handle.\r
+  //\r
+  Status = GetFvbCountAndBuffer (&HandleCount, &HandleBuffer);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  //\r
+  // Get the FVB to access variable store\r
+  //\r
+  Fvb = NULL;\r
+  for (Index = 0; Index < HandleCount; Index += 1) {\r
+    Status = FtwGetFvbByHandle (HandleBuffer[Index], &Fvb);\r
+    if (EFI_ERROR (Status)) {\r
+      Status = EFI_NOT_FOUND;\r
+      break;\r
+    }\r
+\r
+    //\r
+    // Ensure this FVB protocol support Write operation.\r
+    //\r
+    Status = Fvb->GetAttributes (Fvb, &Attributes);\r
+    if (EFI_ERROR (Status) || ((Attributes & EFI_FVB2_WRITE_STATUS) == 0)) {\r
+      continue;     \r
+    }\r
+    //\r
+    // Compare the address and select the right one\r
+    //\r
+    Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress);\r
+    if (EFI_ERROR (Status)) {\r
+      continue;\r
+    }\r
+\r
+    FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvbBaseAddress);\r
+    if ((FtwDevice->FtwFvBlock == NULL) && (FtwDevice->WorkSpaceAddress >= FvbBaseAddress) &&\r
+      ((FtwDevice->WorkSpaceAddress + FtwDevice->WorkSpaceLength) <= (FvbBaseAddress + FwVolHeader->FvLength))\r
+      ) {\r
+      FtwDevice->FtwFvBlock = Fvb;\r
+      //\r
+      // To get the LBA of work space\r
+      //\r
+      if ((FwVolHeader->FvLength) > (FwVolHeader->HeaderLength)) {\r
+        //\r
+        // Now, one FV has one type of BlockLength\r
+        //\r
+        FvbMapEntry = &FwVolHeader->BlockMap[0];\r
+        for (LbaIndex = 1; LbaIndex <= FvbMapEntry->NumBlocks; LbaIndex += 1) {\r
+          if ((FtwDevice->WorkSpaceAddress >= (FvbBaseAddress + FvbMapEntry->Length * (LbaIndex - 1)))\r
+              && (FtwDevice->WorkSpaceAddress < (FvbBaseAddress + FvbMapEntry->Length * LbaIndex))) {\r
+            FtwDevice->FtwWorkSpaceLba = LbaIndex - 1;\r
+            //\r
+            // Get the Work space size and Base(Offset)\r
+            //\r
+            FtwDevice->FtwWorkSpaceSize = FtwDevice->WorkSpaceLength;\r
+            FtwDevice->FtwWorkSpaceBase = (UINTN) (FtwDevice->WorkSpaceAddress - (FvbBaseAddress + FvbMapEntry->Length * (LbaIndex - 1)));\r
+            break;\r
+          }\r
+        }\r
+      }\r
+    }\r
+    \r
+    if ((FtwDevice->FtwBackupFvb == NULL) && (FtwDevice->SpareAreaAddress >= FvbBaseAddress) &&\r
+      ((FtwDevice->SpareAreaAddress + FtwDevice->SpareAreaLength) <= (FvbBaseAddress + FwVolHeader->FvLength))\r
+      ) {\r
+      FtwDevice->FtwBackupFvb = Fvb;\r
+      //\r
+      // To get the LBA of spare\r
+      //\r
+      if ((FwVolHeader->FvLength) > (FwVolHeader->HeaderLength)) {\r
+        //\r
+        // Now, one FV has one type of BlockLength\r
+        //\r
+        FvbMapEntry = &FwVolHeader->BlockMap[0];\r
+        for (LbaIndex = 1; LbaIndex <= FvbMapEntry->NumBlocks; LbaIndex += 1) {\r
+          if ((FtwDevice->SpareAreaAddress >= (FvbBaseAddress + FvbMapEntry->Length * (LbaIndex - 1)))\r
+              && (FtwDevice->SpareAreaAddress < (FvbBaseAddress + FvbMapEntry->Length * LbaIndex))) {\r
+            //\r
+            // Get the NumberOfSpareBlock and BlockSize\r
+            //\r
+            FtwDevice->FtwSpareLba   = LbaIndex - 1;\r
+            FtwDevice->BlockSize     = FvbMapEntry->Length;\r
+            FtwDevice->NumberOfSpareBlock = FtwDevice->SpareAreaLength / FtwDevice->BlockSize;\r
+            //\r
+            // Check the range of spare area to make sure that it's in FV range\r
+            //\r
+            if ((FtwDevice->FtwSpareLba + FtwDevice->NumberOfSpareBlock) > FvbMapEntry->NumBlocks) {\r
+              DEBUG ((EFI_D_ERROR, "Ftw: Spare area is out of FV range\n"));\r
+              FreePool (HandleBuffer);\r
+              ASSERT (FALSE);\r
+              return EFI_ABORTED;\r
+            }\r
+            break;\r
+          }\r
+        }\r
+      }\r
+    }\r
+  }\r
+  FreePool (HandleBuffer);\r
\r
+  if ((FtwDevice->FtwBackupFvb == NULL) || (FtwDevice->FtwFvBlock == NULL) ||\r
+    (FtwDevice->FtwWorkSpaceLba == (EFI_LBA) (-1)) || (FtwDevice->FtwSpareLba == (EFI_LBA) (-1))) {\r
+    return EFI_ABORTED;\r
+  }\r
+    \r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Initialization for Fault Tolerant Write protocol.\r
+\r
+  @param[in,out] FtwData        Pointer to the FTW device structure\r
+\r
+  @retval EFI_SUCCESS           Initialize the FTW protocol successfully.\r
+  @retval EFI_NOT_FOUND         No proper FVB protocol was found.\r
+  \r
+**/\r
+EFI_STATUS\r
+InitFtwProtocol (\r
+  IN OUT EFI_FTW_DEVICE               *FtwDevice\r
+  )\r
+{\r
+  EFI_STATUS                          Status;\r
+  EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *Fvb;\r
+  UINTN                               Length;\r
+  EFI_FAULT_TOLERANT_WRITE_HEADER     *FtwHeader;\r
+  UINTN                               Offset;\r
+  EFI_HANDLE                          FvbHandle;\r
+\r
+  //\r
+  // Find the right SMM Fvb protocol instance for FTW.\r
+  //\r
+  Status = FindFvbForFtw (FtwDevice);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_NOT_FOUND;\r
+  }  \r
+  \r
+  //\r
+  // Calculate the start LBA of working block. Working block is an area which\r
+  // contains working space in its last block and has the same size as spare\r
+  // block, unless there are not enough blocks before the block that contains\r
+  // working space.\r
+  //\r
+  FtwDevice->FtwWorkBlockLba = FtwDevice->FtwWorkSpaceLba - FtwDevice->NumberOfSpareBlock + 1;\r
+  ASSERT ((INT64) (FtwDevice->FtwWorkBlockLba) >= 0); \r
+\r
+  //\r
+  // Initialize other parameters, and set WorkSpace as FTW_ERASED_BYTE.\r
+  //\r
+  FtwDevice->FtwWorkSpace = (UINT8 *) (FtwDevice + 1);\r
+  FtwDevice->FtwWorkSpaceHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *) FtwDevice->FtwWorkSpace;\r
+\r
+  FtwDevice->FtwLastWriteHeader = NULL;\r
+  FtwDevice->FtwLastWriteRecord = NULL;\r
+\r
+  //\r
+  // Refresh the working space data from working block\r
+  //\r
+  Status = WorkSpaceRefresh (FtwDevice);\r
+  ASSERT_EFI_ERROR (Status);\r
+  //\r
+  // If the working block workspace is not valid, try the spare block\r
+  //\r
+  if (!IsValidWorkSpace (FtwDevice->FtwWorkSpaceHeader)) {\r
+    //\r
+    // Read from spare block\r
+    //\r
+    Length = FtwDevice->FtwWorkSpaceSize;\r
+    Status = FtwDevice->FtwBackupFvb->Read (\r
+                    FtwDevice->FtwBackupFvb,\r
+                    FtwDevice->FtwSpareLba,\r
+                    FtwDevice->FtwWorkSpaceBase,\r
+                    &Length,\r
+                    FtwDevice->FtwWorkSpace\r
+                    );\r
+    ASSERT_EFI_ERROR (Status);\r
+\r
+    //\r
+    // If spare block is valid, then replace working block content.\r
+    //\r
+    if (IsValidWorkSpace (FtwDevice->FtwWorkSpaceHeader)) {\r
+      Status = FlushSpareBlockToWorkingBlock (FtwDevice);\r
+      DEBUG ((EFI_D_ERROR, "Ftw: Restart working block update in InitFtwProtocol() - %r\n", Status));\r
+      FtwAbort (&FtwDevice->FtwInstance);\r
+      //\r
+      // Refresh work space.\r
+      //\r
+      Status = WorkSpaceRefresh (FtwDevice);\r
+      ASSERT_EFI_ERROR (Status);\r
+    } else {\r
+      DEBUG ((EFI_D_ERROR, "Ftw: Both are invalid, init workspace\n"));\r
+      //\r
+      // If both are invalid, then initialize work space.\r
+      //\r
+      SetMem (\r
+        FtwDevice->FtwWorkSpace,\r
+        FtwDevice->FtwWorkSpaceSize,\r
+        FTW_ERASED_BYTE\r
+        );\r
+      InitWorkSpaceHeader (FtwDevice->FtwWorkSpaceHeader);\r
+      //\r
+      // Initialize the work space\r
+      //\r
+      Status = FtwReclaimWorkSpace (FtwDevice, FALSE);\r
+      ASSERT_EFI_ERROR (Status);\r
+    }\r
+  }\r
+  //\r
+  // If the FtwDevice->FtwLastWriteRecord is 1st record of write header &&\r
+  // (! SpareComplete) THEN call Abort().\r
+  //\r
+  if ((FtwDevice->FtwLastWriteHeader->HeaderAllocated == FTW_VALID_STATE) &&\r
+    (FtwDevice->FtwLastWriteRecord->SpareComplete != FTW_VALID_STATE) &&\r
+    IsFirstRecordOfWrites (FtwDevice->FtwLastWriteHeader, FtwDevice->FtwLastWriteRecord)\r
+    ) {\r
+    DEBUG ((EFI_D_ERROR, "Ftw: Init.. find first record not SpareCompleted, abort()\n"));\r
+    FtwAbort (&FtwDevice->FtwInstance);\r
+  }\r
+  //\r
+  // If Header is incompleted and the last record has completed, then\r
+  // call Abort() to set the Header->Complete FLAG.\r
+  //\r
+  if ((FtwDevice->FtwLastWriteHeader->Complete != FTW_VALID_STATE) &&\r
+    (FtwDevice->FtwLastWriteRecord->DestinationComplete == FTW_VALID_STATE) &&\r
+    IsLastRecordOfWrites (FtwDevice->FtwLastWriteHeader, FtwDevice->FtwLastWriteRecord)\r
+    ) {\r
+    DEBUG ((EFI_D_ERROR, "Ftw: Init.. find last record completed but header not, abort()\n"));\r
+    FtwAbort (&FtwDevice->FtwInstance);\r
+  }\r
+  //\r
+  // To check the workspace buffer following last Write header/records is EMPTY or not.\r
+  // If it's not EMPTY, FTW also need to call reclaim().\r
+  //\r
+  FtwHeader = FtwDevice->FtwLastWriteHeader;\r
+  Offset    = (UINT8 *) FtwHeader - FtwDevice->FtwWorkSpace;\r
+  if (FtwDevice->FtwWorkSpace[Offset] != FTW_ERASED_BYTE) {\r
+    Offset += WRITE_TOTAL_SIZE (FtwHeader->NumberOfWrites, FtwHeader->PrivateDataSize);\r
+  }\r
+  \r
+  if (!IsErasedFlashBuffer (FtwDevice->FtwWorkSpace + Offset, FtwDevice->FtwWorkSpaceSize - Offset)) {\r
+    Status = FtwReclaimWorkSpace (FtwDevice, TRUE);\r
+    ASSERT_EFI_ERROR (Status);\r
+  }\r
+\r
+  //\r
+  // Restart if it's boot block\r
+  //\r
+  if ((FtwDevice->FtwLastWriteHeader->Complete != FTW_VALID_STATE) &&\r
+    (FtwDevice->FtwLastWriteRecord->SpareComplete == FTW_VALID_STATE)\r
+    ) {\r
+    if (FtwDevice->FtwLastWriteRecord->BootBlockUpdate == FTW_VALID_STATE) {\r
+      Status = FlushSpareBlockToBootBlock (FtwDevice);\r
+      DEBUG ((EFI_D_ERROR, "Ftw: Restart boot block update - %r\n", Status));\r
+      ASSERT_EFI_ERROR (Status);\r
+      FtwAbort (&FtwDevice->FtwInstance);\r
+    } else {\r
+      //\r
+      // if (SpareCompleted) THEN  Restart to fault tolerant write.\r
+      //\r
+      FvbHandle = NULL;\r
+      FvbHandle = GetFvbByAddress (FtwDevice->FtwLastWriteRecord->FvBaseAddress, &Fvb);\r
+      if (FvbHandle != NULL) {\r
+        Status = FtwRestart (&FtwDevice->FtwInstance, FvbHandle);\r
+        DEBUG ((EFI_D_ERROR, "FtwLite: Restart last write - %r\n", Status));\r
+        ASSERT_EFI_ERROR (Status);\r
+      }\r
+      FtwAbort (&FtwDevice->FtwInstance);\r
+    }\r
+  }\r
+  //\r
+  // Hook the protocol API\r
+  //\r
+  FtwDevice->FtwInstance.GetMaxBlockSize = FtwGetMaxBlockSize;\r
+  FtwDevice->FtwInstance.Allocate        = FtwAllocate;\r
+  FtwDevice->FtwInstance.Write           = FtwWrite;\r
+  FtwDevice->FtwInstance.Restart         = FtwRestart;\r
+  FtwDevice->FtwInstance.Abort           = FtwAbort;\r
+  FtwDevice->FtwInstance.GetLastWrite    = FtwGetLastWrite;\r
+    \r
+  return EFI_SUCCESS;\r
+}\r
+\r
index 79962daa6484f603cc0ef49dd05dd697d7aaf7b4..11bf1a02b6f6a5299479d9d08dfb1f9694f4817e 100644 (file)
@@ -3,7 +3,7 @@
   Handles non-volatile variable store garbage collection, using FTW\r
   (Fault Tolerant Write) protocol.\r
 \r
   Handles non-volatile variable store garbage collection, using FTW\r
   (Fault Tolerant Write) protocol.\r
 \r
-Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
 This program and the accompanying materials\r
 are licensed and made available under the terms and conditions of the BSD License\r
 which accompanies this distribution.  The full text of the license may be found at\r
 This program and the accompanying materials\r
 are licensed and made available under the terms and conditions of the BSD License\r
 which accompanies this distribution.  The full text of the license may be found at\r
@@ -14,105 +14,23 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 \r
 **/\r
 \r
 \r
 **/\r
 \r
-\r
 #include "Variable.h"\r
 \r
 #include "Variable.h"\r
 \r
-/**\r
-  Gets firmware volume block handle by given address.\r
-\r
-  This function gets firmware volume block handle whose\r
-  address range contains the parameter Address.\r
-\r
-  @param  Address        Address which should be contained\r
-                         by returned FVB handle\r
-  @param  FvbHandle      Pointer to FVB handle for output\r
-\r
-  @retval EFI_SUCCESS    FVB handle successfully returned\r
-  @retval EFI_NOT_FOUND  Fail to find FVB handle by address\r
-\r
-**/\r
-EFI_STATUS\r
-GetFvbHandleByAddress (\r
-  IN  EFI_PHYSICAL_ADDRESS   Address,\r
-  OUT EFI_HANDLE             *FvbHandle\r
-  )\r
-{\r
-  EFI_STATUS                          Status;\r
-  EFI_HANDLE                          *HandleBuffer;\r
-  UINTN                               HandleCount;\r
-  UINTN                               Index;\r
-  EFI_PHYSICAL_ADDRESS                FvbBaseAddress;\r
-  EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *Fvb;\r
-  EFI_FIRMWARE_VOLUME_HEADER          *FwVolHeader;\r
-  EFI_FVB_ATTRIBUTES_2                Attributes;\r
-\r
-  *FvbHandle = NULL;\r
-  //\r
-  // Locate all handles of Fvb protocol\r
-  //\r
-  Status = gBS->LocateHandleBuffer (\r
-                  ByProtocol,\r
-                  &gEfiFirmwareVolumeBlockProtocolGuid,\r
-                  NULL,\r
-                  &HandleCount,\r
-                  &HandleBuffer\r
-                  );\r
-  if (EFI_ERROR (Status)) {\r
-    return EFI_NOT_FOUND;\r
-  }\r
-  //\r
-  // Get the FVB to access variable store\r
-  //\r
-  for (Index = 0; Index < HandleCount; Index += 1) {\r
-    Status = gBS->HandleProtocol (\r
-                    HandleBuffer[Index],\r
-                    &gEfiFirmwareVolumeBlockProtocolGuid,\r
-                    (VOID **) &Fvb\r
-                    );\r
-    if (EFI_ERROR (Status)) {\r
-      Status = EFI_NOT_FOUND;\r
-      break;\r
-    }\r
-\r
-    Status = Fvb->GetAttributes (Fvb, &Attributes);\r
-    if (EFI_ERROR (Status) || ((Attributes & EFI_FVB2_WRITE_STATUS) == 0)) {\r
-      continue;     \r
-    }\r
-    //\r
-    // Compare the address and select the right one\r
-    //\r
-    Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress);\r
-    if (EFI_ERROR (Status)) {\r
-      continue;\r
-    }\r
-\r
-    FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvbBaseAddress);\r
-    if ((Address >= FvbBaseAddress) && (Address <= (FvbBaseAddress + FwVolHeader->FvLength))) {\r
-      *FvbHandle  = HandleBuffer[Index];\r
-      Status      = EFI_SUCCESS;\r
-      break;\r
-    }\r
-  }\r
-\r
-  FreePool (HandleBuffer);\r
-  return Status;\r
-}\r
-\r
 /**\r
   Gets LBA of block and offset by given address.\r
 \r
 /**\r
   Gets LBA of block and offset by given address.\r
 \r
-  This function gets the Logical Block Address (LBA) of firmware\r
-  volume block containing the given address, and the offset of\r
+  This function gets the Logical Block Address (LBA) of firmware\r
+  volume block containing the given address, and the offset of the\r
   address on the block.\r
 \r
   @param  Address        Address which should be contained\r
   address on the block.\r
 \r
   @param  Address        Address which should be contained\r
-                         by returned FVB handle\r
-  @param  Lba            Pointer to LBA for output\r
-  @param  Offset         Pointer to offset for output\r
+                         by returned FVB handle.\r
+  @param  Lba            Pointer to LBA for output.\r
+  @param  Offset         Pointer to offset for output.\r
 \r
 \r
-  @retval EFI_SUCCESS    LBA and offset successfully returned\r
-  @retval EFI_NOT_FOUND  Fail to find FVB handle by address\r
-  @retval EFI_ABORTED    Fail to find valid LBA and offset\r
+  @retval EFI_SUCCESS    LBA and offset successfully returned.\r
+  @retval EFI_NOT_FOUND  Fail to find FVB handle by address.\r
+  @retval EFI_ABORTED    Fail to find valid LBA and offset.\r
 \r
 **/\r
 EFI_STATUS\r
 \r
 **/\r
 EFI_STATUS\r
@@ -123,7 +41,6 @@ GetLbaAndOffsetByAddress (
   )\r
 {\r
   EFI_STATUS                          Status;\r
   )\r
 {\r
   EFI_STATUS                          Status;\r
-  EFI_HANDLE                          FvbHandle;\r
   EFI_PHYSICAL_ADDRESS                FvbBaseAddress;\r
   EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *Fvb;\r
   EFI_FIRMWARE_VOLUME_HEADER          *FwVolHeader;\r
   EFI_PHYSICAL_ADDRESS                FvbBaseAddress;\r
   EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *Fvb;\r
   EFI_FIRMWARE_VOLUME_HEADER          *FwVolHeader;\r
@@ -132,25 +49,17 @@ GetLbaAndOffsetByAddress (
 \r
   *Lba    = (EFI_LBA) (-1);\r
   *Offset = 0;\r
 \r
   *Lba    = (EFI_LBA) (-1);\r
   *Offset = 0;\r
-\r
+  \r
   //\r
   //\r
-  // Get the proper FVB\r
+  // Get the proper FVB protocol.\r
   //\r
   //\r
-  Status = GetFvbHandleByAddress (Address, &FvbHandle);\r
+  Status = GetFvbInfoByAddress (Address, NULL, &Fvb);\r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
 \r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
 \r
-  Status = gBS->HandleProtocol (\r
-                  FvbHandle,\r
-                  &gEfiFirmwareVolumeBlockProtocolGuid,\r
-                  (VOID **) &Fvb\r
-                  );\r
-  if (EFI_ERROR (Status)) {\r
-    return Status;\r
-  }\r
   //\r
   //\r
-  // Get the Base Address of FV\r
+  // Get the Base Address of FV.\r
   //\r
   Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress);\r
   if (EFI_ERROR (Status)) {\r
   //\r
   Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress);\r
   if (EFI_ERROR (Status)) {\r
@@ -160,24 +69,22 @@ GetLbaAndOffsetByAddress (
   FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvbBaseAddress);\r
 \r
   //\r
   FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvbBaseAddress);\r
 \r
   //\r
-  // Get the (LBA, Offset) of Address\r
+  // Get the (LBA, Offset) of Address.\r
   //\r
   //\r
-  if ((Address >= FvbBaseAddress) && (Address <= (FvbBaseAddress + FwVolHeader->FvLength))) {\r
-    if ((FwVolHeader->FvLength) > (FwVolHeader->HeaderLength)) {\r
-      //\r
-      // BUGBUG: Assume one FV has one type of BlockLength\r
-      //\r
-      FvbMapEntry = &FwVolHeader->BlockMap[0];\r
-      for (LbaIndex = 1; LbaIndex <= FvbMapEntry->NumBlocks; LbaIndex += 1) {\r
-        if (Address < (FvbBaseAddress + FvbMapEntry->Length * LbaIndex)) {\r
-          //\r
-          // Found the (Lba, Offset)\r
-          //\r
-          *Lba    = LbaIndex - 1;\r
-          *Offset = (UINTN) (Address - (FvbBaseAddress + FvbMapEntry->Length * (LbaIndex - 1)));\r
-          return EFI_SUCCESS;\r
-       }\r
-      }\r
+  if ((FwVolHeader->FvLength) > (FwVolHeader->HeaderLength)) {\r
+    //\r
+    // BUGBUG: Assume one FV has one type of BlockLength.\r
+    //\r
+    FvbMapEntry = &FwVolHeader->BlockMap[0];\r
+    for (LbaIndex = 1; LbaIndex <= FvbMapEntry->NumBlocks; LbaIndex += 1) {\r
+      if (Address < (FvbBaseAddress + FvbMapEntry->Length * LbaIndex)) {\r
+        //\r
+        // Found the (Lba, Offset).\r
+        //\r
+        *Lba    = LbaIndex - 1;\r
+        *Offset = (UINTN) (Address - (FvbBaseAddress + FvbMapEntry->Length * (LbaIndex - 1)));\r
+        return EFI_SUCCESS;\r
+     }\r
     }\r
   }\r
 \r
     }\r
   }\r
 \r
@@ -187,17 +94,17 @@ GetLbaAndOffsetByAddress (
 /**\r
   Writes a buffer to variable storage space, in the working block.\r
 \r
 /**\r
   Writes a buffer to variable storage space, in the working block.\r
 \r
-  This function writes a buffer to variable storage space into firmware\r
+  This function writes a buffer to variable storage space into firmware\r
   volume block device. The destination is specified by parameter\r
   VariableBase. Fault Tolerant Write protocol is used for writing.\r
 \r
   @param  VariableBase   Base address of variable to write\r
   volume block device. The destination is specified by parameter\r
   VariableBase. Fault Tolerant Write protocol is used for writing.\r
 \r
   @param  VariableBase   Base address of variable to write\r
-  @param  Buffer         Point to the data buffer\r
-  @param  BufferSize     The number of bytes of the data Buffer\r
+  @param  Buffer         Point to the data buffer.\r
+  @param  BufferSize     The number of bytes of the data Buffer.\r
 \r
 \r
-  @retval EFI_SUCCESS    The function completed successfully\r
-  @retval EFI_NOT_FOUND  Fail to locate Fault Tolerant Write protocol\r
-  @retval EFI_ABORTED    The function could not complete successfully\r
+  @retval EFI_SUCCESS    The function completed successfully.\r
+  @retval EFI_NOT_FOUND  Fail to locate Fault Tolerant Write protocol.\r
+  @retval EFI_ABORTED    The function could not complete successfully.\r
 \r
 **/\r
 EFI_STATUS\r
 \r
 **/\r
 EFI_STATUS\r
@@ -216,35 +123,31 @@ FtwVariableSpace (
   EFI_FAULT_TOLERANT_WRITE_PROTOCOL  *FtwProtocol;\r
 \r
   //\r
   EFI_FAULT_TOLERANT_WRITE_PROTOCOL  *FtwProtocol;\r
 \r
   //\r
-  // Locate fault tolerant write protocol\r
+  // Locate fault tolerant write protocol.\r
   //\r
   //\r
-  Status = gBS->LocateProtocol (\r
-                  &gEfiFaultTolerantWriteProtocolGuid,\r
-                  NULL,\r
-                  (VOID **) &FtwProtocol\r
-                  );\r
+  Status = GetFtwProtocol((VOID **) &FtwProtocol);\r
   if (EFI_ERROR (Status)) {\r
     return EFI_NOT_FOUND;\r
   }\r
   //\r
   if (EFI_ERROR (Status)) {\r
     return EFI_NOT_FOUND;\r
   }\r
   //\r
-  // Locate Fvb handle by address\r
+  // Locate Fvb handle by address.\r
   //\r
   //\r
-  Status = GetFvbHandleByAddress (VariableBase, &FvbHandle);\r
+  Status = GetFvbInfoByAddress (VariableBase, &FvbHandle, NULL);\r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
   //\r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
   //\r
-  // Get LBA and Offset by address\r
+  // Get LBA and Offset by address.\r
   //\r
   Status = GetLbaAndOffsetByAddress (VariableBase, &VarLba, &VarOffset);\r
   if (EFI_ERROR (Status)) {\r
     return EFI_ABORTED;\r
   }\r
   //\r
   //\r
   Status = GetLbaAndOffsetByAddress (VariableBase, &VarLba, &VarOffset);\r
   if (EFI_ERROR (Status)) {\r
     return EFI_ABORTED;\r
   }\r
   //\r
-  // Prepare for the variable data\r
+  // Prepare for the variable data.\r
   //\r
   FtwBufferSize = ((VARIABLE_STORE_HEADER *) ((UINTN) VariableBase))->Size;\r
   //\r
   FtwBufferSize = ((VARIABLE_STORE_HEADER *) ((UINTN) VariableBase))->Size;\r
-  FtwBuffer     = AllocateRuntimePool (FtwBufferSize);\r
+  FtwBuffer     = AllocatePool (FtwBufferSize);\r
   if (FtwBuffer == NULL) {\r
     return EFI_OUT_OF_RESOURCES;\r
   }\r
   if (FtwBuffer == NULL) {\r
     return EFI_OUT_OF_RESOURCES;\r
   }\r
@@ -253,17 +156,17 @@ FtwVariableSpace (
   CopyMem (FtwBuffer, Buffer, BufferSize);\r
 \r
   //\r
   CopyMem (FtwBuffer, Buffer, BufferSize);\r
 \r
   //\r
-  // FTW write record\r
+  // FTW write record.\r
   //\r
   Status = FtwProtocol->Write (\r
   //\r
   Status = FtwProtocol->Write (\r
-                              FtwProtocol,\r
-                              VarLba,         // LBA\r
-                              VarOffset,      // Offset\r
-                              FtwBufferSize,  // NumBytes\r
-                              NULL,           // PrivateData NULL\r
-                              FvbHandle,      // Fvb Handle\r
-                              FtwBuffer       // write buffer\r
-                              );\r
+                          FtwProtocol,\r
+                          VarLba,         // LBA\r
+                          VarOffset,      // Offset\r
+                          FtwBufferSize,  // NumBytes\r
+                          NULL,           // PrivateData NULL\r
+                          FvbHandle,      // Fvb Handle\r
+                          FtwBuffer       // write buffer\r
+                          );\r
 \r
   FreePool (FtwBuffer);\r
   return Status;\r
 \r
   FreePool (FtwBuffer);\r
   return Status;\r
index dca3e30370e1a8993efb205f6aa12c31a5e88e30..9a2468efb0802a63f9e1f7ab3d00f9aaddbe9e07 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
 \r
 /** @file\r
 \r
-  Implement all four UEFI Runtime Variable services for the nonvolatile\r
-  and volatile storage space and install variable architecture protocol.\r
+  The common variable operation routines shared by DXE_RINTIME variable \r
+  module and DXE_SMM variable module.\r
   \r
 Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
 This program and the accompanying materials                          \r
   \r
 Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
 This program and the accompanying materials                          \r
@@ -17,110 +17,16 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 #include "Variable.h"\r
 \r
 VARIABLE_MODULE_GLOBAL  *mVariableModuleGlobal;\r
 #include "Variable.h"\r
 \r
 VARIABLE_MODULE_GLOBAL  *mVariableModuleGlobal;\r
-EFI_EVENT   mVirtualAddressChangeEvent = NULL;\r
-EFI_HANDLE  mHandle = NULL;\r
 \r
 ///\r
 \r
 ///\r
-/// The current Hii implementation accesses this variable many times on every boot.\r
-/// Other common variables are only accessed once. This is why this cache algorithm\r
-/// only targets a single variable. Probably to get an performance improvement out of\r
-/// a Cache you would need a cache that improves the search performance for a variable.\r
+/// Define a memory cache that improves the search performance for a variable.\r
 ///\r
 ///\r
-VARIABLE_CACHE_ENTRY mVariableCache[] = {\r
-  {\r
-    &gEfiGlobalVariableGuid,\r
-    L"Lang",\r
-    0x00000000,\r
-    0x00,\r
-    NULL\r
-  },\r
-  {\r
-    &gEfiGlobalVariableGuid,\r
-    L"PlatformLang",\r
-    0x00000000,\r
-    0x00,\r
-    NULL\r
-  }\r
-};\r
-\r
-VARIABLE_INFO_ENTRY *gVariableInfo      = NULL;\r
-EFI_EVENT           mFvbRegistration    = NULL;\r
-\r
-/**\r
-  Update the variable region with Variable information. These are the same \r
-  arguments as the EFI Variable services.\r
-\r
-  @param[in] VariableName       Name of variable\r
-\r
-  @param[in] VendorGuid         Guid of variable\r
-\r
-  @param[in] Data               Variable data\r
-\r
-  @param[in] DataSize           Size of data. 0 means delete\r
-\r
-  @param[in] Attributes              Attribues of the variable\r
-\r
-  @param[in] Variable           The variable information which is used to keep track of variable usage.\r
-\r
-  @retval EFI_SUCCESS           The update operation is success.\r
-\r
-  @retval EFI_OUT_OF_RESOURCES  Variable region is full, can not write other data into this region.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-UpdateVariable (\r
-  IN      CHAR16                 *VariableName,\r
-  IN      EFI_GUID               *VendorGuid,\r
-  IN      VOID                   *Data,\r
-  IN      UINTN                  DataSize,\r
-  IN      UINT32                 Attributes OPTIONAL,\r
-  IN      VARIABLE_POINTER_TRACK *Variable\r
-  );\r
+VARIABLE_STORE_HEADER  *mNvVariableCache = NULL;\r
 \r
 \r
-/**\r
-  Acquires lock only at boot time. Simply returns at runtime.\r
-\r
-  This is a temperary function which will be removed when\r
-  EfiAcquireLock() in UefiLib can handle the call in UEFI\r
-  Runtimer driver in RT phase.\r
-  It calls EfiAcquireLock() at boot time, and simply returns\r
-  at runtime.\r
-\r
-  @param  Lock         A pointer to the lock to acquire\r
-\r
-**/\r
-VOID\r
-AcquireLockOnlyAtBootTime (\r
-  IN EFI_LOCK  *Lock\r
-  )\r
-{\r
-  if (!EfiAtRuntime ()) {\r
-    EfiAcquireLock (Lock);\r
-  }\r
-}\r
-\r
-/**\r
-  Releases lock only at boot time. Simply returns at runtime.\r
-\r
-  This is a temperary function which will be removed when\r
-  EfiReleaseLock() in UefiLib can handle the call in UEFI\r
-  Runtimer driver in RT phase.\r
-  It calls EfiReleaseLock() at boot time, and simply returns\r
-  at runtime.\r
-\r
-  @param  Lock         A pointer to the lock to release\r
-\r
-**/\r
-VOID\r
-ReleaseLockOnlyAtBootTime (\r
-  IN EFI_LOCK  *Lock\r
-  )\r
-{\r
-  if (!EfiAtRuntime ()) {\r
-    EfiReleaseLock (Lock);\r
-  }\r
-}\r
+///\r
+/// The memory entry used for variable statistics data.\r
+///\r
+VARIABLE_INFO_ENTRY    *gVariableInfo    = NULL;\r
 \r
 \r
 /**\r
 \r
 \r
 /**\r
@@ -134,12 +40,12 @@ ReleaseLockOnlyAtBootTime (
   the transaction. Data is allocated by this routine, but never\r
   freed.\r
 \r
   the transaction. Data is allocated by this routine, but never\r
   freed.\r
 \r
-  @param[in] VariableName   Name of the Variable to track\r
-  @param[in] VendorGuid     Guid of the Variable to track\r
-  @param[in] Volatile       TRUE if volatile FALSE if non-volatile\r
-  @param[in] Read           TRUE if GetVariable() was called\r
-  @param[in] Write          TRUE if SetVariable() was called\r
-  @param[in] Delete         TRUE if deleted via SetVariable()\r
+  @param[in] VariableName   Name of the Variable to track.\r
+  @param[in] VendorGuid     Guid of the Variable to track.\r
+  @param[in] Volatile       TRUE if volatile FALSE if non-volatile.\r
+  @param[in] Read           TRUE if GetVariable() was called.\r
+  @param[in] Write          TRUE if SetVariable() was called.\r
+  @param[in] Delete         TRUE if deleted via SetVariable().\r
   @param[in] Cache          TRUE for a cache hit.\r
 \r
 **/\r
   @param[in] Cache          TRUE for a cache hit.\r
 \r
 **/\r
@@ -158,15 +64,15 @@ UpdateVariableInfo (
 \r
   if (FeaturePcdGet (PcdVariableCollectStatistics)) {\r
 \r
 \r
   if (FeaturePcdGet (PcdVariableCollectStatistics)) {\r
 \r
-    if (EfiAtRuntime ()) {\r
-      // Don't collect statistics at runtime\r
+    if (AtRuntime ()) {\r
+      // Don't collect statistics at runtime.\r
       return;\r
     }\r
 \r
     if (gVariableInfo == NULL) {\r
       //\r
       return;\r
     }\r
 \r
     if (gVariableInfo == NULL) {\r
       //\r
-      // on the first call allocate a entry and place a pointer to it in\r
-      // the EFI System Table\r
+      // On the first call allocate a entry and place a pointer to it in\r
+      // the EFI System Table.\r
       //\r
       gVariableInfo = AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY));\r
       ASSERT (gVariableInfo != NULL);\r
       //\r
       gVariableInfo = AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY));\r
       ASSERT (gVariableInfo != NULL);\r
@@ -176,8 +82,6 @@ UpdateVariableInfo (
       ASSERT (gVariableInfo->Name != NULL);\r
       StrCpy (gVariableInfo->Name, VariableName);\r
       gVariableInfo->Volatile = Volatile;\r
       ASSERT (gVariableInfo->Name != NULL);\r
       StrCpy (gVariableInfo->Name, VariableName);\r
       gVariableInfo->Volatile = Volatile;\r
-\r
-      gBS->InstallConfigurationTable (&gEfiVariableGuid, gVariableInfo);\r
     }\r
 \r
     \r
     }\r
 \r
     \r
@@ -204,7 +108,7 @@ UpdateVariableInfo (
       if (Entry->Next == NULL) {\r
         //\r
         // If the entry is not in the table add it.\r
       if (Entry->Next == NULL) {\r
         //\r
         // If the entry is not in the table add it.\r
-        // Next iteration of the loop will fill in the data\r
+        // Next iteration of the loop will fill in the data.\r
         //\r
         Entry->Next = AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY));\r
         ASSERT (Entry->Next != NULL);\r
         //\r
         Entry->Next = AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY));\r
         ASSERT (Entry->Next != NULL);\r
@@ -249,18 +153,18 @@ IsValidVariableHeader (
   This function writes data to the FWH at the correct LBA even if the LBAs\r
   are fragmented.\r
 \r
   This function writes data to the FWH at the correct LBA even if the LBAs\r
   are fragmented.\r
 \r
-  @param Global                  Pointer to VARAIBLE_GLOBAL structure\r
-  @param Volatile                Point out the Variable is Volatile or Non-Volatile\r
-  @param SetByIndex              TRUE if target pointer is given as index\r
-                                 FALSE if target pointer is absolute\r
-  @param Fvb                     Pointer to the writable FVB protocol\r
+  @param Global                  Pointer to VARAIBLE_GLOBAL structure.\r
+  @param Volatile                Point out the Variable is Volatile or Non-Volatile.\r
+  @param SetByIndex              TRUE if target pointer is given as index.\r
+                                 FALSE if target pointer is absolute.\r
+  @param Fvb                     Pointer to the writable FVB protocol.\r
   @param DataPtrIndex            Pointer to the Data from the end of VARIABLE_STORE_HEADER\r
   @param DataPtrIndex            Pointer to the Data from the end of VARIABLE_STORE_HEADER\r
-                                 structure\r
-  @param DataSize                Size of data to be written\r
-  @param Buffer                  Pointer to the buffer from which data is written\r
+                                 structure.\r
+  @param DataSize                Size of data to be written.\r
+  @param Buffer                  Pointer to the buffer from which data is written.\r
 \r
 \r
-  @retval EFI_INVALID_PARAMETER  Parameters not valid\r
-  @retval EFI_SUCCESS            Variable store successfully updated\r
+  @retval EFI_INVALID_PARAMETER  Parameters not valid.\r
+  @retval EFI_SUCCESS            Variable store successfully updated.\r
 \r
 **/\r
 EFI_STATUS\r
 \r
 **/\r
 EFI_STATUS\r
@@ -292,7 +196,7 @@ UpdateVariableStore (
   DataPtr     = DataPtrIndex;\r
 \r
   //\r
   DataPtr     = DataPtrIndex;\r
 \r
   //\r
-  // Check if the Data is Volatile\r
+  // Check if the Data is Volatile.\r
   //\r
   if (!Volatile) {\r
     Status = Fvb->GetPhysicalAddress(Fvb, &FvVolHdr);\r
   //\r
   if (!Volatile) {\r
     Status = Fvb->GetPhysicalAddress(Fvb, &FvVolHdr);\r
@@ -301,7 +205,7 @@ UpdateVariableStore (
     FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvVolHdr);\r
     //\r
     // Data Pointer should point to the actual Address where data is to be\r
     FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvVolHdr);\r
     //\r
     // Data Pointer should point to the actual Address where data is to be\r
-    // written\r
+    // written.\r
     //\r
     if (SetByIndex) {\r
       DataPtr += mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;\r
     //\r
     if (SetByIndex) {\r
       DataPtr += mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;\r
@@ -313,7 +217,7 @@ UpdateVariableStore (
   } else {\r
     //\r
     // Data Pointer should point to the actual Address where data is to be\r
   } else {\r
     //\r
     // Data Pointer should point to the actual Address where data is to be\r
-    // written\r
+    // written.\r
     //\r
     VolatileBase = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);\r
     if (SetByIndex) {\r
     //\r
     VolatileBase = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);\r
     if (SetByIndex) {\r
@@ -332,7 +236,7 @@ UpdateVariableStore (
   }\r
   \r
   //\r
   }\r
   \r
   //\r
-  // If we are here we are dealing with Non-Volatile Variables\r
+  // If we are here we are dealing with Non-Volatile Variables.\r
   //\r
   LinearOffset  = (UINTN) FwVolHeader;\r
   CurrWritePtr  = (UINTN) DataPtr;\r
   //\r
   LinearOffset  = (UINTN) FwVolHeader;\r
   CurrWritePtr  = (UINTN) DataPtr;\r
@@ -394,9 +298,9 @@ UpdateVariableStore (
 \r
   @param VarStoreHeader  Pointer to the Variable Store Header.\r
 \r
 \r
   @param VarStoreHeader  Pointer to the Variable Store Header.\r
 \r
-  @retval EfiRaw         Variable store status is raw\r
-  @retval EfiValid       Variable store status is valid\r
-  @retval EfiInvalid     Variable store status is invalid\r
+  @retval EfiRaw         Variable store status is raw.\r
+  @retval EfiValid       Variable store status is valid.\r
+  @retval EfiInvalid     Variable store status is invalid.\r
 \r
 **/\r
 VARIABLE_STORE_STATUS\r
 \r
 **/\r
 VARIABLE_STORE_STATUS\r
@@ -430,9 +334,9 @@ GetVariableStoreStatus (
 \r
   This code gets the size of name of variable.\r
 \r
 \r
   This code gets the size of name of variable.\r
 \r
-  @param Variable        Pointer to the Variable Header\r
+  @param Variable        Pointer to the Variable Header.\r
 \r
 \r
-  @return UINTN          Size of variable in bytes\r
+  @return UINTN          Size of variable in bytes.\r
 \r
 **/\r
 UINTN\r
 \r
 **/\r
 UINTN\r
@@ -453,9 +357,9 @@ NameSizeOfVariable (
 \r
   This code gets the size of variable data.\r
 \r
 \r
   This code gets the size of variable data.\r
 \r
-  @param Variable        Pointer to the Variable Header\r
+  @param Variable        Pointer to the Variable Header.\r
 \r
 \r
-  @return Size of variable in bytes\r
+  @return Size of variable in bytes.\r
 \r
 **/\r
 UINTN\r
 \r
 **/\r
 UINTN\r
@@ -476,9 +380,9 @@ DataSizeOfVariable (
 \r
   This code gets the pointer to the variable name.\r
 \r
 \r
   This code gets the pointer to the variable name.\r
 \r
-  @param Variable        Pointer to the Variable Header\r
+  @param Variable        Pointer to the Variable Header.\r
 \r
 \r
-  @return Pointer to Variable Name which is Unicode encoding\r
+  @return Pointer to Variable Name which is Unicode encoding.\r
 \r
 **/\r
 CHAR16 *\r
 \r
 **/\r
 CHAR16 *\r
@@ -494,9 +398,9 @@ GetVariableNamePtr (
 \r
   This code gets the pointer to the variable data.\r
 \r
 \r
   This code gets the pointer to the variable data.\r
 \r
-  @param Variable        Pointer to the Variable Header\r
+  @param Variable        Pointer to the Variable Header.\r
 \r
 \r
-  @return Pointer to Variable Data\r
+  @return Pointer to Variable Data.\r
 \r
 **/\r
 UINT8 *\r
 \r
 **/\r
 UINT8 *\r
@@ -507,7 +411,7 @@ GetVariableDataPtr (
   UINTN Value;\r
   \r
   //\r
   UINTN Value;\r
   \r
   //\r
-  // Be careful about pad size for alignment\r
+  // Be careful about pad size for alignment.\r
   //\r
   Value =  (UINTN) GetVariableNamePtr (Variable);\r
   Value += NameSizeOfVariable (Variable);\r
   //\r
   Value =  (UINTN) GetVariableNamePtr (Variable);\r
   Value += NameSizeOfVariable (Variable);\r
@@ -521,9 +425,9 @@ GetVariableDataPtr (
 \r
   This code gets the pointer to the next variable header.\r
 \r
 \r
   This code gets the pointer to the next variable header.\r
 \r
-  @param Variable        Pointer to the Variable Header\r
+  @param Variable        Pointer to the Variable Header.\r
 \r
 \r
-  @return Pointer to next variable header\r
+  @return Pointer to next variable header.\r
 \r
 **/\r
 VARIABLE_HEADER *\r
 \r
 **/\r
 VARIABLE_HEADER *\r
@@ -542,7 +446,7 @@ GetNextVariablePtr (
   Value += GET_PAD_SIZE (DataSizeOfVariable (Variable));\r
 \r
   //\r
   Value += GET_PAD_SIZE (DataSizeOfVariable (Variable));\r
 \r
   //\r
-  // Be careful about pad size for alignment\r
+  // Be careful about pad size for alignment.\r
   //\r
   return (VARIABLE_HEADER *) HEADER_ALIGN (Value);\r
 }\r
   //\r
   return (VARIABLE_HEADER *) HEADER_ALIGN (Value);\r
 }\r
@@ -553,7 +457,7 @@ GetNextVariablePtr (
 \r
   @param VarStoreHeader  Pointer to the Variable Store Header.\r
 \r
 \r
   @param VarStoreHeader  Pointer to the Variable Store Header.\r
 \r
-  @return Pointer to the first variable header\r
+  @return Pointer to the first variable header.\r
 \r
 **/\r
 VARIABLE_HEADER *\r
 \r
 **/\r
 VARIABLE_HEADER *\r
@@ -562,7 +466,7 @@ GetStartPointer (
   )\r
 {\r
   //\r
   )\r
 {\r
   //\r
-  // The end of variable store\r
+  // The end of variable store.\r
   //\r
   return (VARIABLE_HEADER *) HEADER_ALIGN (VarStoreHeader + 1);\r
 }\r
   //\r
   return (VARIABLE_HEADER *) HEADER_ALIGN (VarStoreHeader + 1);\r
 }\r
@@ -574,9 +478,9 @@ GetStartPointer (
   This function gets pointer to the end of the variable storage\r
   area, according to the input variable store header.\r
 \r
   This function gets pointer to the end of the variable storage\r
   area, according to the input variable store header.\r
 \r
-  @param VarStoreHeader  Pointer to the Variable Store Header\r
+  @param VarStoreHeader  Pointer to the Variable Store Header.\r
 \r
 \r
-  @return Pointer to the end of the variable storage area  \r
+  @return Pointer to the end of the variable storage area. \r
 \r
 **/\r
 VARIABLE_HEADER *\r
 \r
 **/\r
 VARIABLE_HEADER *\r
@@ -595,11 +499,11 @@ GetEndPointer (
 \r
   Variable store garbage collection and reclaim operation.\r
 \r
 \r
   Variable store garbage collection and reclaim operation.\r
 \r
-  @param VariableBase            Base address of variable store\r
-  @param LastVariableOffset      Offset of last variable\r
-  @param IsVolatile              The variable store is volatile or not,\r
-                                 if it is non-volatile, need FTW\r
-  @param UpdatingVariable        Pointer to updateing variable.\r
+  @param VariableBase            Base address of variable store.\r
+  @param LastVariableOffset      Offset of last variable.\r
+  @param IsVolatile              The variable store is volatile or not;\r
+                                 if it is non-volatile, need FTW.\r
+  @param UpdatingVariable        Pointer to updating variable.\r
 \r
   @return EFI_OUT_OF_RESOURCES\r
   @return EFI_SUCCESS\r
 \r
   @return EFI_OUT_OF_RESOURCES\r
   @return EFI_SUCCESS\r
@@ -635,7 +539,7 @@ Reclaim (
 \r
   VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) VariableBase);\r
   //\r
 \r
   VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) VariableBase);\r
   //\r
-  // recaluate the total size of Common/HwErr type variables in non-volatile area.\r
+  // Recalculate the total size of Common/HwErr type variables in non-volatile area.\r
   //\r
   if (!IsVolatile) {\r
     mVariableModuleGlobal->CommonVariableTotalSize = 0;\r
   //\r
   if (!IsVolatile) {\r
     mVariableModuleGlobal->CommonVariableTotalSize = 0;\r
@@ -673,13 +577,13 @@ Reclaim (
   SetMem (ValidBuffer, MaximumBufferSize, 0xff);\r
 \r
   //\r
   SetMem (ValidBuffer, MaximumBufferSize, 0xff);\r
 \r
   //\r
-  // Copy variable store header\r
+  // Copy variable store header.\r
   //\r
   CopyMem (ValidBuffer, VariableStoreHeader, sizeof (VARIABLE_STORE_HEADER));\r
   CurrPtr = (UINT8 *) GetStartPointer ((VARIABLE_STORE_HEADER *) ValidBuffer);\r
 \r
   //\r
   //\r
   CopyMem (ValidBuffer, VariableStoreHeader, sizeof (VARIABLE_STORE_HEADER));\r
   CurrPtr = (UINT8 *) GetStartPointer ((VARIABLE_STORE_HEADER *) ValidBuffer);\r
 \r
   //\r
-  // Reinstall all ADDED variables as long as they are not identical to Updating Variable\r
+  // Reinstall all ADDED variables as long as they are not identical to Updating Variable.\r
   // \r
   Variable = GetStartPointer (VariableStoreHeader);\r
   while (IsValidVariableHeader (Variable)) {\r
   // \r
   Variable = GetStartPointer (VariableStoreHeader);\r
   while (IsValidVariableHeader (Variable)) {\r
@@ -716,7 +620,7 @@ Reclaim (
   }\r
 \r
   //\r
   }\r
 \r
   //\r
-  // Reinstall the variable being updated if it is not NULL\r
+  // Reinstall the variable being updated if it is not NULL.\r
   //\r
   if (UpdatingVariable != NULL) {\r
     VariableSize = (UINTN)(GetNextVariablePtr (UpdatingVariable)) - (UINTN)UpdatingVariable;\r
   //\r
   if (UpdatingVariable != NULL) {\r
     VariableSize = (UINTN)(GetNextVariablePtr (UpdatingVariable)) - (UINTN)UpdatingVariable;\r
@@ -730,7 +634,7 @@ Reclaim (
   }\r
 \r
   //\r
   }\r
 \r
   //\r
-  // Reinstall all in delete transition variables\r
+  // Reinstall all in delete transition variables.\r
   // \r
   Variable      = GetStartPointer (VariableStoreHeader);\r
   while (IsValidVariableHeader (Variable)) {\r
   // \r
   Variable      = GetStartPointer (VariableStoreHeader);\r
   while (IsValidVariableHeader (Variable)) {\r
@@ -762,7 +666,7 @@ Reclaim (
       }\r
       if (!FoundAdded) {\r
         //\r
       }\r
       if (!FoundAdded) {\r
         //\r
-        // Promote VAR_IN_DELETED_TRANSITION to VAR_ADDED\r
+        // Promote VAR_IN_DELETED_TRANSITION to VAR_ADDED.\r
         //\r
         VariableSize = (UINTN) NextVariable - (UINTN) Variable;\r
         CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize);\r
         //\r
         VariableSize = (UINTN) NextVariable - (UINTN) Variable;\r
         CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize);\r
@@ -781,11 +685,11 @@ Reclaim (
 \r
   if (IsVolatile) {\r
     //\r
 \r
   if (IsVolatile) {\r
     //\r
-    // If volatile variable store, just copy valid buffer\r
+    // If volatile variable store, just copy valid buffer.\r
     //\r
     SetMem ((UINT8 *) (UINTN) VariableBase, VariableStoreHeader->Size, 0xff);\r
     CopyMem ((UINT8 *) (UINTN) VariableBase, ValidBuffer, (UINTN) (CurrPtr - (UINT8 *) ValidBuffer));\r
     //\r
     SetMem ((UINT8 *) (UINTN) VariableBase, VariableStoreHeader->Size, 0xff);\r
     CopyMem ((UINT8 *) (UINTN) VariableBase, ValidBuffer, (UINTN) (CurrPtr - (UINT8 *) ValidBuffer));\r
-    Status              = EFI_SUCCESS;\r
+    Status  = EFI_SUCCESS;\r
   } else {\r
     //\r
     // If non-volatile variable store, perform FTW here.\r
   } else {\r
     //\r
     // If non-volatile variable store, perform FTW here.\r
@@ -795,6 +699,7 @@ Reclaim (
               ValidBuffer,\r
               (UINTN) (CurrPtr - (UINT8 *) ValidBuffer)\r
               );\r
               ValidBuffer,\r
               (UINTN) (CurrPtr - (UINT8 *) ValidBuffer)\r
               );\r
+    CopyMem (mNvVariableCache, (CHAR8 *)(UINTN)VariableBase, VariableStoreHeader->Size);\r
   }\r
   if (!EFI_ERROR (Status)) {\r
     *LastVariableOffset = (UINTN) (CurrPtr - (UINT8 *) ValidBuffer);\r
   }\r
   if (!EFI_ERROR (Status)) {\r
     *LastVariableOffset = (UINTN) (CurrPtr - (UINT8 *) ValidBuffer);\r
@@ -808,126 +713,6 @@ Reclaim (
 }\r
 \r
 \r
 }\r
 \r
 \r
-/**\r
-  Update the Cache with Variable information. These are the same \r
-  arguments as the EFI Variable services.\r
-\r
-  @param[in] VariableName  Name of variable\r
-  @param[in] VendorGuid    Guid of variable\r
-  @param[in] Attributes    Attribues of the variable\r
-  @param[in] DataSize      Size of data. 0 means delete\r
-  @param[in] Data          Variable data\r
-\r
-**/\r
-VOID\r
-UpdateVariableCache (\r
-  IN      CHAR16            *VariableName,\r
-  IN      EFI_GUID          *VendorGuid,\r
-  IN      UINT32            Attributes,\r
-  IN      UINTN             DataSize,\r
-  IN      VOID              *Data\r
-  )\r
-{\r
-  VARIABLE_CACHE_ENTRY      *Entry;\r
-  UINTN                     Index;\r
-\r
-  if (EfiAtRuntime ()) {\r
-    //\r
-    // Don't use the cache at runtime\r
-    // \r
-    return;\r
-  }\r
-\r
-  for (Index = 0, Entry = mVariableCache; Index < sizeof (mVariableCache)/sizeof (VARIABLE_CACHE_ENTRY); Index++, Entry++) {\r
-    if (CompareGuid (VendorGuid, Entry->Guid)) {\r
-      if (StrCmp (VariableName, Entry->Name) == 0) { \r
-        Entry->Attributes = Attributes;\r
-        if (DataSize == 0) {\r
-          //\r
-          // Delete Case\r
-          //\r
-          if (Entry->DataSize != 0) {\r
-            FreePool (Entry->Data);\r
-          }\r
-          Entry->DataSize = DataSize;\r
-        } else if (DataSize == Entry->DataSize) {\r
-          CopyMem (Entry->Data, Data, DataSize);\r
-        } else {\r
-          Entry->Data = AllocatePool (DataSize);\r
-          ASSERT (Entry->Data != NULL);\r
-\r
-          Entry->DataSize = DataSize;\r
-          CopyMem (Entry->Data, Data, DataSize);\r
-        }\r
-      }\r
-    }\r
-  }\r
-}\r
-\r
-\r
-/**\r
-  Search the cache to check if the variable is in it.\r
-\r
-  This function searches the variable cache. If the variable to find exists, return its data\r
-  and attributes.\r
-\r
-  @param  VariableName          A Null-terminated Unicode string that is the name of the vendor's\r
-                                variable.  Each VariableName is unique for each \r
-                                VendorGuid.\r
-  @param  VendorGuid            A unique identifier for the vendor\r
-  @param  Attributes            Pointer to the attributes bitmask of the variable for output.\r
-  @param  DataSize              On input, size of the buffer of Data.\r
-                                On output, size of the variable's data.\r
-  @param  Data                  Pointer to the data buffer for output.\r
-\r
-  @retval EFI_SUCCESS           VariableGuid & VariableName data was returned.\r
-  @retval EFI_NOT_FOUND         No matching variable found in cache.\r
-  @retval EFI_BUFFER_TOO_SMALL  *DataSize is smaller than size of the variable's data to return.\r
-\r
-**/\r
-EFI_STATUS\r
-FindVariableInCache (\r
-  IN      CHAR16            *VariableName,\r
-  IN      EFI_GUID          *VendorGuid,\r
-  OUT     UINT32            *Attributes OPTIONAL,\r
-  IN OUT  UINTN             *DataSize,\r
-  OUT     VOID              *Data\r
-  )\r
-{\r
-  VARIABLE_CACHE_ENTRY      *Entry;\r
-  UINTN                     Index;\r
-\r
-  if (EfiAtRuntime ()) {\r
-    // Don't use the cache at runtime\r
-    return EFI_NOT_FOUND;\r
-  }\r
-\r
-  for (Index = 0, Entry = mVariableCache; Index < sizeof (mVariableCache)/sizeof (VARIABLE_CACHE_ENTRY); Index++, Entry++) {\r
-    if (CompareGuid (VendorGuid, Entry->Guid)) {\r
-      if (StrCmp (VariableName, Entry->Name) == 0) {\r
-        if (Entry->DataSize == 0) {\r
-          // Variable was deleted so return not found\r
-          return EFI_NOT_FOUND;\r
-        } else if (Entry->DataSize > *DataSize) {\r
-          // If the buffer is too small return correct size\r
-          *DataSize = Entry->DataSize;\r
-          return EFI_BUFFER_TOO_SMALL;\r
-        } else {\r
-          *DataSize = Entry->DataSize;\r
-          // Return the data\r
-          CopyMem (Data, Entry->Data, Entry->DataSize);\r
-          if (Attributes != NULL) {\r
-            *Attributes = Entry->Attributes;\r
-          }\r
-          return EFI_SUCCESS;\r
-        }\r
-      }\r
-    }\r
-  }\r
-  \r
-  return EFI_NOT_FOUND;\r
-}\r
-\r
 /**\r
   Finds variable in storage blocks of volatile and non-volatile storage areas.\r
 \r
 /**\r
   Finds variable in storage blocks of volatile and non-volatile storage areas.\r
 \r
@@ -936,7 +721,7 @@ FindVariableInCache (
   qualified variable without comparing VariableName and VendorGuid.\r
   Otherwise, VariableName and VendorGuid are compared.\r
 \r
   qualified variable without comparing VariableName and VendorGuid.\r
   Otherwise, VariableName and VendorGuid are compared.\r
 \r
-  @param  VariableName                Name of the variable to be found\r
+  @param  VariableName                Name of the variable to be found.\r
   @param  VendorGuid                  Vendor GUID to be found.\r
   @param  PtrTrack                    VARIABLE_POINTER_TRACK structure for output,\r
                                       including the range searched and the target position.\r
   @param  VendorGuid                  Vendor GUID to be found.\r
   @param  PtrTrack                    VARIABLE_POINTER_TRACK structure for output,\r
                                       including the range searched and the target position.\r
@@ -945,8 +730,8 @@ FindVariableInCache (
                                       NV variable storage area, and a lock.\r
 \r
   @retval EFI_INVALID_PARAMETER       If VariableName is not an empty string, while\r
                                       NV variable storage area, and a lock.\r
 \r
   @retval EFI_INVALID_PARAMETER       If VariableName is not an empty string, while\r
-                                      VendorGuid is NULL\r
-  @retval EFI_SUCCESS                 Variable successfully found\r
+                                      VendorGuid is NULL.\r
+  @retval EFI_SUCCESS                 Variable successfully found.\r
   @retval EFI_NOT_FOUND               Variable not found\r
 \r
 **/\r
   @retval EFI_NOT_FOUND               Variable not found\r
 \r
 **/\r
@@ -966,12 +751,12 @@ FindVariable (
   VOID                    *Point;\r
 \r
   //\r
   VOID                    *Point;\r
 \r
   //\r
-  // 0: Volatile, 1: Non-Volatile\r
+  // 0: Volatile, 1: Non-Volatile.\r
   // The index and attributes mapping must be kept in this order as RuntimeServiceGetNextVariableName\r
   // The index and attributes mapping must be kept in this order as RuntimeServiceGetNextVariableName\r
-  // make use of this mapping to implement search algorithme.\r
+  // make use of this mapping to implement search algorithm.\r
   //\r
   VariableStoreHeader[0]  = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);\r
   //\r
   VariableStoreHeader[0]  = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);\r
-  VariableStoreHeader[1]  = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase);\r
+  VariableStoreHeader[1]  = mNvVariableCache;\r
 \r
   //\r
   // Start Pointers for the variable.\r
 \r
   //\r
   // Start Pointers for the variable.\r
@@ -985,7 +770,7 @@ FindVariable (
   }\r
 \r
   //\r
   }\r
 \r
   //\r
-  // Find the variable by walk through volatile and then non-volatile variable store\r
+  // Find the variable by walk through volatile and then non-volatile variable store.\r
   //\r
   InDeletedVariable     = NULL;\r
   InDeletedStorageIndex = 0;\r
   //\r
   InDeletedVariable     = NULL;\r
   InDeletedStorageIndex = 0;\r
@@ -994,7 +779,7 @@ FindVariable (
       if (Variable[Index]->State == VAR_ADDED || \r
           Variable[Index]->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)\r
          ) {\r
       if (Variable[Index]->State == VAR_ADDED || \r
           Variable[Index]->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)\r
          ) {\r
-        if (!EfiAtRuntime () || ((Variable[Index]->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) != 0)) {\r
+        if (!AtRuntime () || ((Variable[Index]->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) != 0)) {\r
           if (VariableName[0] == 0) {\r
             if (Variable[Index]->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
               InDeletedVariable     = Variable[Index];\r
           if (VariableName[0] == 0) {\r
             if (Variable[Index]->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
               InDeletedVariable     = Variable[Index];\r
@@ -1067,7 +852,7 @@ FindVariable (
   @param  Lang                        Configured language.\r
   @param  Iso639Language              A bool value to signify if the handler is operated on ISO639 or RFC4646.\r
 \r
   @param  Lang                        Configured language.\r
   @param  Iso639Language              A bool value to signify if the handler is operated on ISO639 or RFC4646.\r
 \r
-  @retval the index of language in the language codes.\r
+  @retval The index of language in the language codes.\r
 \r
 **/\r
 UINTN\r
 \r
 **/\r
 UINTN\r
@@ -1127,7 +912,7 @@ GetIndexFromSupportedLangCodes(
 /**\r
   Get language string from supported language codes according to index.\r
 \r
 /**\r
   Get language string from supported language codes according to index.\r
 \r
-  This code is used to get corresponding language string in supported language codes. It can handle\r
+  This code is used to get corresponding language strings in supported language codes. It can handle\r
   RFC4646 and ISO639 language tags.\r
   In ISO639 language tags, take 3-characters as a delimitation. Find language string according to the index.\r
   In RFC4646 language tags, take semicolon as a delimitation. Find language string according to the index.\r
   RFC4646 and ISO639 language tags.\r
   In ISO639 language tags, take 3-characters as a delimitation. Find language string according to the index.\r
   In RFC4646 language tags, take semicolon as a delimitation. Find language string according to the index.\r
@@ -1144,10 +929,10 @@ GetIndexFromSupportedLangCodes(
   The return value is "fr".\r
 \r
   @param  SupportedLang               Platform supported language codes.\r
   The return value is "fr".\r
 \r
   @param  SupportedLang               Platform supported language codes.\r
-  @param  Index                       the index in supported language codes.\r
+  @param  Index                       The index in supported language codes.\r
   @param  Iso639Language              A bool value to signify if the handler is operated on ISO639 or RFC4646.\r
 \r
   @param  Iso639Language              A bool value to signify if the handler is operated on ISO639 or RFC4646.\r
 \r
-  @retval the language string in the language codes.\r
+  @retval The language string in the language codes.\r
 \r
 **/\r
 CHAR8 *\r
 \r
 **/\r
 CHAR8 *\r
@@ -1165,18 +950,18 @@ GetLangFromSupportedLangCodes (
   Supported = SupportedLang;\r
   if (Iso639Language) {\r
     //\r
   Supported = SupportedLang;\r
   if (Iso639Language) {\r
     //\r
-    // according to the index of Lang string in SupportedLang string to get the language.\r
-    // As this code will be invoked in RUNTIME, therefore there is not memory allocate/free operation.\r
+    // According to the index of Lang string in SupportedLang string to get the language.\r
+    // This code will be invoked in RUNTIME, therefore there is not a memory allocate/free operation.\r
     // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.\r
     //\r
     CompareLength = ISO_639_2_ENTRY_SIZE;\r
     mVariableModuleGlobal->Lang[CompareLength] = '\0';\r
     return CopyMem (mVariableModuleGlobal->Lang, SupportedLang + Index * CompareLength, CompareLength);\r
     // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.\r
     //\r
     CompareLength = ISO_639_2_ENTRY_SIZE;\r
     mVariableModuleGlobal->Lang[CompareLength] = '\0';\r
     return CopyMem (mVariableModuleGlobal->Lang, SupportedLang + Index * CompareLength, CompareLength);\r
-\r
+      \r
   } else {\r
     while (TRUE) {\r
       //\r
   } else {\r
     while (TRUE) {\r
       //\r
-      // take semicolon as delimitation, sequentially traverse supported language codes.\r
+      // Take semicolon as delimitation, sequentially traverse supported language codes.\r
       //\r
       for (CompareLength = 0; *Supported != ';' && *Supported != '\0'; CompareLength++) {\r
         Supported++;\r
       //\r
       for (CompareLength = 0; *Supported != ';' && *Supported != '\0'; CompareLength++) {\r
         Supported++;\r
@@ -1191,7 +976,7 @@ GetLangFromSupportedLangCodes (
       }\r
       if (SubIndex == Index) {\r
         //\r
       }\r
       if (SubIndex == Index) {\r
         //\r
-        // according to the index of Lang string in SupportedLang string to get the language.\r
+        // According to the index of Lang string in SupportedLang string to get the language.\r
         // As this code will be invoked in RUNTIME, therefore there is not memory allocate/free operation.\r
         // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.\r
         //\r
         // As this code will be invoked in RUNTIME, therefore there is not memory allocate/free operation.\r
         // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.\r
         //\r
@@ -1199,7 +984,7 @@ GetLangFromSupportedLangCodes (
         return CopyMem (mVariableModuleGlobal->PlatformLang, Supported - CompareLength, CompareLength);\r
       }\r
       SubIndex++;\r
         return CopyMem (mVariableModuleGlobal->PlatformLang, Supported - CompareLength, CompareLength);\r
       }\r
       SubIndex++;\r
-      \r
+\r
       //\r
       // Skip ';' characters in Supported\r
       //\r
       //\r
       // Skip ';' characters in Supported\r
       //\r
@@ -1347,11 +1132,11 @@ VariableGetBestLanguage (
   According to UEFI spec, PlatformLangCodes/LangCodes are only set once in firmware initialization,\r
   and are read-only. Therefore, in variable driver, only store the original value for other use.\r
 \r
   According to UEFI spec, PlatformLangCodes/LangCodes are only set once in firmware initialization,\r
   and are read-only. Therefore, in variable driver, only store the original value for other use.\r
 \r
-  @param[in] VariableName       Name of variable\r
+  @param[in] VariableName       Name of variable.\r
 \r
 \r
-  @param[in] Data               Variable data\r
+  @param[in] Data               Variable data.\r
 \r
 \r
-  @param[in] DataSize           Size of data. 0 means delete\r
+  @param[in] DataSize           Size of data. 0 means delete.\r
 \r
 **/\r
 VOID\r
 \r
 **/\r
 VOID\r
@@ -1382,7 +1167,7 @@ AutoUpdateLangVariable(
     //\r
     // PlatformLangCodes is a volatile variable, so it can not be updated at runtime.\r
     //\r
     //\r
     // PlatformLangCodes is a volatile variable, so it can not be updated at runtime.\r
     //\r
-    if (EfiAtRuntime ()) {\r
+    if (AtRuntime ()) {\r
       return;\r
     }\r
 \r
       return;\r
     }\r
 \r
@@ -1412,7 +1197,7 @@ AutoUpdateLangVariable(
     //\r
     // LangCodes is a volatile variable, so it can not be updated at runtime.\r
     //\r
     //\r
     // LangCodes is a volatile variable, so it can not be updated at runtime.\r
     //\r
-    if (EfiAtRuntime ()) {\r
+    if (AtRuntime ()) {\r
       return;\r
     }\r
 \r
       return;\r
     }\r
 \r
@@ -1492,7 +1277,8 @@ AutoUpdateLangVariable(
         //\r
         FindVariable (L"Lang", &gEfiGlobalVariableGuid, &Variable, (VARIABLE_GLOBAL *)mVariableModuleGlobal);\r
 \r
         //\r
         FindVariable (L"Lang", &gEfiGlobalVariableGuid, &Variable, (VARIABLE_GLOBAL *)mVariableModuleGlobal);\r
 \r
-        Status = UpdateVariable (L"Lang", &gEfiGlobalVariableGuid, BestLang, ISO_639_2_ENTRY_SIZE + 1, Attributes, &Variable);\r
+        Status = UpdateVariable (L"Lang", &gEfiGlobalVariableGuid, BestLang,\r
+                                 ISO_639_2_ENTRY_SIZE + 1, Attributes, &Variable);\r
 \r
         DEBUG ((EFI_D_INFO, "Variable Driver Auto Update PlatformLang, PlatformLang:%a, Lang:%a\n", BestPlatformLang, BestLang));\r
 \r
 \r
         DEBUG ((EFI_D_INFO, "Variable Driver Auto Update PlatformLang, PlatformLang:%a, Lang:%a\n", BestPlatformLang, BestLang));\r
 \r
@@ -1539,32 +1325,25 @@ AutoUpdateLangVariable(
   Update the variable region with Variable information. These are the same \r
   arguments as the EFI Variable services.\r
 \r
   Update the variable region with Variable information. These are the same \r
   arguments as the EFI Variable services.\r
 \r
-  @param[in] VariableName       Name of variable\r
-\r
-  @param[in] VendorGuid         Guid of variable\r
-\r
-  @param[in] Data               Variable data\r
-\r
-  @param[in] DataSize           Size of data. 0 means delete\r
-\r
-  @param[in] Attributes         Attribues of the variable\r
-\r
-  @param[in] Variable           The variable information which is used to keep track of variable usage.\r
-\r
+  @param[in] VariableName       Name of variable.\r
+  @param[in] VendorGuid         Guid of variable.\r
+  @param[in] Data               Variable data.\r
+  @param[in] DataSize           Size of data. 0 means delete.\r
+  @param[in] Attributes         Attribues of the variable.\r
+  @param[in] CacheVariable      The variable information which is used to keep track of variable usage.\r
+  \r
   @retval EFI_SUCCESS           The update operation is success.\r
   @retval EFI_SUCCESS           The update operation is success.\r
-\r
   @retval EFI_OUT_OF_RESOURCES  Variable region is full, can not write other data into this region.\r
 \r
 **/\r
 EFI_STATUS\r
   @retval EFI_OUT_OF_RESOURCES  Variable region is full, can not write other data into this region.\r
 \r
 **/\r
 EFI_STATUS\r
-EFIAPI\r
 UpdateVariable (\r
 UpdateVariable (\r
-  IN      CHAR16          *VariableName,\r
-  IN      EFI_GUID        *VendorGuid,\r
-  IN      VOID            *Data,\r
-  IN      UINTN           DataSize,\r
-  IN      UINT32          Attributes OPTIONAL,\r
-  IN      VARIABLE_POINTER_TRACK *Variable\r
+  IN      CHAR16                      *VariableName,\r
+  IN      EFI_GUID                    *VendorGuid,\r
+  IN      VOID                        *Data,\r
+  IN      UINTN                       DataSize,\r
+  IN      UINT32                      Attributes      OPTIONAL,\r
+  IN      VARIABLE_POINTER_TRACK      *CacheVariable\r
   )\r
 {\r
   EFI_STATUS                          Status;\r
   )\r
 {\r
   EFI_STATUS                          Status;\r
@@ -1579,19 +1358,47 @@ UpdateVariable (
   EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *Fvb;\r
   UINT8                               State;\r
   BOOLEAN                             Reclaimed;\r
   EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *Fvb;\r
   UINT8                               State;\r
   BOOLEAN                             Reclaimed;\r
+  VARIABLE_POINTER_TRACK              *Variable;\r
+  VARIABLE_POINTER_TRACK              NvVariable;\r
+  VARIABLE_STORE_HEADER               *VariableStoreHeader;\r
+  UINTN                               CacheOffset;\r
 \r
 \r
+  if (CacheVariable->Volatile) {\r
+    Variable = CacheVariable;\r
+  } else {\r
+    if (mVariableModuleGlobal->FvbInstance == NULL) {\r
+      //\r
+      // Trying to update NV variable prior to the installation of EFI_VARIABLE_WRITE_ARCH_PROTOCOL\r
+      //\r
+      return EFI_NOT_AVAILABLE_YET;\r
+    }\r
+    \r
+    //\r
+    // CacheVariable points to the variable in the memory copy of Flash area\r
+    // Now let Variable points to the same variable in Flash area.\r
+    //\r
+    VariableStoreHeader  = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase);\r
+    Variable = &NvVariable;    \r
+    Variable->StartPtr = GetStartPointer (VariableStoreHeader);\r
+    Variable->EndPtr   = GetEndPointer (VariableStoreHeader);\r
+    if (CacheVariable->CurrPtr == NULL) {\r
+      Variable->CurrPtr = NULL;\r
+    } else {\r
+      Variable->CurrPtr = (VARIABLE_HEADER *)((UINTN)Variable->StartPtr + ((UINTN)CacheVariable->CurrPtr - (UINTN)CacheVariable->StartPtr));\r
+    }\r
+    Variable->Volatile  = FALSE;\r
+  }\r
+  \r
   Fvb               = mVariableModuleGlobal->FvbInstance;\r
   Reclaimed         = FALSE;\r
 \r
   if (Variable->CurrPtr != NULL) {\r
     //\r
   Fvb               = mVariableModuleGlobal->FvbInstance;\r
   Reclaimed         = FALSE;\r
 \r
   if (Variable->CurrPtr != NULL) {\r
     //\r
-    // Update/Delete existing variable\r
+    // Update/Delete existing variable.\r
     //\r
     //\r
-    Volatile = Variable->Volatile;\r
-    \r
-    if (EfiAtRuntime ()) {        \r
+    if (AtRuntime ()) {        \r
       //\r
       //\r
-      // If EfiAtRuntime and the variable is Volatile and Runtime Access,  \r
+      // If AtRuntime and the variable is Volatile and Runtime Access,  \r
       // the volatile is ReadOnly, and SetVariable should be aborted and \r
       // return EFI_WRITE_PROTECTED.\r
       //\r
       // the volatile is ReadOnly, and SetVariable should be aborted and \r
       // return EFI_WRITE_PROTECTED.\r
       //\r
@@ -1600,16 +1407,17 @@ UpdateVariable (
         goto Done;\r
       }\r
       //\r
         goto Done;\r
       }\r
       //\r
-      // Only variable have NV attribute can be updated/deleted in Runtime\r
+      // Only variable that have NV attributes can be updated/deleted in Runtime.\r
       //\r
       if ((Variable->CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {\r
         Status = EFI_INVALID_PARAMETER;\r
         goto Done;      \r
       }\r
     }\r
       //\r
       if ((Variable->CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {\r
         Status = EFI_INVALID_PARAMETER;\r
         goto Done;      \r
       }\r
     }\r
+\r
     //\r
     // Setting a data variable with no access, or zero DataSize attributes\r
     //\r
     // Setting a data variable with no access, or zero DataSize attributes\r
-    // specified causes it to be deleted.\r
+    // causes it to be deleted.\r
     //\r
     if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) {    \r
       State = Variable->CurrPtr->State;\r
     //\r
     if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) {    \r
       State = Variable->CurrPtr->State;\r
@@ -1625,26 +1433,28 @@ UpdateVariable (
                  &State\r
                  ); \r
       if (!EFI_ERROR (Status)) {\r
                  &State\r
                  ); \r
       if (!EFI_ERROR (Status)) {\r
-        UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, FALSE, TRUE, FALSE);\r
-        UpdateVariableCache (VariableName, VendorGuid, Attributes, DataSize, Data);\r
+        UpdateVariableInfo (VariableName, VendorGuid, Variable->Volatile, FALSE, FALSE, TRUE, FALSE);\r
+        if (!Variable->Volatile) {\r
+          CacheVariable->CurrPtr->State = State;\r
+        }\r
       }\r
       goto Done;     \r
     }\r
     //\r
       }\r
       goto Done;     \r
     }\r
     //\r
-    // If the variable is marked valid and the same data has been passed in\r
+    // If the variable is marked valid, and the same data has been passed in,\r
     // then return to the caller immediately.\r
     //\r
     if (DataSizeOfVariable (Variable->CurrPtr) == DataSize &&\r
         (CompareMem (Data, GetVariableDataPtr (Variable->CurrPtr), DataSize) == 0)) {\r
       \r
     // then return to the caller immediately.\r
     //\r
     if (DataSizeOfVariable (Variable->CurrPtr) == DataSize &&\r
         (CompareMem (Data, GetVariableDataPtr (Variable->CurrPtr), DataSize) == 0)) {\r
       \r
-      UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, TRUE, FALSE, FALSE);\r
+      UpdateVariableInfo (VariableName, VendorGuid, Variable->Volatile, FALSE, TRUE, FALSE, FALSE);\r
       Status = EFI_SUCCESS;\r
       goto Done;\r
     } else if ((Variable->CurrPtr->State == VAR_ADDED) ||\r
                (Variable->CurrPtr->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION))) {\r
 \r
       //\r
       Status = EFI_SUCCESS;\r
       goto Done;\r
     } else if ((Variable->CurrPtr->State == VAR_ADDED) ||\r
                (Variable->CurrPtr->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION))) {\r
 \r
       //\r
-      // Mark the old variable as in delete transition\r
+      // Mark the old variable as in delete transition.\r
       //\r
       State = Variable->CurrPtr->State;\r
       State &= VAR_IN_DELETED_TRANSITION;\r
       //\r
       State = Variable->CurrPtr->State;\r
       State &= VAR_IN_DELETED_TRANSITION;\r
@@ -1661,15 +1471,18 @@ UpdateVariable (
       if (EFI_ERROR (Status)) {\r
         goto Done;  \r
       } \r
       if (EFI_ERROR (Status)) {\r
         goto Done;  \r
       } \r
+      if (!Variable->Volatile) {\r
+        CacheVariable->CurrPtr->State = State;\r
+      }\r
     }    \r
   } else {\r
     //\r
     }    \r
   } else {\r
     //\r
-    // Not found existing variable. Create a new variable\r
+    // Not found existing variable. Create a new variable.\r
     //  \r
     \r
     //\r
     // Make sure we are trying to create a new variable.\r
     //  \r
     \r
     //\r
     // Make sure we are trying to create a new variable.\r
-    // Setting a data variable with no access, or zero DataSize attributes means to delete it.    \r
+    // Setting a data variable with zero DataSize or no access attributes means to delete it.    \r
     //\r
     if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) {\r
       Status = EFI_NOT_FOUND;\r
     //\r
     if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) {\r
       Status = EFI_NOT_FOUND;\r
@@ -1677,9 +1490,9 @@ UpdateVariable (
     }\r
         \r
     //\r
     }\r
         \r
     //\r
-    // Only variable have NV|RT attribute can be created in Runtime\r
+    // Only variable have NV|RT attribute can be created in Runtime.\r
     //\r
     //\r
-    if (EfiAtRuntime () &&\r
+    if (AtRuntime () &&\r
         (((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) || ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0))) {\r
       Status = EFI_INVALID_PARAMETER;\r
       goto Done;\r
         (((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) || ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0))) {\r
       Status = EFI_INVALID_PARAMETER;\r
       goto Done;\r
@@ -1689,6 +1502,7 @@ UpdateVariable (
   //\r
   // Function part - create a new variable and copy the data.\r
   // Both update a variable and create a variable will come here.\r
   //\r
   // Function part - create a new variable and copy the data.\r
   // Both update a variable and create a variable will come here.\r
+\r
   //\r
   // Tricky part: Use scratch data area at the end of volatile variable store\r
   // as a temporary storage.\r
   //\r
   // Tricky part: Use scratch data area at the end of volatile variable store\r
   // as a temporary storage.\r
@@ -1703,9 +1517,9 @@ UpdateVariable (
   //\r
   // NextVariable->State = VAR_ADDED;\r
   //\r
   //\r
   // NextVariable->State = VAR_ADDED;\r
   //\r
-  NextVariable->Reserved  = 0;\r
-  VarNameOffset           = sizeof (VARIABLE_HEADER);\r
-  VarNameSize             = StrSize (VariableName);\r
+  NextVariable->Reserved        = 0;\r
+  VarNameOffset                 = sizeof (VARIABLE_HEADER);\r
+  VarNameSize                   = StrSize (VariableName);\r
   CopyMem (\r
     (UINT8 *) ((UINTN) NextVariable + VarNameOffset),\r
     VariableName,\r
   CopyMem (\r
     (UINT8 *) ((UINTN) NextVariable + VarNameOffset),\r
     VariableName,\r
@@ -1721,7 +1535,7 @@ UpdateVariable (
   //\r
   // There will be pad bytes after Data, the NextVariable->NameSize and\r
   // NextVariable->DataSize should not include pad size so that variable\r
   //\r
   // There will be pad bytes after Data, the NextVariable->NameSize and\r
   // NextVariable->DataSize should not include pad size so that variable\r
-  // service can get actual size in GetVariable\r
+  // service can get actual size in GetVariable.\r
   //\r
   NextVariable->NameSize  = (UINT32)VarNameSize;\r
   NextVariable->DataSize  = (UINT32)DataSize;\r
   //\r
   NextVariable->NameSize  = (UINT32)VarNameSize;\r
   NextVariable->DataSize  = (UINT32)DataSize;\r
@@ -1733,7 +1547,7 @@ UpdateVariable (
   VarSize = VarDataOffset + DataSize + GET_PAD_SIZE (DataSize);\r
   if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {\r
     //\r
   VarSize = VarDataOffset + DataSize + GET_PAD_SIZE (DataSize);\r
   if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {\r
     //\r
-    // Create a nonvolatile variable\r
+    // Create a nonvolatile variable.\r
     //\r
     Volatile = FALSE;\r
     NonVolatileVarableStoreSize = ((VARIABLE_STORE_HEADER *)(UINTN)(mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase))->Size;\r
     //\r
     Volatile = FALSE;\r
     NonVolatileVarableStoreSize = ((VARIABLE_STORE_HEADER *)(UINTN)(mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase))->Size;\r
@@ -1741,12 +1555,12 @@ UpdateVariable (
       && ((VarSize + mVariableModuleGlobal->HwErrVariableTotalSize) > PcdGet32 (PcdHwErrStorageSize)))\r
       || (((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0) \r
       && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > NonVolatileVarableStoreSize - sizeof (VARIABLE_STORE_HEADER) - PcdGet32 (PcdHwErrStorageSize)))) {\r
       && ((VarSize + mVariableModuleGlobal->HwErrVariableTotalSize) > PcdGet32 (PcdHwErrStorageSize)))\r
       || (((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0) \r
       && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > NonVolatileVarableStoreSize - sizeof (VARIABLE_STORE_HEADER) - PcdGet32 (PcdHwErrStorageSize)))) {\r
-      if (EfiAtRuntime ()) {\r
+      if (AtRuntime ()) {\r
         Status = EFI_OUT_OF_RESOURCES;\r
         goto Done;\r
       }\r
       //\r
         Status = EFI_OUT_OF_RESOURCES;\r
         goto Done;\r
       }\r
       //\r
-      // Perform garbage collection & reclaim operation\r
+      // Perform garbage collection & reclaim operation.\r
       //\r
       Status = Reclaim (mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase, \r
                         &mVariableModuleGlobal->NonVolatileLastVariableOffset, FALSE, Variable->CurrPtr);\r
       //\r
       Status = Reclaim (mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase, \r
                         &mVariableModuleGlobal->NonVolatileLastVariableOffset, FALSE, Variable->CurrPtr);\r
@@ -1754,7 +1568,7 @@ UpdateVariable (
         goto Done;\r
       }\r
       //\r
         goto Done;\r
       }\r
       //\r
-      // If still no enough space, return out of resources\r
+      // If still no enough space, return out of resources.\r
       //\r
       if ((((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) \r
         && ((VarSize + mVariableModuleGlobal->HwErrVariableTotalSize) > PcdGet32 (PcdHwErrStorageSize)))\r
       //\r
       if ((((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) \r
         && ((VarSize + mVariableModuleGlobal->HwErrVariableTotalSize) > PcdGet32 (PcdHwErrStorageSize)))\r
@@ -1766,7 +1580,7 @@ UpdateVariable (
       Reclaimed = TRUE;\r
     }\r
     //\r
       Reclaimed = TRUE;\r
     }\r
     //\r
-    // Three steps\r
+    // Four steps\r
     // 1. Write variable header\r
     // 2. Set variable state to header valid  \r
     // 3. Write variable data\r
     // 1. Write variable header\r
     // 2. Set variable state to header valid  \r
     // 3. Write variable data\r
@@ -1775,6 +1589,7 @@ UpdateVariable (
     //\r
     // Step 1:\r
     //\r
     //\r
     // Step 1:\r
     //\r
+    CacheOffset = mVariableModuleGlobal->NonVolatileLastVariableOffset;\r
     Status = UpdateVariableStore (\r
                &mVariableModuleGlobal->VariableGlobal,\r
                FALSE,\r
     Status = UpdateVariableStore (\r
                &mVariableModuleGlobal->VariableGlobal,\r
                FALSE,\r
@@ -1798,9 +1613,9 @@ UpdateVariable (
                FALSE,\r
                TRUE,\r
                Fvb,\r
                FALSE,\r
                TRUE,\r
                Fvb,\r
-               mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
-               sizeof (VARIABLE_HEADER),\r
-               (UINT8 *) NextVariable\r
+               mVariableModuleGlobal->NonVolatileLastVariableOffset + OFFSET_OF (VARIABLE_HEADER, State),\r
+               sizeof (UINT8),\r
+               &NextVariable->State\r
                );\r
 \r
     if (EFI_ERROR (Status)) {\r
                );\r
 \r
     if (EFI_ERROR (Status)) {\r
@@ -1831,9 +1646,9 @@ UpdateVariable (
                FALSE,\r
                TRUE,\r
                Fvb,\r
                FALSE,\r
                TRUE,\r
                Fvb,\r
-               mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
-               sizeof (VARIABLE_HEADER),\r
-               (UINT8 *) NextVariable\r
+               mVariableModuleGlobal->NonVolatileLastVariableOffset + OFFSET_OF (VARIABLE_HEADER, State),\r
+               sizeof (UINT8),\r
+               &NextVariable->State\r
                );\r
 \r
     if (EFI_ERROR (Status)) {\r
                );\r
 \r
     if (EFI_ERROR (Status)) {\r
@@ -1847,16 +1662,20 @@ UpdateVariable (
     } else {\r
       mVariableModuleGlobal->CommonVariableTotalSize += HEADER_ALIGN (VarSize);\r
     }\r
     } else {\r
       mVariableModuleGlobal->CommonVariableTotalSize += HEADER_ALIGN (VarSize);\r
     }\r
+    //\r
+    // update the memory copy of Flash region.\r
+    //\r
+    CopyMem ((UINT8 *)mNvVariableCache + CacheOffset, (UINT8 *)NextVariable, VarSize);\r
   } else {\r
     //\r
   } else {\r
     //\r
-    // Create a volatile variable\r
+    // Create a volatile variable.\r
     //      \r
     Volatile = TRUE;\r
 \r
     if ((UINT32) (VarSize + mVariableModuleGlobal->VolatileLastVariableOffset) >\r
         ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase)))->Size) {\r
       //\r
     //      \r
     Volatile = TRUE;\r
 \r
     if ((UINT32) (VarSize + mVariableModuleGlobal->VolatileLastVariableOffset) >\r
         ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase)))->Size) {\r
       //\r
-      // Perform garbage collection & reclaim operation\r
+      // Perform garbage collection & reclaim operation.\r
       //\r
       Status = Reclaim (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase, \r
                           &mVariableModuleGlobal->VolatileLastVariableOffset, TRUE, Variable->CurrPtr);\r
       //\r
       Status = Reclaim (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase, \r
                           &mVariableModuleGlobal->VolatileLastVariableOffset, TRUE, Variable->CurrPtr);\r
@@ -1864,7 +1683,7 @@ UpdateVariable (
         goto Done;\r
       }\r
       //\r
         goto Done;\r
       }\r
       //\r
-      // If still no enough space, return out of resources\r
+      // If still no enough space, return out of resources.\r
       //\r
       if ((UINT32) (VarSize + mVariableModuleGlobal->VolatileLastVariableOffset) >\r
             ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase)))->Size\r
       //\r
       if ((UINT32) (VarSize + mVariableModuleGlobal->VolatileLastVariableOffset) >\r
             ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase)))->Size\r
@@ -1894,7 +1713,7 @@ UpdateVariable (
   }\r
 \r
   //\r
   }\r
 \r
   //\r
-  // Mark the old variable as deleted\r
+  // Mark the old variable as deleted.\r
   //\r
   if (!Reclaimed && !EFI_ERROR (Status) && Variable->CurrPtr != NULL) {\r
     State = Variable->CurrPtr->State;\r
   //\r
   if (!Reclaimed && !EFI_ERROR (Status) && Variable->CurrPtr != NULL) {\r
     State = Variable->CurrPtr->State;\r
@@ -1909,11 +1728,13 @@ UpdateVariable (
              sizeof (UINT8),\r
              &State\r
              );\r
              sizeof (UINT8),\r
              &State\r
              );\r
+    if (!EFI_ERROR (Status) && !Variable->Volatile) {         \r
+      CacheVariable->CurrPtr->State = State;\r
+    }\r
   }\r
 \r
   if (!EFI_ERROR (Status)) {\r
     UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, TRUE, FALSE, FALSE);\r
   }\r
 \r
   if (!EFI_ERROR (Status)) {\r
     UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, TRUE, FALSE, FALSE);\r
-    UpdateVariableCache (VariableName, VendorGuid, Attributes, DataSize, Data);\r
   }\r
 \r
 Done:\r
   }\r
 \r
 Done:\r
@@ -1931,15 +1752,15 @@ Done:
                                     data, this value contains the required size.\r
   @param Data                       Data pointer.\r
                       \r
                                     data, this value contains the required size.\r
   @param Data                       Data pointer.\r
                       \r
-  @return EFI_INVALID_PARAMETER     Invalid parameter\r
-  @return EFI_SUCCESS               Find the specified variable\r
-  @return EFI_NOT_FOUND             Not found\r
-  @return EFI_BUFFER_TO_SMALL       DataSize is too small for the result\r
+  @return EFI_INVALID_PARAMETER     Invalid parameter.\r
+  @return EFI_SUCCESS               Find the specified variable.\r
+  @return EFI_NOT_FOUND             Not found.\r
+  @return EFI_BUFFER_TO_SMALL       DataSize is too small for the result.\r
 \r
 **/\r
 EFI_STATUS\r
 EFIAPI\r
 \r
 **/\r
 EFI_STATUS\r
 EFIAPI\r
-RuntimeServiceGetVariable (\r
+VariableServiceGetVariable (\r
   IN      CHAR16            *VariableName,\r
   IN      EFI_GUID          *VendorGuid,\r
   OUT     UINT32            *Attributes OPTIONAL,\r
   IN      CHAR16            *VariableName,\r
   IN      EFI_GUID          *VendorGuid,\r
   OUT     UINT32            *Attributes OPTIONAL,\r
@@ -1956,16 +1777,6 @@ RuntimeServiceGetVariable (
   }\r
 \r
   AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
   }\r
 \r
   AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
-\r
-  //\r
-  // Find existing variable\r
-  //\r
-  Status = FindVariableInCache (VariableName, VendorGuid, Attributes, DataSize, Data);\r
-  if ((Status == EFI_BUFFER_TOO_SMALL) || (Status == EFI_SUCCESS)){\r
-    // Hit in the Cache\r
-    UpdateVariableInfo (VariableName, VendorGuid, FALSE, TRUE, FALSE, FALSE, TRUE);\r
-    goto Done;\r
-  }\r
   \r
   Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal);\r
   if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {\r
   \r
   Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal);\r
   if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {\r
@@ -1991,7 +1802,6 @@ RuntimeServiceGetVariable (
 \r
     *DataSize = VarDataSize;\r
     UpdateVariableInfo (VariableName, VendorGuid, Variable.Volatile, TRUE, FALSE, FALSE, FALSE);\r
 \r
     *DataSize = VarDataSize;\r
     UpdateVariableInfo (VariableName, VendorGuid, Variable.Volatile, TRUE, FALSE, FALSE, FALSE);\r
-    UpdateVariableCache (VariableName, VendorGuid, Variable.CurrPtr->Attributes, VarDataSize, Data);\r
  \r
     Status = EFI_SUCCESS;\r
     goto Done;\r
  \r
     Status = EFI_SUCCESS;\r
     goto Done;\r
@@ -2012,19 +1822,19 @@ Done:
 \r
   This code Finds the Next available variable.\r
 \r
 \r
   This code Finds the Next available variable.\r
 \r
-  @param VariableNameSize           Size of the variable name\r
-  @param VariableName               Pointer to variable name\r
-  @param VendorGuid                 Variable Vendor Guid\r
+  @param VariableNameSize           Size of the variable name.\r
+  @param VariableName               Pointer to variable name.\r
+  @param VendorGuid                 Variable Vendor Guid.\r
 \r
 \r
-  @return EFI_INVALID_PARAMETER     Invalid parameter\r
-  @return EFI_SUCCESS               Find the specified variable\r
-  @return EFI_NOT_FOUND             Not found\r
-  @return EFI_BUFFER_TO_SMALL       DataSize is too small for the result\r
+  @return EFI_INVALID_PARAMETER     Invalid parameter.\r
+  @return EFI_SUCCESS               Find the specified variable.\r
+  @return EFI_NOT_FOUND             Not found.\r
+  @return EFI_BUFFER_TO_SMALL       DataSize is too small for the result.\r
 \r
 **/\r
 EFI_STATUS\r
 EFIAPI\r
 \r
 **/\r
 EFI_STATUS\r
 EFIAPI\r
-RuntimeServiceGetNextVariableName (\r
+VariableServiceGetNextVariableName (\r
   IN OUT  UINTN             *VariableNameSize,\r
   IN OUT  CHAR16            *VariableName,\r
   IN OUT  EFI_GUID          *VendorGuid\r
   IN OUT  UINTN             *VariableNameSize,\r
   IN OUT  CHAR16            *VariableName,\r
   IN OUT  EFI_GUID          *VendorGuid\r
@@ -2047,7 +1857,7 @@ RuntimeServiceGetNextVariableName (
 \r
   if (VariableName[0] != 0) {\r
     //\r
 \r
   if (VariableName[0] != 0) {\r
     //\r
-    // If variable name is not NULL, get next variable\r
+    // If variable name is not NULL, get next variable.\r
     //\r
     Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);\r
   }\r
     //\r
     Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);\r
   }\r
@@ -2055,7 +1865,7 @@ RuntimeServiceGetNextVariableName (
   while (TRUE) {\r
     //\r
     // If both volatile and non-volatile variable store are parsed,\r
   while (TRUE) {\r
     //\r
     // If both volatile and non-volatile variable store are parsed,\r
-    // return not found\r
+    // return not found.\r
     //\r
     if (Variable.CurrPtr >= Variable.EndPtr || Variable.CurrPtr == NULL) {\r
       Variable.Volatile = (BOOLEAN) (Variable.Volatile ^ ((BOOLEAN) 0x1));\r
     //\r
     if (Variable.CurrPtr >= Variable.EndPtr || Variable.CurrPtr == NULL) {\r
       Variable.Volatile = (BOOLEAN) (Variable.Volatile ^ ((BOOLEAN) 0x1));\r
@@ -2076,7 +1886,7 @@ RuntimeServiceGetNextVariableName (
     // Variable is found\r
     //\r
     if (IsValidVariableHeader (Variable.CurrPtr) && Variable.CurrPtr->State == VAR_ADDED) {\r
     // Variable is found\r
     //\r
     if (IsValidVariableHeader (Variable.CurrPtr) && Variable.CurrPtr->State == VAR_ADDED) {\r
-      if ((EfiAtRuntime () && ((Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)) == 0) {\r
+      if ((AtRuntime () && ((Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)) == 0) {\r
         VarNameSize = NameSizeOfVariable (Variable.CurrPtr);\r
         ASSERT (VarNameSize != 0);\r
 \r
         VarNameSize = NameSizeOfVariable (Variable.CurrPtr);\r
         ASSERT (VarNameSize != 0);\r
 \r
@@ -2113,23 +1923,23 @@ Done:
 \r
   This code sets variable in storage blocks (Volatile or Non-Volatile).\r
 \r
 \r
   This code sets variable in storage blocks (Volatile or Non-Volatile).\r
 \r
-  @param VariableName                     Name of Variable to be found\r
-  @param VendorGuid                       Variable vendor GUID\r
+  @param VariableName                     Name of Variable to be found.\r
+  @param VendorGuid                       Variable vendor GUID.\r
   @param Attributes                       Attribute value of the variable found\r
   @param DataSize                         Size of Data found. If size is less than the\r
                                           data, this value contains the required size.\r
   @param Attributes                       Attribute value of the variable found\r
   @param DataSize                         Size of Data found. If size is less than the\r
                                           data, this value contains the required size.\r
-  @param Data                             Data pointer\r
+  @param Data                             Data pointer.\r
 \r
 \r
-  @return EFI_INVALID_PARAMETER           Invalid parameter\r
-  @return EFI_SUCCESS                     Set successfully\r
-  @return EFI_OUT_OF_RESOURCES            Resource not enough to set variable\r
-  @return EFI_NOT_FOUND                   Not found\r
-  @return EFI_WRITE_PROTECTED             Variable is read-only\r
+  @return EFI_INVALID_PARAMETER           Invalid parameter.\r
+  @return EFI_SUCCESS                     Set successfully.\r
+  @return EFI_OUT_OF_RESOURCES            Resource not enough to set variable.\r
+  @return EFI_NOT_FOUND                   Not found.\r
+  @return EFI_WRITE_PROTECTED             Variable is read-only.\r
 \r
 **/\r
 EFI_STATUS\r
 EFIAPI\r
 \r
 **/\r
 EFI_STATUS\r
 EFIAPI\r
-RuntimeServiceSetVariable (\r
+VariableServiceSetVariable (\r
   IN CHAR16                  *VariableName,\r
   IN EFI_GUID                *VendorGuid,\r
   IN UINT32                  Attributes,\r
   IN CHAR16                  *VariableName,\r
   IN EFI_GUID                *VendorGuid,\r
   IN UINT32                  Attributes,\r
@@ -2143,11 +1953,11 @@ RuntimeServiceSetVariable (
   EFI_PHYSICAL_ADDRESS                Point;\r
 \r
   //\r
   EFI_PHYSICAL_ADDRESS                Point;\r
 \r
   //\r
-  // Check input parameters\r
+  // Check input parameters.\r
   //\r
   if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {\r
     return EFI_INVALID_PARAMETER;\r
   //\r
   if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {\r
     return EFI_INVALID_PARAMETER;\r
-  }\r
+  } \r
 \r
   if (DataSize != 0 && Data == NULL) {\r
     return EFI_INVALID_PARAMETER;\r
 \r
   if (DataSize != 0 && Data == NULL) {\r
     return EFI_INVALID_PARAMETER;\r
@@ -2161,7 +1971,7 @@ RuntimeServiceSetVariable (
   }\r
 \r
   //\r
   }\r
 \r
   //\r
-  //  Make sure if runtime bit is set, boot service bit is set also\r
+  //  Make sure if runtime bit is set, boot service bit is set also.\r
   //\r
   if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {\r
     return EFI_INVALID_PARAMETER;\r
   //\r
   if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {\r
     return EFI_INVALID_PARAMETER;\r
@@ -2178,7 +1988,7 @@ RuntimeServiceSetVariable (
       return EFI_INVALID_PARAMETER;\r
     }\r
     //\r
       return EFI_INVALID_PARAMETER;\r
     }\r
     //\r
-    // According to UEFI spec, HARDWARE_ERROR_RECORD variable name convention should be L"HwErrRecXXXX"\r
+    // According to UEFI spec, HARDWARE_ERROR_RECORD variable name convention should be L"HwErrRecXXXX".\r
     //\r
     if (StrnCmp(VariableName, L"HwErrRec", StrLen(L"HwErrRec")) != 0) {\r
       return EFI_INVALID_PARAMETER;\r
     //\r
     if (StrnCmp(VariableName, L"HwErrRec", StrLen(L"HwErrRec")) != 0) {\r
       return EFI_INVALID_PARAMETER;\r
@@ -2197,12 +2007,12 @@ RuntimeServiceSetVariable (
   AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
 \r
   //\r
   AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
 \r
   //\r
-  // Consider reentrant in MCA/INIT/NMI. It needs be reupdated;\r
+  // Consider reentrant in MCA/INIT/NMI. It needs be reupdated.\r
   //\r
   if (1 < InterlockedIncrement (&mVariableModuleGlobal->VariableGlobal.ReentrantState)) {\r
   //\r
   if (1 < InterlockedIncrement (&mVariableModuleGlobal->VariableGlobal.ReentrantState)) {\r
-    Point = mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;;\r
+    Point = mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;\r
     //\r
     //\r
-    // Parse non-volatile variable data and get last variable offset\r
+    // Parse non-volatile variable data and get last variable offset.\r
     //\r
     NextVariable  = GetStartPointer ((VARIABLE_STORE_HEADER *) (UINTN) Point);\r
     while ((NextVariable < GetEndPointer ((VARIABLE_STORE_HEADER *) (UINTN) Point)) \r
     //\r
     NextVariable  = GetStartPointer ((VARIABLE_STORE_HEADER *) (UINTN) Point);\r
     while ((NextVariable < GetEndPointer ((VARIABLE_STORE_HEADER *) (UINTN) Point)) \r
@@ -2213,12 +2023,12 @@ RuntimeServiceSetVariable (
   }\r
 \r
   //\r
   }\r
 \r
   //\r
-  // Check whether the input variable is already existed\r
+  // Check whether the input variable is already existed.\r
   //\r
   FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal);\r
 \r
   //\r
   //\r
   FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal);\r
 \r
   //\r
-  // Hook the operation of setting PlatformLangCodes/PlatformLang and LangCodes/Lang\r
+  // Hook the operation of setting PlatformLangCodes/PlatformLang and LangCodes/Lang.\r
   //\r
   AutoUpdateLangVariable (VariableName, Data, DataSize);\r
 \r
   //\r
   AutoUpdateLangVariable (VariableName, Data, DataSize);\r
 \r
@@ -2250,7 +2060,7 @@ RuntimeServiceSetVariable (
 **/\r
 EFI_STATUS\r
 EFIAPI\r
 **/\r
 EFI_STATUS\r
 EFIAPI\r
-RuntimeServiceQueryVariableInfo (\r
+VariableServiceQueryVariableInfo (\r
   IN  UINT32                 Attributes,\r
   OUT UINT64                 *MaximumVariableStorageSize,\r
   OUT UINT64                 *RemainingVariableStorageSize,\r
   IN  UINT32                 Attributes,\r
   OUT UINT64                 *MaximumVariableStorageSize,\r
   OUT UINT64                 *RemainingVariableStorageSize,\r
@@ -2281,7 +2091,7 @@ RuntimeServiceQueryVariableInfo (
     // Make sure if runtime bit is set, boot service bit is set also.\r
     //\r
     return EFI_INVALID_PARAMETER;\r
     // Make sure if runtime bit is set, boot service bit is set also.\r
     //\r
     return EFI_INVALID_PARAMETER;\r
-  } else if (EfiAtRuntime () && ((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)) {\r
+  } else if (AtRuntime () && ((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)) {\r
     //\r
     // Make sure RT Attribute is set if we are in Runtime phase.\r
     //\r
     //\r
     // Make sure RT Attribute is set if we are in Runtime phase.\r
     //\r
@@ -2309,7 +2119,7 @@ RuntimeServiceQueryVariableInfo (
     //\r
     // Query is Non-Volatile related.\r
     //\r
     //\r
     // Query is Non-Volatile related.\r
     //\r
-    VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase);\r
+    VariableStoreHeader = mNvVariableCache;\r
   }\r
 \r
   //\r
   }\r
 \r
   //\r
@@ -2348,9 +2158,9 @@ RuntimeServiceQueryVariableInfo (
     NextVariable = GetNextVariablePtr (Variable);\r
     VariableSize = (UINT64) (UINTN) NextVariable - (UINT64) (UINTN) Variable;\r
 \r
     NextVariable = GetNextVariablePtr (Variable);\r
     VariableSize = (UINT64) (UINTN) NextVariable - (UINT64) (UINTN) Variable;\r
 \r
-    if (EfiAtRuntime ()) {\r
+    if (AtRuntime ()) {\r
       //\r
       //\r
-      // we don't take the state of the variables in mind\r
+      // We don't take the state of the variables in mind\r
       // when calculating RemainingVariableStorageSize,\r
       // since the space occupied by variables not marked with\r
       // VAR_ADDED is not allowed to be reclaimed in Runtime.\r
       // when calculating RemainingVariableStorageSize,\r
       // since the space occupied by variables not marked with\r
       // VAR_ADDED is not allowed to be reclaimed in Runtime.\r
@@ -2362,7 +2172,7 @@ RuntimeServiceQueryVariableInfo (
       }\r
     } else {\r
       //\r
       }\r
     } else {\r
       //\r
-      // Only care about Variables with State VAR_ADDED,because\r
+      // Only care about Variables with State VAR_ADDED, because\r
       // the space not marked as VAR_ADDED is reclaimable now.\r
       //\r
       if (Variable->State == VAR_ADDED) {\r
       // the space not marked as VAR_ADDED is reclaimable now.\r
       //\r
       if (Variable->State == VAR_ADDED) {\r
@@ -2375,7 +2185,7 @@ RuntimeServiceQueryVariableInfo (
     }\r
 \r
     //\r
     }\r
 \r
     //\r
-    // Go to the next one\r
+    // Go to the next one.\r
     //\r
     Variable = NextVariable;\r
   }\r
     //\r
     Variable = NextVariable;\r
   }\r
@@ -2398,21 +2208,12 @@ RuntimeServiceQueryVariableInfo (
 \r
 \r
 /**\r
 \r
 \r
 /**\r
-  Notification function of EVT_GROUP_READY_TO_BOOT event group.\r
-\r
-  This is a notification function registered on EVT_GROUP_READY_TO_BOOT event group.\r
-  When the Boot Manager is about to load and execute a boot option, it reclaims variable\r
-  storage if free size is below the threshold.\r
-\r
-  @param  Event        Event whose notification function is being invoked\r
-  @param  Context      Pointer to the notification function's context\r
-\r
+  This function reclaims variable storage if free size is below the threshold.\r
+  \r
 **/\r
 VOID\r
 **/\r
 VOID\r
-EFIAPI\r
 ReclaimForOS(\r
 ReclaimForOS(\r
-  EFI_EVENT  Event,\r
-  VOID       *Context\r
+  VOID\r
   )\r
 {\r
   EFI_STATUS                     Status;\r
   )\r
 {\r
   EFI_STATUS                     Status;\r
@@ -2443,10 +2244,81 @@ ReclaimForOS(
   }\r
 }\r
 \r
   }\r
 }\r
 \r
+\r
 /**\r
 /**\r
-  Initializes variable store area for non-volatile and volatile variable.\r
+  Initializes variable write service after FVB was ready.\r
 \r
 \r
-  @param  FvbProtocol           Pointer to an instance of EFI Firmware Volume Block Protocol.\r
+  @retval EFI_SUCCESS          Function successfully executed.\r
+  @retval Others               Fail to initialize the variable service.\r
+\r
+**/\r
+EFI_STATUS\r
+VariableWriteServiceInitialize (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+  VARIABLE_STORE_HEADER           *VariableStoreHeader;\r
+  UINTN                           Index;\r
+  UINT8                           Data;\r
+  EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor;\r
+  EFI_PHYSICAL_ADDRESS            BaseAddress;\r
+  UINT64                          Length;\r
+  EFI_PHYSICAL_ADDRESS            VariableStoreBase;\r
+  UINT64                          VariableStoreLength;\r
+\r
+  VariableStoreBase   = mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;\r
+  VariableStoreHeader = (VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase;\r
+  VariableStoreLength = VariableStoreHeader->Size;\r
+  \r
+  //\r
+  // Check if the free area is really free.\r
+  //\r
+  for (Index = mVariableModuleGlobal->NonVolatileLastVariableOffset; Index < VariableStoreLength; Index++) {\r
+    Data = ((UINT8 *) mNvVariableCache)[Index];\r
+    if (Data != 0xff) {\r
+      //\r
+      // There must be something wrong in variable store, do reclaim operation.\r
+      //\r
+      Status = Reclaim (\r
+                 mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,\r
+                 &mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
+                 FALSE,\r
+                 NULL\r
+                 );\r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
+      }\r
+      break;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Mark the variable storage region of the FLASH as RUNTIME.\r
+  //\r
+  BaseAddress = VariableStoreBase & (~EFI_PAGE_MASK);\r
+  Length      = VariableStoreLength + (VariableStoreBase - BaseAddress);\r
+  Length      = (Length + EFI_PAGE_SIZE - 1) & (~EFI_PAGE_MASK);\r
+\r
+  Status      = gDS->GetMemorySpaceDescriptor (BaseAddress, &GcdDescriptor);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((DEBUG_WARN, "Variable driver failed to add EFI_MEMORY_RUNTIME attribute to Flash.\n"));\r
+  } else {\r
+    Status = gDS->SetMemorySpaceAttributes (\r
+                    BaseAddress,\r
+                    Length,\r
+                    GcdDescriptor.Attributes | EFI_MEMORY_RUNTIME\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((DEBUG_WARN, "Variable driver failed to add EFI_MEMORY_RUNTIME attribute to Flash.\n"));\r
+    }\r
+  }\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Initializes variable store area for non-volatile and volatile variable.\r
 \r
   @retval EFI_SUCCESS           Function successfully executed.\r
   @retval EFI_OUT_OF_RESOURCES  Fail to allocate enough memory resource.\r
 \r
   @retval EFI_SUCCESS           Function successfully executed.\r
   @retval EFI_OUT_OF_RESOURCES  Fail to allocate enough memory resource.\r
@@ -2454,7 +2326,7 @@ ReclaimForOS(
 **/\r
 EFI_STATUS\r
 VariableCommonInitialize (\r
 **/\r
 EFI_STATUS\r
 VariableCommonInitialize (\r
-  IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol\r
+  VOID\r
   )\r
 {\r
   EFI_STATUS                      Status;\r
   )\r
 {\r
   EFI_STATUS                      Status;\r
@@ -2462,18 +2334,11 @@ VariableCommonInitialize (
   VARIABLE_STORE_HEADER           *VariableStoreHeader;\r
   VARIABLE_HEADER                 *NextVariable;\r
   EFI_PHYSICAL_ADDRESS            TempVariableStoreHeader;\r
   VARIABLE_STORE_HEADER           *VariableStoreHeader;\r
   VARIABLE_HEADER                 *NextVariable;\r
   EFI_PHYSICAL_ADDRESS            TempVariableStoreHeader;\r
-  EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor;\r
-  EFI_PHYSICAL_ADDRESS            BaseAddress;\r
-  UINT64                          Length;\r
-  UINTN                           Index;\r
-  UINT8                           Data;\r
   EFI_PHYSICAL_ADDRESS            VariableStoreBase;\r
   UINT64                          VariableStoreLength;\r
   EFI_PHYSICAL_ADDRESS            VariableStoreBase;\r
   UINT64                          VariableStoreLength;\r
-  EFI_EVENT                       ReadyToBootEvent;\r
   UINTN                           ScratchSize;\r
   UINTN                           VariableSize;\r
 \r
   UINTN                           ScratchSize;\r
   UINTN                           VariableSize;\r
 \r
-  Status = EFI_SUCCESS;\r
   //\r
   // Allocate runtime memory for variable driver global structure.\r
   //\r
   //\r
   // Allocate runtime memory for variable driver global structure.\r
   //\r
@@ -2482,7 +2347,7 @@ VariableCommonInitialize (
     return EFI_OUT_OF_RESOURCES;\r
   }\r
 \r
     return EFI_OUT_OF_RESOURCES;\r
   }\r
 \r
-  EfiInitializeLock(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock, TPL_NOTIFY);\r
+  InitializeLock (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock, TPL_NOTIFY);\r
 \r
   //\r
   // Note that in EdkII variable driver implementation, Hardware Error Record type variable\r
 \r
   //\r
   // Note that in EdkII variable driver implementation, Hardware Error Record type variable\r
@@ -2505,139 +2370,69 @@ VariableCommonInitialize (
   SetMem (VolatileVariableStore, PcdGet32 (PcdVariableStoreSize) + ScratchSize, 0xff);\r
 \r
   //\r
   SetMem (VolatileVariableStore, PcdGet32 (PcdVariableStoreSize) + ScratchSize, 0xff);\r
 \r
   //\r
-  //  Variable Specific Data\r
+  // Initialize Variable Specific Data.\r
   //\r
   mVariableModuleGlobal->VariableGlobal.VolatileVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VolatileVariableStore;\r
   mVariableModuleGlobal->VolatileLastVariableOffset = (UINTN) GetStartPointer (VolatileVariableStore) - (UINTN) VolatileVariableStore;\r
   //\r
   mVariableModuleGlobal->VariableGlobal.VolatileVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VolatileVariableStore;\r
   mVariableModuleGlobal->VolatileLastVariableOffset = (UINTN) GetStartPointer (VolatileVariableStore) - (UINTN) VolatileVariableStore;\r
-  mVariableModuleGlobal->FvbInstance = FvbProtocol;\r
+  mVariableModuleGlobal->FvbInstance = NULL;\r
 \r
   CopyGuid (&VolatileVariableStore->Signature, &gEfiVariableGuid);\r
 \r
   CopyGuid (&VolatileVariableStore->Signature, &gEfiVariableGuid);\r
-  VolatileVariableStore->Size                       = PcdGet32 (PcdVariableStoreSize);\r
-  VolatileVariableStore->Format                     = VARIABLE_STORE_FORMATTED;\r
-  VolatileVariableStore->State                      = VARIABLE_STORE_HEALTHY;\r
-  VolatileVariableStore->Reserved                   = 0;\r
-  VolatileVariableStore->Reserved1                  = 0;\r
+  VolatileVariableStore->Size        = PcdGet32 (PcdVariableStoreSize);\r
+  VolatileVariableStore->Format      = VARIABLE_STORE_FORMATTED;\r
+  VolatileVariableStore->State       = VARIABLE_STORE_HEALTHY;\r
+  VolatileVariableStore->Reserved    = 0;\r
+  VolatileVariableStore->Reserved1   = 0;\r
 \r
   //\r
 \r
   //\r
-  // Get non volatile varaible store\r
+  // Get non-volatile varaible store.\r
   //\r
 \r
   TempVariableStoreHeader = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageVariableBase64);\r
   if (TempVariableStoreHeader == 0) {\r
     TempVariableStoreHeader = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageVariableBase);\r
   }\r
   //\r
 \r
   TempVariableStoreHeader = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageVariableBase64);\r
   if (TempVariableStoreHeader == 0) {\r
     TempVariableStoreHeader = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageVariableBase);\r
   }\r
-  \r
-  VariableStoreBase = TempVariableStoreHeader + \\r
+  VariableStoreBase       = TempVariableStoreHeader + \\r
+                              (((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader)) -> HeaderLength);\r
+  VariableStoreLength     = (UINT64) PcdGet32 (PcdFlashNvStorageVariableSize) - \\r
                               (((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader)) -> HeaderLength);\r
                               (((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader)) -> HeaderLength);\r
-  VariableStoreLength = (UINT64) PcdGet32 (PcdFlashNvStorageVariableSize) - \\r
-                                (((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader)) -> HeaderLength);\r
-  //\r
-  // Mark the variable storage region of the FLASH as RUNTIME\r
-  //\r
-  BaseAddress = VariableStoreBase & (~EFI_PAGE_MASK);\r
-  Length      = VariableStoreLength + (VariableStoreBase - BaseAddress);\r
-  Length      = (Length + EFI_PAGE_SIZE - 1) & (~EFI_PAGE_MASK);\r
-\r
-  Status      = gDS->GetMemorySpaceDescriptor (BaseAddress, &GcdDescriptor);\r
-  if (EFI_ERROR (Status)) {\r
-    goto Done;\r
-  }\r
 \r
 \r
-  Status = gDS->SetMemorySpaceAttributes (\r
-                  BaseAddress,\r
-                  Length,\r
-                  GcdDescriptor.Attributes | EFI_MEMORY_RUNTIME\r
-                  );\r
-  if (EFI_ERROR (Status)) {\r
+  mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase;\r
+  VariableStoreHeader = (VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase;\r
+  if (GetVariableStoreStatus (VariableStoreHeader) != EfiValid) {\r
+    Status = EFI_VOLUME_CORRUPTED;\r
+    DEBUG((EFI_D_INFO, "Variable Store header is corrupted\n"));\r
     goto Done;\r
     goto Done;\r
-  }\r
+  }  \r
+  ASSERT(VariableStoreHeader->Size == VariableStoreLength);\r
+    \r
   //\r
   //\r
-  // Get address of non volatile variable store base\r
+  // Parse non-volatile variable data and get last variable offset.\r
   //\r
   //\r
-  mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase;\r
-  VariableStoreHeader = (VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase;\r
-  if (GetVariableStoreStatus (VariableStoreHeader) == EfiValid) {\r
-    if (~VariableStoreHeader->Size == 0) {\r
-      Status = UpdateVariableStore (\r
-                &mVariableModuleGlobal->VariableGlobal,\r
-                FALSE,\r
-                FALSE,\r
-                mVariableModuleGlobal->FvbInstance,\r
-                (UINTN) &VariableStoreHeader->Size,\r
-                sizeof (UINT32),\r
-                (UINT8 *) &VariableStoreLength\r
-                );\r
-      //\r
-      // As Variables are stored in NV storage, which are slow devices,such as flash.\r
-      // Variable operation may skip checking variable program result to improve performance,\r
-      // We can assume Variable program is OK through some check point.\r
-      // Variable Store Size Setting should be the first Variable write operation,\r
-      // We can assume all Read/Write is OK if we can set Variable store size successfully.\r
-      // If write fail, we will assert here\r
-      //\r
-      ASSERT(VariableStoreHeader->Size == VariableStoreLength);\r
-\r
-      if (EFI_ERROR (Status)) {\r
-        goto Done;\r
-      }\r
-    }\r
-\r
-    //\r
-    // Parse non-volatile variable data and get last variable offset\r
-    //\r
-    NextVariable  = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase);\r
-    Status        = EFI_SUCCESS;\r
-\r
-    while (IsValidVariableHeader (NextVariable)) {\r
-      VariableSize = NextVariable->NameSize + NextVariable->DataSize + sizeof (VARIABLE_HEADER);\r
-      if ((NextVariable->Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
-        mVariableModuleGlobal->HwErrVariableTotalSize += HEADER_ALIGN (VariableSize);\r
-      } else {\r
-        mVariableModuleGlobal->CommonVariableTotalSize += HEADER_ALIGN (VariableSize);\r
-      }\r
-\r
-      NextVariable = GetNextVariablePtr (NextVariable);\r
+  NextVariable  = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase);\r
+  while (IsValidVariableHeader (NextVariable)) {\r
+    VariableSize = NextVariable->NameSize + NextVariable->DataSize + sizeof (VARIABLE_HEADER);\r
+    if ((NextVariable->Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
+      mVariableModuleGlobal->HwErrVariableTotalSize += HEADER_ALIGN (VariableSize);\r
+    } else {\r
+      mVariableModuleGlobal->CommonVariableTotalSize += HEADER_ALIGN (VariableSize);\r
     }\r
 \r
     }\r
 \r
-    mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) VariableStoreBase;\r
-\r
-    //\r
-    // Check if the free area is really free.\r
-    //\r
-    for (Index = mVariableModuleGlobal->NonVolatileLastVariableOffset; Index < VariableStoreHeader->Size; Index++) {\r
-      Data = ((UINT8 *) (UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase)[Index];\r
-      if (Data != 0xff) {\r
-        //\r
-        // There must be something wrong in variable store, do reclaim operation.\r
-        //\r
-        Status = Reclaim (\r
-                  mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,\r
-                  &mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
-                  FALSE,\r
-                  NULL\r
-                  );\r
-\r
-        if (EFI_ERROR (Status)) {\r
-          goto Done;\r
-        }\r
-\r
-        break;\r
-      }\r
-    }\r
+    NextVariable = GetNextVariablePtr (NextVariable);\r
+  }\r
 \r
 \r
-    //\r
-    // Register the event handling function to reclaim variable for OS usage.\r
-    //\r
-    Status = EfiCreateEventReadyToBootEx (\r
-               TPL_NOTIFY, \r
-               ReclaimForOS, \r
-               NULL, \r
-               &ReadyToBootEvent\r
-               );\r
-  } else {\r
-    Status = EFI_VOLUME_CORRUPTED;\r
-    DEBUG((EFI_D_INFO, "Variable Store header is corrupted\n"));\r
+  mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) VariableStoreBase;\r
+    \r
+  //\r
+  // Allocate runtime memory used for a memory copy of the FLASH region.\r
+  // Keep the memory and the FLASH in sync as updates occur\r
+  //\r
+  mNvVariableCache = AllocateRuntimeZeroPool ((UINTN)VariableStoreLength);\r
+  if (mNvVariableCache == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto Done;\r
   }\r
   }\r
+  CopyMem (mNvVariableCache, (CHAR8 *)(UINTN)VariableStoreBase, (UINTN)VariableStoreLength);\r
+  Status = EFI_SUCCESS;\r
 \r
 Done:\r
   if (EFI_ERROR (Status)) {\r
 \r
 Done:\r
   if (EFI_ERROR (Status)) {\r
@@ -2648,97 +2443,45 @@ Done:
   return Status;\r
 }\r
 \r
   return Status;\r
 }\r
 \r
-/**\r
-  Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE\r
-\r
-  This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.\r
-  It convers pointer to new virtual address.\r
-\r
-  @param  Event        Event whose notification function is being invoked\r
-  @param  Context      Pointer to the notification function's context\r
-\r
-**/\r
-VOID\r
-EFIAPI\r
-VariableClassAddressChangeEvent (\r
-  IN EFI_EVENT        Event,\r
-  IN VOID             *Context\r
-  )\r
-{\r
-  EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetBlockSize);\r
-  EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetPhysicalAddress);\r
-  EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetAttributes);\r
-  EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->SetAttributes);\r
-  EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->Read);\r
-  EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->Write);\r
-  EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->EraseBlocks);\r
-  EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance);\r
-  EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->PlatformLangCodes);\r
-  EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->LangCodes);\r
-  EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->PlatformLang);\r
-  EfiConvertPointer (\r
-    0x0,\r
-    (VOID **) &mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase\r
-    );\r
-  EfiConvertPointer (\r
-    0x0,\r
-    (VOID **) &mVariableModuleGlobal->VariableGlobal.VolatileVariableBase\r
-    );\r
-  EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal);\r
-}\r
 \r
 /**\r
 \r
 /**\r
-  Firmware Volume Block Protocol notification event handler.\r
+  Get the proper fvb handle and/or fvb protocol by the given Flash address.\r
 \r
 \r
-  Discover NV Variable Store and install Variable Arch Protocol.\r
+  @param[in] Address        The Flash address.\r
+  @param[out] FvbHandle     In output, if it is not NULL, it points to the proper FVB handle.\r
+  @param[out] FvbProtocol   In output, if it is not NULL, it points to the proper FVB protocol.\r
 \r
 \r
-  @param[in] Event    Event whose notification function is being invoked.\r
-  @param[in] Context  Pointer to the notification function's context.\r
 **/\r
 **/\r
-VOID\r
-EFIAPI\r
-FvbNotificationEvent (\r
-  IN  EFI_EVENT       Event,\r
-  IN  VOID            *Context\r
+EFI_STATUS\r
+GetFvbInfoByAddress (\r
+  IN  EFI_PHYSICAL_ADDRESS                Address,\r
+  OUT EFI_HANDLE                          *FvbHandle OPTIONAL,\r
+  OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  **FvbProtocol OPTIONAL\r
   )\r
 {\r
   )\r
 {\r
-  EFI_STATUS                          Status;\r
-  EFI_HANDLE                          *HandleBuffer;\r
-  UINTN                               HandleCount;\r
-  UINTN                               Index;\r
-  EFI_PHYSICAL_ADDRESS                FvbBaseAddress;\r
-  EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *Fvb;\r
-  EFI_FIRMWARE_VOLUME_HEADER          *FwVolHeader;\r
-  EFI_FVB_ATTRIBUTES_2                Attributes;\r
-  EFI_SYSTEM_TABLE                    *SystemTable;\r
-  EFI_PHYSICAL_ADDRESS                NvStorageVariableBase;\r
-\r
-  SystemTable = (EFI_SYSTEM_TABLE *)Context;\r
-  Fvb         = NULL;\r
-  \r
+  EFI_STATUS                              Status;\r
+  EFI_HANDLE                              *HandleBuffer;\r
+  UINTN                                   HandleCount;\r
+  UINTN                                   Index;\r
+  EFI_PHYSICAL_ADDRESS                    FvbBaseAddress;\r
+  EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL      *Fvb;\r
+  EFI_FIRMWARE_VOLUME_HEADER              *FwVolHeader;\r
+  EFI_FVB_ATTRIBUTES_2                    Attributes;\r
\r
   //\r
   //\r
-  // Locate all handles of Fvb protocol\r
+  // Get all FVB handles.\r
   //\r
   //\r
-  Status = gBS->LocateHandleBuffer (\r
-                  ByProtocol,\r
-                  &gEfiFirmwareVolumeBlockProtocolGuid,\r
-                  NULL,\r
-                  &HandleCount,\r
-                  &HandleBuffer\r
-                  );\r
+  Status = GetFvbCountAndBuffer (&HandleCount, &HandleBuffer);\r
   if (EFI_ERROR (Status)) {\r
   if (EFI_ERROR (Status)) {\r
-    return ;\r
+    return EFI_NOT_FOUND;\r
   }\r
   }\r
-  \r
+\r
   //\r
   //\r
-  // Get the FVB to access variable store\r
+  // Get the FVB to access variable store.\r
   //\r
   //\r
+  Fvb = NULL;\r
   for (Index = 0; Index < HandleCount; Index += 1, Status = EFI_NOT_FOUND, Fvb = NULL) {\r
   for (Index = 0; Index < HandleCount; Index += 1, Status = EFI_NOT_FOUND, Fvb = NULL) {\r
-    Status = gBS->HandleProtocol (\r
-                    HandleBuffer[Index],\r
-                    &gEfiFirmwareVolumeBlockProtocolGuid,\r
-                    (VOID **) &Fvb\r
-                    );\r
+    Status = GetFvbByHandle (HandleBuffer[Index], &Fvb);\r
     if (EFI_ERROR (Status)) {\r
       Status = EFI_NOT_FOUND;\r
       break;\r
     if (EFI_ERROR (Status)) {\r
       Status = EFI_NOT_FOUND;\r
       break;\r
@@ -2751,8 +2494,9 @@ FvbNotificationEvent (
     if (EFI_ERROR (Status) || ((Attributes & EFI_FVB2_WRITE_STATUS) == 0)) {\r
       continue;     \r
     }\r
     if (EFI_ERROR (Status) || ((Attributes & EFI_FVB2_WRITE_STATUS) == 0)) {\r
       continue;     \r
     }\r
+    \r
     //\r
     //\r
-    // Compare the address and select the right one\r
+    // Compare the address and select the right one.\r
     //\r
     Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress);\r
     if (EFI_ERROR (Status)) {\r
     //\r
     Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress);\r
     if (EFI_ERROR (Status)) {\r
@@ -2760,87 +2504,23 @@ FvbNotificationEvent (
     }\r
 \r
     FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvbBaseAddress);\r
     }\r
 \r
     FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvbBaseAddress);\r
-    NvStorageVariableBase = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageVariableBase64);\r
-    if (NvStorageVariableBase == 0) {\r
-      NvStorageVariableBase = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageVariableBase);\r
-    }\r
-    \r
-    if ((NvStorageVariableBase >= FvbBaseAddress) && (NvStorageVariableBase < (FvbBaseAddress + FwVolHeader->FvLength))) {\r
-      Status      = EFI_SUCCESS;\r
+    if ((Address >= FvbBaseAddress) && (Address < (FvbBaseAddress + FwVolHeader->FvLength))) {\r
+      if (FvbHandle != NULL) {\r
+        *FvbHandle  = HandleBuffer[Index];\r
+      }\r
+      if (FvbProtocol != NULL) {\r
+        *FvbProtocol = Fvb;\r
+      }\r
+      Status = EFI_SUCCESS;\r
       break;\r
     }\r
   }\r
       break;\r
     }\r
   }\r
-\r
   FreePool (HandleBuffer);\r
   FreePool (HandleBuffer);\r
-  if (!EFI_ERROR (Status) && Fvb != NULL) {\r
-    //\r
-    // Close the notify event to avoid install gEfiVariableArchProtocolGuid & gEfiVariableWriteArchProtocolGuid again.\r
-    //\r
-    Status = gBS->CloseEvent (Event);  \r
-    ASSERT_EFI_ERROR (Status);\r
 \r
 \r
-    Status = VariableCommonInitialize (Fvb);\r
-    ASSERT_EFI_ERROR (Status);\r
-  \r
-    SystemTable->RuntimeServices->GetVariable         = RuntimeServiceGetVariable;\r
-    SystemTable->RuntimeServices->GetNextVariableName = RuntimeServiceGetNextVariableName;\r
-    SystemTable->RuntimeServices->SetVariable         = RuntimeServiceSetVariable;\r
-    SystemTable->RuntimeServices->QueryVariableInfo   = RuntimeServiceQueryVariableInfo;\r
-  \r
-    //\r
-    // Now install the Variable Runtime Architectural Protocol on a new handle\r
-    //\r
-    Status = gBS->InstallMultipleProtocolInterfaces (\r
-                  &mHandle,\r
-                  &gEfiVariableArchProtocolGuid, NULL,\r
-                  &gEfiVariableWriteArchProtocolGuid, NULL,\r
-                  NULL\r
-                  );\r
-    ASSERT_EFI_ERROR (Status);\r
-  \r
-    Status = gBS->CreateEventEx (\r
-                  EVT_NOTIFY_SIGNAL,\r
-                  TPL_NOTIFY,\r
-                  VariableClassAddressChangeEvent,\r
-                  NULL,\r
-                  &gEfiEventVirtualAddressChangeGuid,\r
-                  &mVirtualAddressChangeEvent\r
-                  );\r
-    ASSERT_EFI_ERROR (Status);\r
+  if (Fvb == NULL) {\r
+    Status = EFI_NOT_FOUND;\r
   }\r
   }\r
-\r
-}\r
-\r
-/**\r
-  Variable Driver main entry point. The Variable driver places the 4 EFI\r
-  runtime services in the EFI System Table and installs arch protocols \r
-  for variable read and write services being availible. It also registers\r
-  notification function for EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.\r
-\r
-  @param[in] ImageHandle    The firmware allocated handle for the EFI image.  \r
-  @param[in] SystemTable    A pointer to the EFI System Table.\r
   \r
   \r
-  @retval EFI_SUCCESS       Variable service successfully initialized.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-VariableServiceInitialize (\r
-  IN EFI_HANDLE         ImageHandle,\r
-  IN EFI_SYSTEM_TABLE   *SystemTable\r
-  )\r
-{\r
-  //\r
-  // Register FvbNotificationEvent () notify function.\r
-  // \r
-  EfiCreateProtocolNotifyEvent (\r
-    &gEfiFirmwareVolumeBlockProtocolGuid,\r
-    TPL_CALLBACK,\r
-    FvbNotificationEvent,\r
-    (VOID *)SystemTable,\r
-    &mFvbRegistration\r
-    );\r
-\r
-  return EFI_SUCCESS;\r
+  return Status;  \r
 }\r
 \r
 }\r
 \r
index 91fdf9dbfd586078304fce9597f6b2ecae578b24..7cc039dea85c47f3fea3928b791a2437a32c3b94 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
 \r
   The internal header file includes the common header files, defines\r
 /** @file\r
 \r
   The internal header file includes the common header files, defines\r
-  internal structure and functions used by RuntimeVariable module.\r
+  internal structure and functions used by Variable modules.\r
 \r
 Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
 This program and the accompanying materials\r
 \r
 Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
 This program and the accompanying materials\r
@@ -82,17 +82,17 @@ typedef struct {
 /**\r
   Writes a buffer to variable storage space, in the working block.\r
 \r
 /**\r
   Writes a buffer to variable storage space, in the working block.\r
 \r
-  This function writes a buffer to variable storage space into firmware\r
-  volume block device. The destination is specified by parameter\r
+  This function writes a buffer to variable storage space into firmware\r
+  volume block device. The destination is specified by the parameter\r
   VariableBase. Fault Tolerant Write protocol is used for writing.\r
 \r
   VariableBase. Fault Tolerant Write protocol is used for writing.\r
 \r
-  @param  VariableBase   Base address of variable to write\r
-  @param  Buffer         Point to the data buffer\r
-  @param  BufferSize     The number of bytes of the data Buffer\r
+  @param  VariableBase   Base address of the variable to write.\r
+  @param  Buffer         Point to the data buffer.\r
+  @param  BufferSize     The number of bytes of the data Buffer.\r
 \r
 \r
-  @retval EFI_SUCCESS    The function completed successfully\r
-  @retval EFI_NOT_FOUND  Fail to locate Fault Tolerant Write protocol\r
-  @retval EFI_ABORTED    The function could not complete successfully\r
+  @retval EFI_SUCCESS    The function completed successfully.\r
+  @retval EFI_NOT_FOUND  Fail to locate Fault Tolerant Write protocol.\r
+  @retval EFI_ABORTED    The function could not complete successfully.\r
 \r
 **/\r
 EFI_STATUS\r
 \r
 **/\r
 EFI_STATUS\r
@@ -103,4 +103,329 @@ FtwVariableSpace (
   );\r
 \r
 \r
   );\r
 \r
 \r
+/**\r
+  Update the variable region with Variable information. These are the same \r
+  arguments as the EFI Variable services.\r
+\r
+  @param[in] VariableName       Name of variable.\r
+\r
+  @param[in] VendorGuid         Guid of variable.\r
+\r
+  @param[in] Data               Variable data.\r
+\r
+  @param[in] DataSize           Size of data. 0 means delete.\r
+\r
+  @param[in] Attributes         Attribues of the variable.\r
+\r
+  @param[in] Variable           The variable information that is used to keep track of variable usage.\r
+\r
+  @retval EFI_SUCCESS           The update operation is success.\r
+\r
+  @retval EFI_OUT_OF_RESOURCES  Variable region is full, cannot write other data into this region.\r
+\r
+**/\r
+EFI_STATUS\r
+UpdateVariable (\r
+  IN      CHAR16          *VariableName,\r
+  IN      EFI_GUID        *VendorGuid,\r
+  IN      VOID            *Data,\r
+  IN      UINTN           DataSize,\r
+  IN      UINT32          Attributes OPTIONAL,\r
+  IN      VARIABLE_POINTER_TRACK *Variable\r
+  );\r
+\r
+\r
+/**\r
+  Return TRUE if ExitBootServices () has been called.\r
+  \r
+  @retval TRUE If ExitBootServices () has been called.\r
+**/\r
+BOOLEAN\r
+AtRuntime (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Initializes a basic mutual exclusion lock.\r
+\r
+  This function initializes a basic mutual exclusion lock to the released state \r
+  and returns the lock.  Each lock provides mutual exclusion access at its task \r
+  priority level.  Since there is no preemption or multiprocessor support in EFI,\r
+  acquiring the lock only consists of raising to the locks TPL.\r
+  If Lock is NULL, then ASSERT().\r
+  If Priority is not a valid TPL value, then ASSERT().\r
+\r
+  @param  Lock       A pointer to the lock data structure to initialize.\r
+  @param  Priority   EFI TPL is associated with the lock.\r
+\r
+  @return The lock.\r
+\r
+**/\r
+EFI_LOCK *\r
+InitializeLock (\r
+  IN OUT EFI_LOCK  *Lock,\r
+  IN EFI_TPL        Priority\r
+  );\r
+\r
+  \r
+/**\r
+  Acquires lock only at boot time. Simply returns at runtime.\r
+\r
+  This is a temperary function that will be removed when\r
+  EfiAcquireLock() in UefiLib can handle the call in UEFI\r
+  Runtimer driver in RT phase.\r
+  It calls EfiAcquireLock() at boot time, and simply returns\r
+  at runtime.\r
+\r
+  @param  Lock         A pointer to the lock to acquire.\r
+\r
+**/\r
+VOID\r
+AcquireLockOnlyAtBootTime (\r
+  IN EFI_LOCK  *Lock\r
+  );\r
+\r
+\r
+/**\r
+  Releases lock only at boot time. Simply returns at runtime.\r
+\r
+  This is a temperary function which will be removed when\r
+  EfiReleaseLock() in UefiLib can handle the call in UEFI\r
+  Runtimer driver in RT phase.\r
+  It calls EfiReleaseLock() at boot time and simply returns\r
+  at runtime.\r
+\r
+  @param  Lock         A pointer to the lock to release.\r
+\r
+**/\r
+VOID\r
+ReleaseLockOnlyAtBootTime (\r
+  IN EFI_LOCK  *Lock\r
+  );  \r
+\r
+/**\r
+  Retrive the FVB protocol interface by HANDLE.\r
+\r
+  @param[in]  FvBlockHandle     The handle of FVB protocol that provides services for\r
+                                reading, writing, and erasing the target block.\r
+  @param[out] FvBlock           The interface of FVB protocol\r
+\r
+  @retval EFI_SUCCESS           The interface information for the specified protocol was returned.\r
+  @retval EFI_UNSUPPORTED       The device does not support the FVB protocol.\r
+  @retval EFI_INVALID_PARAMETER FvBlockHandle is not a valid EFI_HANDLE or FvBlock is NULL.\r
+  \r
+**/\r
+EFI_STATUS\r
+GetFvbByHandle (\r
+  IN  EFI_HANDLE                          FvBlockHandle,\r
+  OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  **FvBlock\r
+  );\r
+\r
+\r
+/**\r
+  Retrive the Swap Address Range protocol interface.\r
+\r
+  @param[out] SarProtocol       The interface of SAR protocol\r
+\r
+  @retval EFI_SUCCESS           The SAR protocol instance was found and returned in SarProtocol.\r
+  @retval EFI_NOT_FOUND         The SAR protocol instance was not found.\r
+  @retval EFI_INVALID_PARAMETER SarProtocol is NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+GetSarProtocol (\r
+  OUT VOID                                **SarProtocol\r
+  );\r
+\r
+/**\r
+  Function returns an array of handles that support the FVB protocol\r
+  in a buffer allocated from pool. \r
+\r
+  @param[out]  NumberHandles    The number of handles returned in Buffer.\r
+  @param[out]  Buffer           A pointer to the buffer to return the requested\r
+                                array of  handles that support FVB protocol.\r
+\r
+  @retval EFI_SUCCESS           The array of handles was returned in Buffer, and the number of\r
+                                handles in Buffer was returned in NumberHandles.\r
+  @retval EFI_NOT_FOUND         No FVB handle was found.\r
+  @retval EFI_OUT_OF_RESOURCES  There is not enough pool memory to store the matching results.\r
+  @retval EFI_INVALID_PARAMETER NumberHandles is NULL or Buffer is NULL.\r
+  \r
+**/\r
+EFI_STATUS\r
+GetFvbCountAndBuffer (\r
+  OUT UINTN                               *NumberHandles,\r
+  OUT EFI_HANDLE                          **Buffer\r
+  );\r
+\r
+/**\r
+  Initializes variable store area for non-volatile and volatile variable.\r
+\r
+  @retval EFI_SUCCESS           Function successfully executed.\r
+  @retval EFI_OUT_OF_RESOURCES  Fail to allocate enough memory resource.\r
+\r
+**/\r
+EFI_STATUS\r
+VariableCommonInitialize (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  This function reclaims variable storage if free size is below the threshold.\r
+  \r
+**/\r
+VOID\r
+ReclaimForOS(\r
+  VOID\r
+  );  \r
+\r
+\r
+/**\r
+  Initializes variable write service after FVB was ready.\r
+\r
+  @retval EFI_SUCCESS          Function successfully executed.\r
+  @retval Others               Fail to initialize the variable service.\r
+\r
+**/\r
+EFI_STATUS\r
+VariableWriteServiceInitialize (\r
+  VOID\r
+  );\r
+  \r
+/**\r
+  Retrive the SMM Fault Tolerent Write protocol interface.\r
+\r
+  @param[out] FtwProtocol       The interface of SMM Ftw protocol\r
+\r
+  @retval EFI_SUCCESS           The SMM SAR protocol instance was found and returned in SarProtocol.\r
+  @retval EFI_NOT_FOUND         The SMM SAR protocol instance was not found.\r
+  @retval EFI_INVALID_PARAMETER SarProtocol is NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+GetFtwProtocol (\r
+  OUT VOID                                **FtwProtocol\r
+  );\r
+\r
+/**\r
+  Get the proper fvb handle and/or fvb protocol by the given Flash address.\r
+\r
+  @param[in] Address        The Flash address.\r
+  @param[out] FvbHandle     In output, if it is not NULL, it points to the proper FVB handle.\r
+  @param[out] FvbProtocol   In output, if it is not NULL, it points to the proper FVB protocol.\r
+\r
+**/\r
+EFI_STATUS\r
+GetFvbInfoByAddress (\r
+  IN  EFI_PHYSICAL_ADDRESS                Address,\r
+  OUT EFI_HANDLE                          *FvbHandle OPTIONAL,\r
+  OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  **FvbProtocol OPTIONAL\r
+  );\r
+\r
+/**\r
+\r
+  This code finds variable in storage blocks (Volatile or Non-Volatile).\r
+\r
+  @param VariableName               Name of Variable to be found.\r
+  @param VendorGuid                 Variable vendor GUID.\r
+  @param Attributes                 Attribute value of the variable found.\r
+  @param DataSize                   Size of Data found. If size is less than the\r
+                                    data, this value contains the required size.\r
+  @param Data                       Data pointer.\r
+                      \r
+  @return EFI_INVALID_PARAMETER     Invalid parameter.\r
+  @return EFI_SUCCESS               Find the specified variable.\r
+  @return EFI_NOT_FOUND             Not found.\r
+  @return EFI_BUFFER_TO_SMALL       DataSize is too small for the result.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+VariableServiceGetVariable (\r
+  IN      CHAR16            *VariableName,\r
+  IN      EFI_GUID          *VendorGuid,\r
+  OUT     UINT32            *Attributes OPTIONAL,\r
+  IN OUT  UINTN             *DataSize,\r
+  OUT     VOID              *Data\r
+  );\r
+\r
+/**\r
+\r
+  This code Finds the Next available variable.\r
+\r
+  @param VariableNameSize           Size of the variable name.\r
+  @param VariableName               Pointer to variable name.\r
+  @param VendorGuid                 Variable Vendor Guid.\r
+\r
+  @return EFI_INVALID_PARAMETER     Invalid parameter.\r
+  @return EFI_SUCCESS               Find the specified variable.\r
+  @return EFI_NOT_FOUND             Not found.\r
+  @return EFI_BUFFER_TO_SMALL       DataSize is too small for the result.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+VariableServiceGetNextVariableName (\r
+  IN OUT  UINTN             *VariableNameSize,\r
+  IN OUT  CHAR16            *VariableName,\r
+  IN OUT  EFI_GUID          *VendorGuid\r
+  );\r
+\r
+/**\r
+\r
+  This code sets variable in storage blocks (Volatile or Non-Volatile).\r
+\r
+  @param VariableName                     Name of Variable to be found.\r
+  @param VendorGuid                       Variable vendor GUID.\r
+  @param Attributes                       Attribute value of the variable found\r
+  @param DataSize                         Size of Data found. If size is less than the\r
+                                          data, this value contains the required size.\r
+  @param Data                             Data pointer.\r
+\r
+  @return EFI_INVALID_PARAMETER           Invalid parameter.\r
+  @return EFI_SUCCESS                     Set successfully.\r
+  @return EFI_OUT_OF_RESOURCES            Resource not enough to set variable.\r
+  @return EFI_NOT_FOUND                   Not found.\r
+  @return EFI_WRITE_PROTECTED             Variable is read-only.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+VariableServiceSetVariable (\r
+  IN CHAR16                  *VariableName,\r
+  IN EFI_GUID                *VendorGuid,\r
+  IN UINT32                  Attributes,\r
+  IN UINTN                   DataSize,\r
+  IN VOID                    *Data\r
+  );\r
+\r
+/**\r
+\r
+  This code returns information about the EFI variables.\r
+\r
+  @param Attributes                     Attributes bitmask to specify the type of variables\r
+                                        on which to return information.\r
+  @param MaximumVariableStorageSize     Pointer to the maximum size of the storage space available\r
+                                        for the EFI variables associated with the attributes specified.\r
+  @param RemainingVariableStorageSize   Pointer to the remaining size of the storage space available\r
+                                        for EFI variables associated with the attributes specified.\r
+  @param MaximumVariableSize            Pointer to the maximum size of an individual EFI variables\r
+                                        associated with the attributes specified.\r
+\r
+  @return EFI_INVALID_PARAMETER         An invalid combination of attribute bits was supplied.\r
+  @return EFI_SUCCESS                   Query successfully.\r
+  @return EFI_UNSUPPORTED               The attribute is not supported on this platform.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+VariableServiceQueryVariableInfo (\r
+  IN  UINT32                 Attributes,\r
+  OUT UINT64                 *MaximumVariableStorageSize,\r
+  OUT UINT64                 *RemainingVariableStorageSize,\r
+  OUT UINT64                 *MaximumVariableSize\r
+  );  \r
+  \r
+extern VARIABLE_MODULE_GLOBAL  *mVariableModuleGlobal;\r
+\r
 #endif\r
 #endif\r
diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c
new file mode 100644 (file)
index 0000000..f9f20bd
--- /dev/null
@@ -0,0 +1,402 @@
+/** @file\r
+\r
+  Implement all four UEFI Runtime Variable services for the nonvolatile\r
+  and volatile storage space and install variable architecture protocol.\r
+  \r
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials                          \r
+are licensed and made available under the terms and conditions of the BSD License         \r
+which accompanies this distribution.  The full text of the license may be found at        \r
+http://opensource.org/licenses/bsd-license.php                                            \r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             \r
+\r
+**/\r
+\r
+#include "Variable.h"\r
+\r
+extern VARIABLE_STORE_HEADER   *mNvVariableCache;\r
+VARIABLE_INFO_ENTRY            *gVariableInfo;\r
+EFI_HANDLE                     mHandle                    = NULL;\r
+EFI_EVENT                      mVirtualAddressChangeEvent = NULL;\r
+EFI_EVENT                           mFtwRegistration           = NULL;\r
+\r
+/**\r
+  Return TRUE if ExitBootServices () has been called\r
+  \r
+  @retval TRUE If ExitBootServices () has been called\r
+**/\r
+BOOLEAN\r
+AtRuntime (\r
+  VOID\r
+  )\r
+{\r
+  return EfiAtRuntime ();\r
+}\r
+\r
+\r
+/**\r
+  Initializes a basic mutual exclusion lock.\r
+\r
+  This function initializes a basic mutual exclusion lock to the released state \r
+  and returns the lock.  Each lock provides mutual exclusion access at its task \r
+  priority level.  Since there is no preemption or multiprocessor support in EFI,\r
+  acquiring the lock only consists of raising to the locks TPL.\r
+  If Lock is NULL, then ASSERT().\r
+  If Priority is not a valid TPL value, then ASSERT().\r
+\r
+  @param  Lock       A pointer to the lock data structure to initialize.\r
+  @param  Priority   EFI TPL is associated with the lock.\r
+\r
+  @return The lock.\r
+\r
+**/\r
+EFI_LOCK *\r
+InitializeLock (\r
+  IN OUT EFI_LOCK                         *Lock,\r
+  IN     EFI_TPL                          Priority\r
+  )\r
+{\r
+  return EfiInitializeLock (Lock, Priority);\r
+}\r
+\r
+\r
+/**\r
+  Acquires lock only at boot time. Simply returns at runtime.\r
+\r
+  This is a temperary function that will be removed when\r
+  EfiAcquireLock() in UefiLib can handle the call in UEFI\r
+  Runtimer driver in RT phase.\r
+  It calls EfiAcquireLock() at boot time, and simply returns\r
+  at runtime.\r
+\r
+  @param  Lock         A pointer to the lock to acquire.\r
+\r
+**/\r
+VOID\r
+AcquireLockOnlyAtBootTime (\r
+  IN EFI_LOCK                             *Lock\r
+  )\r
+{\r
+  if (!AtRuntime ()) {\r
+    EfiAcquireLock (Lock);\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Releases lock only at boot time. Simply returns at runtime.\r
+\r
+  This is a temperary function which will be removed when\r
+  EfiReleaseLock() in UefiLib can handle the call in UEFI\r
+  Runtimer driver in RT phase.\r
+  It calls EfiReleaseLock() at boot time and simply returns\r
+  at runtime.\r
+\r
+  @param  Lock         A pointer to the lock to release.\r
+\r
+**/\r
+VOID\r
+ReleaseLockOnlyAtBootTime (\r
+  IN EFI_LOCK                             *Lock\r
+  )\r
+{\r
+  if (!AtRuntime ()) {\r
+    EfiReleaseLock (Lock);\r
+  }\r
+}\r
+\r
+/**\r
+  Retrive the Fault Tolerent Write protocol interface.\r
+\r
+  @param[out] FtwProtocol       The interface of Ftw protocol\r
+\r
+  @retval EFI_SUCCESS           The FTW protocol instance was found and returned in FtwProtocol.\r
+  @retval EFI_NOT_FOUND         The FTW protocol instance was not found.\r
+  @retval EFI_INVALID_PARAMETER SarProtocol is NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+GetFtwProtocol (\r
+  OUT VOID                                **FtwProtocol\r
+  )\r
+{\r
+  EFI_STATUS                              Status;\r
+\r
+  //\r
+  // Locate Fault Tolerent Write protocol\r
+  //\r
+  Status = gBS->LocateProtocol (\r
+                  &gEfiFaultTolerantWriteProtocolGuid,\r
+                  NULL,\r
+                  FtwProtocol\r
+                  );                    \r
+  return Status;\r
+}\r
+\r
+/**\r
+  Retrive the FVB protocol interface by HANDLE.\r
+\r
+  @param[in]  FvBlockHandle     The handle of FVB protocol that provides services for\r
+                                reading, writing, and erasing the target block.\r
+  @param[out] FvBlock           The interface of FVB protocol\r
+\r
+  @retval EFI_SUCCESS           The interface information for the specified protocol was returned.\r
+  @retval EFI_UNSUPPORTED       The device does not support the FVB protocol.\r
+  @retval EFI_INVALID_PARAMETER FvBlockHandle is not a valid EFI_HANDLE or FvBlock is NULL.\r
+  \r
+**/\r
+EFI_STATUS\r
+GetFvbByHandle (\r
+  IN  EFI_HANDLE                          FvBlockHandle,\r
+  OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  **FvBlock\r
+  )\r
+{\r
+  //\r
+  // To get the FVB protocol interface on the handle\r
+  //\r
+  return gBS->HandleProtocol (\r
+                FvBlockHandle,\r
+                &gEfiFirmwareVolumeBlockProtocolGuid,\r
+                (VOID **) FvBlock\r
+                );\r
+}\r
+\r
+\r
+/**\r
+  Function returns an array of handles that support the FVB protocol\r
+  in a buffer allocated from pool. \r
+\r
+  @param[out]  NumberHandles    The number of handles returned in Buffer.\r
+  @param[out]  Buffer           A pointer to the buffer to return the requested\r
+                                array of  handles that support FVB protocol.\r
+\r
+  @retval EFI_SUCCESS           The array of handles was returned in Buffer, and the number of\r
+                                handles in Buffer was returned in NumberHandles.\r
+  @retval EFI_NOT_FOUND         No FVB handle was found.\r
+  @retval EFI_OUT_OF_RESOURCES  There is not enough pool memory to store the matching results.\r
+  @retval EFI_INVALID_PARAMETER NumberHandles is NULL or Buffer is NULL.\r
+  \r
+**/\r
+EFI_STATUS\r
+GetFvbCountAndBuffer (\r
+  OUT UINTN                               *NumberHandles,\r
+  OUT EFI_HANDLE                          **Buffer\r
+  )\r
+{\r
+  EFI_STATUS                              Status;\r
+\r
+  //\r
+  // Locate all handles of Fvb protocol\r
+  //\r
+  Status = gBS->LocateHandleBuffer (\r
+                  ByProtocol,\r
+                  &gEfiFirmwareVolumeBlockProtocolGuid,\r
+                  NULL,\r
+                  NumberHandles,\r
+                  Buffer\r
+                  );\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.\r
+\r
+  This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.\r
+  It convers pointer to new virtual address.\r
+\r
+  @param  Event        Event whose notification function is being invoked.\r
+  @param  Context      Pointer to the notification function's context.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+VariableClassAddressChangeEvent (\r
+  IN EFI_EVENT                            Event,\r
+  IN VOID                                 *Context\r
+  )\r
+{\r
+  EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetBlockSize);\r
+  EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetPhysicalAddress);\r
+  EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetAttributes);\r
+  EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->SetAttributes);\r
+  EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->Read);\r
+  EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->Write);\r
+  EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->EraseBlocks);\r
+  EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance);\r
+  EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->PlatformLangCodes);\r
+  EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->LangCodes);\r
+  EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->PlatformLang);\r
+  EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase);\r
+  EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);\r
+  EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal);\r
+  EfiConvertPointer (0x0, (VOID **) &mNvVariableCache);  \r
+}\r
+\r
+\r
+/**\r
+  Notification function of EVT_GROUP_READY_TO_BOOT event group.\r
+\r
+  This is a notification function registered on EVT_GROUP_READY_TO_BOOT event group.\r
+  When the Boot Manager is about to load and execute a boot option, it reclaims variable\r
+  storage if free size is below the threshold.\r
+\r
+  @param  Event        Event whose notification function is being invoked.\r
+  @param  Context      Pointer to the notification function's context.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+OnReadyToBoot (\r
+  EFI_EVENT                               Event,\r
+  VOID                                    *Context\r
+  )\r
+{\r
+  ReclaimForOS ();\r
+}\r
+\r
+\r
+/**\r
+  Fault Tolerant Write protocol notification event handler.\r
+\r
+  Non-Volatile variable write may needs FTW protocol to reclaim when \r
+  writting variable.\r
+\r
+  @param[in] Event    Event whose notification function is being invoked.\r
+  @param[in] Context  Pointer to the notification function's context.\r
+  \r
+**/\r
+VOID\r
+EFIAPI\r
+FtwNotificationEvent (\r
+  IN  EFI_EVENT                           Event,\r
+  IN  VOID                                *Context\r
+  )\r
+{\r
+  EFI_STATUS                              Status;\r
+  EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL      *FvbProtocol;\r
+  EFI_FAULT_TOLERANT_WRITE_PROTOCOL       *FtwProtocol;\r
+  EFI_PHYSICAL_ADDRESS                    NvStorageVariableBase;\r
+\r
+  //\r
+  // Ensure FTW protocol is installed.\r
+  //\r
+  Status = GetFtwProtocol (&FtwProtocol);\r
+  if (EFI_ERROR (Status)) {\r
+    return ;\r
+  }\r
+  \r
+  //\r
+  // Find the proper FVB protocol for variable.\r
+  //\r
+  NvStorageVariableBase = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageVariableBase64);\r
+  if (NvStorageVariableBase == 0) {\r
+    NvStorageVariableBase = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageVariableBase);\r
+  }\r
+  Status = GetFvbInfoByAddress (NvStorageVariableBase, NULL, &FvbProtocol);\r
+  if (EFI_ERROR (Status)) {\r
+    return ;\r
+  }\r
+  mVariableModuleGlobal->FvbInstance = FvbProtocol;\r
+  \r
+  Status = VariableWriteServiceInitialize ();\r
+  ASSERT_EFI_ERROR (Status);\r
\r
+  //\r
+  // Install the Variable Write Architectural protocol.\r  //\r
+  Status = gBS->InstallProtocolInterface (\r
+                  &mHandle,\r
+                  &gEfiVariableWriteArchProtocolGuid, \r
+                  EFI_NATIVE_INTERFACE,\r
+                  NULL\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+  \r
+  //\r
+  // Close the notify event to avoid install gEfiVariableWriteArchProtocolGuid again.\r
+  //\r
+  gBS->CloseEvent (Event);\r
+\r
+}\r
+\r
+\r
+/**\r
+  Variable Driver main entry point. The Variable driver places the 4 EFI\r
+  runtime services in the EFI System Table and installs arch protocols \r
+  for variable read and write services being availible. It also registers\r
+  a notification function for an EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.\r
+\r
+  @param[in] ImageHandle    The firmware allocated handle for the EFI image.  \r
+  @param[in] SystemTable    A pointer to the EFI System Table.\r
+  \r
+  @retval EFI_SUCCESS       Variable service successfully initialized.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+VariableServiceInitialize (\r
+  IN EFI_HANDLE                         ImageHandle,\r
+  IN EFI_SYSTEM_TABLE                   *SystemTable\r
+  )\r
+{\r
+  EFI_STATUS                            Status;\r
+  EFI_EVENT                             ReadyToBootEvent;    \r
+\r
+  Status = VariableCommonInitialize ();\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  SystemTable->RuntimeServices->GetVariable         = VariableServiceGetVariable;\r
+  SystemTable->RuntimeServices->GetNextVariableName = VariableServiceGetNextVariableName;\r
+  SystemTable->RuntimeServices->SetVariable         = VariableServiceSetVariable;\r
+  SystemTable->RuntimeServices->QueryVariableInfo   = VariableServiceQueryVariableInfo;\r
+    \r
+  //\r
+  // Now install the Variable Runtime Architectural protocol on a new handle.\r
+  //\r
+  Status = gBS->InstallProtocolInterface (\r
+                  &mHandle,\r
+                  &gEfiVariableArchProtocolGuid, \r
+                  EFI_NATIVE_INTERFACE,\r
+                  NULL\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // Register FtwNotificationEvent () notify function.\r
+  // \r
+  EfiCreateProtocolNotifyEvent (\r
+    &gEfiFaultTolerantWriteProtocolGuid,\r
+    TPL_CALLBACK,\r
+    FtwNotificationEvent,\r
+    (VOID *)SystemTable,\r
+    &mFtwRegistration\r
+    );\r
+\r
+  Status = gBS->CreateEventEx (\r
+                  EVT_NOTIFY_SIGNAL,\r
+                  TPL_NOTIFY,\r
+                  VariableClassAddressChangeEvent,\r
+                  NULL,\r
+                  &gEfiEventVirtualAddressChangeGuid,\r
+                  &mVirtualAddressChangeEvent\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // Register the event handling function to reclaim variable for OS usage.\r
+  //\r
+  Status = EfiCreateEventReadyToBootEx (\r
+             TPL_NOTIFY, \r
+             OnReadyToBoot, \r
+             NULL, \r
+             &ReadyToBootEvent\r
+             );\r
+\r
+  if (FeaturePcdGet (PcdVariableCollectStatistics)) {\r
+    gBS->InstallConfigurationTable (&gEfiVariableGuid, gVariableInfo);\r
+  }\r
+  return EFI_SUCCESS;\r
+}\r
+\r
index bde1d04386f06ed3a3d348009ffa28d81f1928da..15e000e69b2d4313e4891dec894e2d456992d966 100644 (file)
@@ -33,6 +33,7 @@
 [Sources]\r
   Reclaim.c\r
   Variable.c\r
 [Sources]\r
   Reclaim.c\r
   Variable.c\r
+  VariableDxe.c\r
   Variable.h\r
 \r
 [Packages]\r
   Variable.h\r
 \r
 [Packages]\r
@@ -76,7 +77,7 @@
   gEfiMdeModulePkgTokenSpaceGuid.PcdVariableCollectStatistics  ## SOMETIME_CONSUMES (statistic the information of variable.)\r
 \r
 [Depex]\r
   gEfiMdeModulePkgTokenSpaceGuid.PcdVariableCollectStatistics  ## SOMETIME_CONSUMES (statistic the information of variable.)\r
 \r
 [Depex]\r
-  gEfiFirmwareVolumeBlockProtocolGuid AND gEfiFaultTolerantWriteProtocolGuid\r
+  TRUE\r
 \r
 # [Event]\r
 #   ##\r
 \r
 # [Event]\r
 #   ##\r
@@ -84,4 +85,5 @@
 #   #\r
 #   EVENT_TYPE_NOTIFY_SIGNAL                    ## PRODUCES\r
 #\r
 #   #\r
 #   EVENT_TYPE_NOTIFY_SIGNAL                    ## PRODUCES\r
 #\r
-#
\ No newline at end of file
+#\r
+    \r
diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c
new file mode 100644 (file)
index 0000000..75a5163
--- /dev/null
@@ -0,0 +1,585 @@
+/** @file\r
+\r
+  The sample implementation for SMM variable protocol. And this driver \r
+  implements  an SMI handler to communicate with the DXE runtime driver \r
+  to provide variable services.\r
+\r
+Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials                          \r
+are licensed and made available under the terms and conditions of the BSD License         \r
+which accompanies this distribution.  The full text of the license may be found at        \r
+http://opensource.org/licenses/bsd-license.php                                            \r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.  \r
+\r
+**/\r
+#include <Protocol/SmmFaultTolerantWrite.h>\r
+#include <Library/SmmServicesTableLib.h>\r
+\r
+#include "Variable.h"\r
+#include "VariableSmmCommon.h"\r
+\r
+extern SMM_VARIABLE_COMMUNICATE_VARIABLE_INFO_ENTRY  *gVariableInfo;\r
+EFI_HANDLE                                           mSmmVariableHandle      = NULL;\r
+EFI_HANDLE                                           mVariableHandle         = NULL;\r
+BOOLEAN                                              mAtRuntime              = FALSE;\r
+EFI_GUID                                             mZeroGuid               = {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}};\r
+EFI_GUID                                             mSmmVariableWriteGuid   = EFI_SMM_VARIABLE_WRITE_GUID;\r
+  \r
+EFI_SMM_VARIABLE_PROTOCOL      gSmmVariable = {\r
+  VariableServiceGetVariable,\r
+  VariableServiceGetNextVariableName,\r
+  VariableServiceSetVariable,\r
+  VariableServiceQueryVariableInfo\r
+};\r
+\r
+\r
+/**\r
+  Return TRUE if ExitBootServices () has been called.\r
+  \r
+  @retval TRUE If ExitBootServices () has been called.\r
+**/\r
+BOOLEAN\r
+AtRuntime (\r
+  VOID\r
+  )\r
+{\r
+  return mAtRuntime;\r
+}\r
+\r
+/**\r
+  Initializes a basic mutual exclusion lock.\r
+\r
+  This function initializes a basic mutual exclusion lock to the released state \r
+  and returns the lock.  Each lock provides mutual exclusion access at its task \r
+  priority level.  Since there is no preemption or multiprocessor support in EFI,\r
+  acquiring the lock only consists of raising to the locks TPL.\r
+  If Lock is NULL, then ASSERT().\r
+  If Priority is not a valid TPL value, then ASSERT().\r
+\r
+  @param  Lock       A pointer to the lock data structure to initialize.\r
+  @param  Priority   EFI TPL is associated with the lock.\r
+\r
+  @return The lock.\r
+\r
+**/\r
+EFI_LOCK *\r
+InitializeLock (\r
+  IN OUT EFI_LOCK                         *Lock,\r
+  IN EFI_TPL                              Priority\r
+  )\r
+{\r
+  return Lock;\r
+}\r
+\r
+/**\r
+  Acquires lock only at boot time. Simply returns at runtime.\r
+\r
+  This is a temperary function that will be removed when\r
+  EfiAcquireLock() in UefiLib can handle the call in UEFI\r
+  Runtimer driver in RT phase.\r
+  It calls EfiAcquireLock() at boot time, and simply returns\r
+  at runtime.\r
+\r
+  @param  Lock         A pointer to the lock to acquire.\r
+\r
+**/\r
+VOID\r
+AcquireLockOnlyAtBootTime (\r
+  IN EFI_LOCK                             *Lock\r
+  )\r
+{\r
+\r
+}\r
+\r
+\r
+/**\r
+  Releases lock only at boot time. Simply returns at runtime.\r
+\r
+  This is a temperary function which will be removed when\r
+  EfiReleaseLock() in UefiLib can handle the call in UEFI\r
+  Runtimer driver in RT phase.\r
+  It calls EfiReleaseLock() at boot time and simply returns\r
+  at runtime.\r
+\r
+  @param  Lock         A pointer to the lock to release.\r
+\r
+**/\r
+VOID\r
+ReleaseLockOnlyAtBootTime (\r
+  IN EFI_LOCK                             *Lock\r
+  )\r
+{\r
+\r
+}\r
+\r
+/**\r
+  Retrive the SMM Fault Tolerent Write protocol interface.\r
+\r
+  @param[out] FtwProtocol       The interface of SMM Ftw protocol\r
+\r
+  @retval EFI_SUCCESS           The SMM FTW protocol instance was found and returned in FtwProtocol.\r
+  @retval EFI_NOT_FOUND         The SMM FTW protocol instance was not found.\r
+  @retval EFI_INVALID_PARAMETER SarProtocol is NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+GetFtwProtocol (\r
+  OUT VOID                                **FtwProtocol\r
+  )\r
+{\r
+  EFI_STATUS                              Status;\r
+\r
+  //\r
+  // Locate Smm Fault Tolerent Write protocol\r
+  //\r
+  Status = gSmst->SmmLocateProtocol (\r
+                    &gEfiSmmFaultTolerantWriteProtocolGuid, \r
+                    NULL, \r
+                    FtwProtocol\r
+                    );\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Retrive the SMM FVB protocol interface by HANDLE.\r
+\r
+  @param[in]  FvBlockHandle     The handle of SMM FVB protocol that provides services for\r
+                                reading, writing, and erasing the target block.\r
+  @param[out] FvBlock           The interface of SMM FVB protocol\r
+\r
+  @retval EFI_SUCCESS           The interface information for the specified protocol was returned.\r
+  @retval EFI_UNSUPPORTED       The device does not support the SMM FVB protocol.\r
+  @retval EFI_INVALID_PARAMETER FvBlockHandle is not a valid EFI_HANDLE or FvBlock is NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+GetFvbByHandle (\r
+  IN  EFI_HANDLE                          FvBlockHandle,\r
+  OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  **FvBlock\r
+  )\r
+{\r
+  //\r
+  // To get the SMM FVB protocol interface on the handle\r
+  //\r
+  return gSmst->SmmHandleProtocol (\r
+                  FvBlockHandle,\r
+                  &gEfiSmmFirmwareVolumeBlockProtocolGuid,\r
+                  (VOID **) FvBlock\r
+                  );\r
+}\r
+\r
+\r
+/**\r
+  Function returns an array of handles that support the SMM FVB protocol\r
+  in a buffer allocated from pool. \r
+\r
+  @param[out]  NumberHandles    The number of handles returned in Buffer.\r
+  @param[out]  Buffer           A pointer to the buffer to return the requested\r
+                                array of  handles that support SMM FVB protocol.\r
+\r
+  @retval EFI_SUCCESS           The array of handles was returned in Buffer, and the number of\r
+                                handles in Buffer was returned in NumberHandles.\r
+  @retval EFI_NOT_FOUND         No SMM FVB handle was found.\r
+  @retval EFI_OUT_OF_RESOURCES  There is not enough pool memory to store the matching results.\r
+  @retval EFI_INVALID_PARAMETER NumberHandles is NULL or Buffer is NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+GetFvbCountAndBuffer (\r
+  OUT UINTN                               *NumberHandles,\r
+  OUT EFI_HANDLE                          **Buffer\r
+  )\r
+{\r
+  EFI_STATUS                              Status;\r
+  UINTN                                   BufferSize;\r
+\r
+  if ((NumberHandles == NULL) || (Buffer == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  BufferSize     = 0;\r
+  *NumberHandles = 0;\r
+  *Buffer        = NULL;\r
+  Status = gSmst->SmmLocateHandle (\r
+                    ByProtocol,\r
+                    &gEfiSmmFirmwareVolumeBlockProtocolGuid,\r
+                    NULL,\r
+                    &BufferSize,\r
+                    *Buffer\r
+                    );\r
+  if (EFI_ERROR(Status) && Status != EFI_BUFFER_TOO_SMALL) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  *Buffer = AllocatePool (BufferSize);\r
+  if (*Buffer == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Status = gSmst->SmmLocateHandle (\r
+                    ByProtocol,\r
+                    &gEfiSmmFirmwareVolumeBlockProtocolGuid,\r
+                    NULL,\r
+                    &BufferSize,\r
+                    *Buffer\r
+                    );\r
+\r
+  *NumberHandles = BufferSize / sizeof(EFI_HANDLE);\r
+  if (EFI_ERROR(Status)) {\r
+    *NumberHandles = 0;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Get the variable statistics information from the information buffer pointed by gVariableInfo.\r
+\r
+  @param[in, out]  InfoEntry   A pointer to the buffer of variable information entry.\r
+                               On input, point to the variable information returned last time. if \r
+                               InfoEntry->VendorGuid is zero, return the first information.\r
+                               On output, point to the next variable information.\r
+  @param[in, out]  InfoSize    On input, the size of the variable information buffer.\r
+                               On output, the returned variable information size.\r
+\r
+  @retval EFI_SUCCESS          The variable information is found and returned successfully.\r
+  @retval EFI_UNSUPPORTED      No variable inoformation exists in variable driver. The \r
+                               PcdVariableCollectStatistics should be set TRUE to support it.\r
+  @retval EFI_BUFFER_TOO_SMALL The buffer is too small to hold the next variable information.\r
+\r
+**/\r
+EFI_STATUS\r
+SmmVariableGetStatistics (\r
+  IN OUT SMM_VARIABLE_COMMUNICATE_VARIABLE_INFO_ENTRY  *InfoEntry,\r
+  IN OUT UINTN                                         *InfoSize\r
+  )\r
+{\r
+  SMM_VARIABLE_COMMUNICATE_VARIABLE_INFO_ENTRY         *VariableInfo;\r
+  UINTN                                                NameLength;\r
+  UINTN                                                StatisticsInfoSize;\r
+  CHAR16                                               *InfoName;\r
\r
+  ASSERT (InfoEntry != NULL);\r
+  VariableInfo = gVariableInfo; \r
+  if (VariableInfo == NULL) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  StatisticsInfoSize = sizeof (SMM_VARIABLE_COMMUNICATE_VARIABLE_INFO_ENTRY) + StrSize (VariableInfo->Name);\r
+  if (*InfoSize < sizeof (SMM_VARIABLE_COMMUNICATE_VARIABLE_INFO_ENTRY)) {\r
+    *InfoSize = StatisticsInfoSize;\r
+    return EFI_BUFFER_TOO_SMALL;\r
+  }\r
+  InfoName = (CHAR16 *)(InfoEntry + 1);\r
+\r
+  if (CompareGuid (&InfoEntry->VendorGuid, &mZeroGuid)) {\r
+    //\r
+    // Return the first variable info\r
+    //\r
+    CopyMem (InfoEntry, VariableInfo, sizeof (SMM_VARIABLE_COMMUNICATE_VARIABLE_INFO_ENTRY));\r
+    CopyMem (InfoName, VariableInfo->Name, StrSize (VariableInfo->Name));\r
+    *InfoSize = StatisticsInfoSize;\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // Get the next variable info\r
+  //\r
+  while (VariableInfo != NULL) {\r
+    if (CompareGuid (&VariableInfo->VendorGuid, &InfoEntry->VendorGuid)) {\r
+      NameLength = StrSize (VariableInfo->Name);\r
+      if (NameLength == StrSize (InfoName)) {\r
+        if (CompareMem (VariableInfo->Name, InfoName, NameLength) == 0) {\r
+          //\r
+          // Find the match one\r
+          //\r
+          VariableInfo = VariableInfo->Next;\r
+          break;\r
+        }\r
+      }\r
+    }\r
+    VariableInfo = VariableInfo->Next;\r
+  };\r
+    \r
+  if (VariableInfo == NULL) {\r
+    *InfoSize = 0;\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // Output the new variable info\r
+  //\r
+  StatisticsInfoSize = sizeof (SMM_VARIABLE_COMMUNICATE_VARIABLE_INFO_ENTRY) + StrSize (VariableInfo->Name);\r
+  if (*InfoSize < StatisticsInfoSize) {\r
+    *InfoSize = StatisticsInfoSize;\r
+    return EFI_BUFFER_TOO_SMALL;\r
+  }\r
+\r
+  CopyMem (InfoEntry, VariableInfo, sizeof (SMM_VARIABLE_COMMUNICATE_VARIABLE_INFO_ENTRY));\r
+  CopyMem (InfoName, VariableInfo->Name, StrSize (VariableInfo->Name));\r
+  *InfoSize = StatisticsInfoSize;\r
+  \r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Communication service SMI Handler entry.\r
+\r
+  This SMI handler provides services for the variable wrapper driver.\r
+\r
+  @param[in]     DispatchHandle  The unique handle assigned to this handler by SmiHandlerRegister().\r
+  @param[in]     RegisterContext Points to an optional handler context which was specified when the\r
+                                 handler was registered.\r
+  @param[in, out] CommBuffer     A pointer to a collection of data in memory that will\r
+                                 be conveyed from a non-SMM environment into an SMM environment.\r
+  @param[in, out] CommBufferSize The size of the CommBuffer.\r
+\r
+  @retval EFI_SUCCESS                         The interrupt was handled and quiesced. No other handlers \r
+                                              should still be called.\r
+  @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED  The interrupt has been quiesced but other handlers should \r
+                                              still be called.\r
+  @retval EFI_WARN_INTERRUPT_SOURCE_PENDING   The interrupt is still pending and other handlers should still \r
+                                              be called.\r
+  @retval EFI_INTERRUPT_PENDING               The interrupt could not be quiesced.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmVariableHandler (\r
+  IN     EFI_HANDLE                                DispatchHandle,\r
+  IN     CONST VOID                                *RegisterContext,\r
+  IN OUT VOID                                      *CommBuffer,\r
+  IN OUT UINTN                                     *CommBufferSize\r
+  )\r
+{\r
+  EFI_STATUS                                       Status;\r
+  SMM_VARIABLE_COMMUNICATE_HEADER                  *SmmVariableFunctionHeader;\r
+  SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE         *SmmVariableHeader;\r
+  SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME  *GetNextVariableName;\r
+  SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO     *QueryVariableInfo;\r
+  SMM_VARIABLE_COMMUNICATE_VARIABLE_INFO_ENTRY     *VariableInfo;\r
+  UINTN                                            InfoSize;\r
+\r
+  ASSERT (CommBuffer != NULL);\r
+\r
+  SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *)CommBuffer;\r
+  switch (SmmVariableFunctionHeader->Function) {\r
+    case SMM_VARIABLE_FUNCTION_GET_VARIABLE:\r
+      SmmVariableHeader = (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *) SmmVariableFunctionHeader->Data;     \r
+      Status = VariableServiceGetVariable (\r
+                 SmmVariableHeader->Name,\r
+                 &SmmVariableHeader->Guid,\r
+                 &SmmVariableHeader->Attributes,\r
+                 &SmmVariableHeader->DataSize,\r
+                 (UINT8 *)SmmVariableHeader->Name + SmmVariableHeader->NameSize\r
+                 );\r
+      break;\r
+      \r
+    case SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME:\r
+      GetNextVariableName = (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *) SmmVariableFunctionHeader->Data;\r
+      Status = VariableServiceGetNextVariableName (\r
+                 &GetNextVariableName->NameSize,\r
+                 GetNextVariableName->Name,\r
+                 &GetNextVariableName->Guid\r
+                 );\r
+      break;\r
+      \r
+    case SMM_VARIABLE_FUNCTION_SET_VARIABLE:\r
+      SmmVariableHeader = (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *) SmmVariableFunctionHeader->Data;\r
+      Status = VariableServiceSetVariable (\r
+                 SmmVariableHeader->Name,\r
+                 &SmmVariableHeader->Guid,\r
+                 SmmVariableHeader->Attributes,\r
+                 SmmVariableHeader->DataSize,\r
+                 (UINT8 *)SmmVariableHeader->Name + SmmVariableHeader->NameSize\r
+                 );\r
+      break;\r
+      \r
+    case SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO:\r
+      QueryVariableInfo = (SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO *) SmmVariableFunctionHeader->Data;\r
+      Status = VariableServiceQueryVariableInfo (\r
+                 QueryVariableInfo->Attributes,\r
+                 &QueryVariableInfo->MaximumVariableStorageSize,\r
+                 &QueryVariableInfo->RemainingVariableStorageSize,\r
+                 &QueryVariableInfo->MaximumVariableSize\r
+                 );\r
+      break;\r
+\r
+    case SMM_VARIABLE_FUNCTION_READY_TO_BOOT:\r
+      ReclaimForOS ();\r
+      Status = EFI_SUCCESS;\r
+      break;\r
+  \r
+    case SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE:\r
+      mAtRuntime = TRUE;\r
+      Status = EFI_SUCCESS;\r
+      break;\r
+\r
+    case SMM_VARIABLE_FUNCTION_GET_STATISTICS:\r
+      VariableInfo = (SMM_VARIABLE_COMMUNICATE_VARIABLE_INFO_ENTRY *) SmmVariableFunctionHeader->Data;\r
+      InfoSize = *CommBufferSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_HEADER, Data);\r
+      Status = SmmVariableGetStatistics (VariableInfo, &InfoSize);\r
+      *CommBufferSize = InfoSize + OFFSET_OF (SMM_VARIABLE_COMMUNICATE_HEADER, Data);\r
+      break;\r
+\r
+    default:\r
+      ASSERT (FALSE);\r
+      Status = EFI_UNSUPPORTED;\r
+  }\r
+\r
+  SmmVariableFunctionHeader->ReturnStatus = Status;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  SMM Fault Tolerant Write protocol notification event handler.\r
+\r
+  Non-Volatile variable write may needs FTW protocol to reclaim when \r
+  writting variable.\r
+  \r
+  @param  Protocol   Points to the protocol's unique identifier\r
+  @param  Interface  Points to the interface instance\r
+  @param  Handle     The handle on which the interface was installed\r
+\r
+  @retval EFI_SUCCESS   SmmEventCallback runs successfully\r
+  @retval EFI_NOT_FOUND The Fvb protocol for variable is not found.\r
+  \r
+ **/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmFtwNotificationEvent (\r
+  IN CONST EFI_GUID                       *Protocol,\r
+  IN VOID                                 *Interface,\r
+  IN EFI_HANDLE                           Handle\r
+  )\r
+{\r
+  EFI_STATUS                              Status;\r
+  EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *FvbProtocol;\r
+  EFI_SMM_FAULT_TOLERANT_WRITE_PROTOCOL   *FtwProtocol;\r
+  EFI_PHYSICAL_ADDRESS                    NvStorageVariableBase;\r
+  \r
+  if (mVariableModuleGlobal->FvbInstance != NULL) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // Ensure SMM FTW protocol is installed.\r
+  //\r
+  Status = GetFtwProtocol (&FtwProtocol);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Find the proper FVB protocol for variable.\r
+  //\r
+  NvStorageVariableBase = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageVariableBase64);\r
+  if (NvStorageVariableBase == 0) {\r
+    NvStorageVariableBase = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageVariableBase);\r
+  }\r
+  Status = GetFvbInfoByAddress (NvStorageVariableBase, NULL, &FvbProtocol);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  mVariableModuleGlobal->FvbInstance = FvbProtocol;\r
+  \r
+  Status = VariableWriteServiceInitialize ();\r
+  ASSERT_EFI_ERROR (Status);\r
\r
+  //\r
+  // Notify the variable wrapper driver the variable write service is ready\r
+  //\r
+  Status = gBS->InstallProtocolInterface (\r
+                  &mSmmVariableHandle,\r
+                  &mSmmVariableWriteGuid,\r
+                  EFI_NATIVE_INTERFACE,\r
+                  NULL\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+  \r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Variable Driver main entry point. The Variable driver places the 4 EFI\r
+  runtime services in the EFI System Table and installs arch protocols \r
+  for variable read and write services being availible. It also registers\r
+  a notification function for an EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.\r
+\r
+  @param[in] ImageHandle    The firmware allocated handle for the EFI image.  \r
+  @param[in] SystemTable    A pointer to the EFI System Table.\r
+  \r
+  @retval EFI_SUCCESS       Variable service successfully initialized.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+VariableServiceInitialize (\r
+  IN EFI_HANDLE                           ImageHandle,\r
+  IN EFI_SYSTEM_TABLE                     *SystemTable\r
+  )\r
+{\r
+  EFI_STATUS                              Status;\r
+  EFI_HANDLE                              VariableHandle;\r
+  VOID                                    *SmmFtwRegistration;\r
+  \r
+  //\r
+  // Variable initialize.\r
+  //\r
+  Status = VariableCommonInitialize ();\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // Install the Smm Variable Protocol on a new handle.\r
+  //\r
+  VariableHandle = NULL;\r
+  Status = gSmst->SmmInstallProtocolInterface (\r
+                    &VariableHandle,\r
+                    &gEfiSmmVariableProtocolGuid,\r
+                    EFI_NATIVE_INTERFACE,\r
+                    &gSmmVariable\r
+                    );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  ///\r
+  /// Register SMM variable SMI handler\r
+  ///\r
+  VariableHandle = NULL;\r
+  Status = gSmst->SmiHandlerRegister (SmmVariableHandler, &gEfiSmmVariableProtocolGuid, &VariableHandle);\r
+  ASSERT_EFI_ERROR (Status);\r
+  \r
+  //\r
+  // Notify the variable wrapper driver the variable service is ready\r
+  //\r
+  Status = SystemTable->BootServices->InstallProtocolInterface (\r
+                                        &mVariableHandle,\r
+                                        &gEfiSmmVariableProtocolGuid,\r
+                                        EFI_NATIVE_INTERFACE,\r
+                                        &gSmmVariable\r
+                                        );\r
+  ASSERT_EFI_ERROR (Status);\r
\r
+  //\r
+  // Register FtwNotificationEvent () notify function.\r
+  // \r
+  Status = gSmst->SmmRegisterProtocolNotify (\r
+                    &gEfiSmmFaultTolerantWriteProtocolGuid,\r
+                    SmmFtwNotificationEvent,\r
+                    &SmmFtwRegistration\r
+                    );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  SmmFtwNotificationEvent (NULL, NULL, NULL);\r
+  \r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf
new file mode 100644 (file)
index 0000000..6a52c6f
--- /dev/null
@@ -0,0 +1,86 @@
+## @file
+#  Component description file for SMM Variable module.
+#
+#  This module installs SMM variable protocol into SMM protocol database,
+#  which can be used by SMM driver, and installs SMM variable protocol 
+#  into BS protocol database, which can be used to notify the SMM Runtime
+#  Dxe driver that the SMM variable service is ready.
+#  This module should be used with SMM Runtime DXE module together. The 
+#  SMM Runtime DXE module would install variable arch protocol and variable 
+#  write arch protocol based on SMM variable module.
+# Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>
+#
+#  This program and the accompanying materials
+#  are licensed and made available under the terms and conditions of the BSD License
+#  which accompanies this distribution. The full text of the license may be found at
+#  http://opensource.org/licenses/bsd-license.php
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = VariableSmm
+  FILE_GUID                      = 23A089B3-EED5-4ac5-B2AB-43E3298C2343
+  MODULE_TYPE                    = DXE_SMM_DRIVER
+  VERSION_STRING                 = 1.0
+  PI_SPECIFICATION_VERSION       = 0x0001000A
+  ENTRY_POINT                    = VariableServiceInitialize
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64
+#
+
+
+[Sources]
+  Reclaim.c
+  Variable.c
+  VariableSmm.c
+  Variable.h
+  VariableSmmCommon.h
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+  UefiDriverEntryPoint
+  MemoryAllocationLib
+  BaseLib
+  SynchronizationLib
+  UefiLib
+  SmmLib
+  SmmServicesTableLib
+  BaseMemoryLib
+  DebugLib
+  DxeServicesTableLib
+
+[Protocols]
+  gEfiSmmFirmwareVolumeBlockProtocolGuid        ## SOMETIMES_CONSUMES
+  gEfiSmmVariableProtocolGuid                   ## ALWAYS_PRODUCES
+  gEfiSmmFaultTolerantWriteProtocolGuid         ## SOMETIMES_CONSUMES
+
+[Guids]
+  gEfiVariableGuid                              ## PRODUCES ## Configuration Table Guid 
+  gEfiGlobalVariableGuid                        ## PRODUCES ## Variable Guid
+
+[Pcd]
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64
+  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize
+  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxHardwareErrorVariableSize
+  gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize
+  gEfiMdeModulePkgTokenSpaceGuid.PcdHwErrStorageSize
+  
+[FeaturePcd]
+  gEfiMdeModulePkgTokenSpaceGuid.PcdVariableCollectStatistics  ## SOMETIME_CONSUMES (statistic the information of variable.)
+
+[Depex]
+  TRUE
+
+    
\ No newline at end of file
diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmCommon.h b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmCommon.h
new file mode 100644 (file)
index 0000000..06541ec
--- /dev/null
@@ -0,0 +1,40 @@
+/** @file\r
+\r
+  The internal header file includes the common header files shared \r
+  by VariableSmm module and VariableSmmRuntimeDxe module.\r
+\r
+Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials                          \r
+are licensed and made available under the terms and conditions of the BSD License         \r
+which accompanies this distribution.  The full text of the license may be found at        \r
+http://opensource.org/licenses/bsd-license.php                                            \r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.  \r
+\r
+**/\r
+\r
+#ifndef _VARIABLE_SMM_COMMON_H_\r
+#define _VARIABLE_SMM_COMMON_H_\r
+\r
+#include <PiDxe.h>\r
+\r
+#include <Protocol/SmmVariable.h>\r
+#include <Protocol/SmmFirmwareVolumeBlock.h>\r
+#include <Guid/VariableFormat.h>\r
+\r
+#define EFI_SMM_VARIABLE_WRITE_GUID \\r
+  { 0x93ba1826, 0xdffb, 0x45dd, { 0x82, 0xa7, 0xe7, 0xdc, 0xaa, 0x3b, 0xbd, 0xf3 } }\r
+\r
+///\r
+/// Size of SMM communicate header, without including the payload.\r
+///\r
+#define SMM_COMMUNICATE_HEADER_SIZE  (OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data))\r
+\r
+///\r
+/// Size of SMM variable communicate header, without including the payload.\r
+///\r
+#define SMM_VARIABLE_COMMUNICATE_HEADER_SIZE  (OFFSET_OF (SMM_VARIABLE_COMMUNICATE_HEADER, Data))\r
+\r
+\r
+#endif\r
diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c
new file mode 100644 (file)
index 0000000..ac8b96c
--- /dev/null
@@ -0,0 +1,650 @@
+/** @file\r
+\r
+  Implement all four UEFI Runtime Variable services for the nonvolatile\r
+  and volatile storage space and install variable architecture protocol\r
+  based on SMM variable module.\r
+\r
+Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials                          \r
+are licensed and made available under the terms and conditions of the BSD License         \r
+which accompanies this distribution.  The full text of the license may be found at        \r
+http://opensource.org/licenses/bsd-license.php                                            \r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
+\r
+**/\r
+\r
+#include <Protocol/VariableWrite.h>\r
+#include <Protocol/Variable.h>\r
+#include <Protocol/SmmCommunication.h>\r
+\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiRuntimeServicesTableLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/UefiDriverEntryPoint.h>\r
+#include <Library/UefiRuntimeLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/BaseLib.h>\r
+\r
+#include <Guid/EventGroup.h>\r
+#include "VariableSmmCommon.h"\r
+\r
+EFI_HANDLE                       mHandle                    = NULL; \r
+EFI_SMM_VARIABLE_PROTOCOL       *mSmmVariable               = NULL;\r
+EFI_EVENT                        mVirtualAddressChangeEvent = NULL;\r
+EFI_SMM_COMMUNICATION_PROTOCOL  *mSmmCommunication          = NULL;\r
+UINT8                           *mVariableBuffer            = NULL;\r
+UINT8                           *mVariableBufferPhysical    = NULL;\r
+EFI_GUID                         mSmmVariableWriteGuid      = EFI_SMM_VARIABLE_WRITE_GUID;\r
+UINTN                            mVariableBufferSize;\r
+\r
+\r
+/**\r
+  Initialize the communicate buffer using DataSize and Function.\r
+\r
+  The communicate size is: SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE +\r
+  DataSize.\r
+\r
+  @param[out]      DataPtr          Points to the data in the communicate buffer.\r
+  @param[in]       DataSize         The data size to send to SMM.\r
+  @param[in]       Function         The function number to initialize the communicate header.\r
+                      \r
+  @retval EFI_INVALID_PARAMETER     The data size is too big.\r
+  @retval EFI_SUCCESS               Find the specified variable.\r
+\r
+**/\r
+EFI_STATUS\r
+InitCommunicateBuffer (\r
+  OUT     VOID                              **DataPtr OPTIONAL,\r
+  IN      UINTN                             DataSize,\r
+  IN      UINTN                             Function\r
+  )\r
+{\r
+  EFI_SMM_COMMUNICATE_HEADER                *SmmCommunicateHeader;  \r
+  SMM_VARIABLE_COMMUNICATE_HEADER           *SmmVariableFunctionHeader; \r
+\r
\r
+  if (DataSize + SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE > mVariableBufferSize) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) mVariableBuffer;\r
+  CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmVariableProtocolGuid);\r
+  SmmCommunicateHeader->MessageLength = DataSize + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;\r
+   \r
+  SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *) SmmCommunicateHeader->Data;\r
+  SmmVariableFunctionHeader->Function = Function;\r
+  if (DataPtr != NULL) {\r
+    *DataPtr = SmmVariableFunctionHeader->Data;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Send the data in communicate buffer to SMM.\r
+\r
+  @param[in]   DataSize               This size of the function header and the data.\r
+\r
+  @RetVal      EFI_SUCCESS            Success is returned from the functin in SMM.\r
+  @RetVal      Others                 Failure is returned from the function in SMM. \r
+  \r
+**/\r
+EFI_STATUS\r
+SendCommunicateBuffer (\r
+  IN      UINTN                             DataSize\r
+  )\r
+{\r
+  EFI_STATUS                                Status;\r
+  UINTN                                     CommSize;\r
+  EFI_SMM_COMMUNICATE_HEADER                *SmmCommunicateHeader;  \r
+  SMM_VARIABLE_COMMUNICATE_HEADER           *SmmVariableFunctionHeader;\r
+  \r
+  CommSize = DataSize + SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;\r
+  Status = mSmmCommunication->Communicate (mSmmCommunication, mVariableBufferPhysical, &CommSize);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  SmmCommunicateHeader      = (EFI_SMM_COMMUNICATE_HEADER *) mVariableBuffer;\r
+  SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *)SmmCommunicateHeader->Data;\r
+  return  SmmVariableFunctionHeader->ReturnStatus;\r
+}\r
+\r
+\r
+/**\r
+  This code finds variable in storage blocks (Volatile or Non-Volatile).\r
+\r
+  @param[in]      VariableName       Name of Variable to be found.\r
+  @param[in]      VendorGuid         Variable vendor GUID.\r
+  @param[out]     Attributes         Attribute value of the variable found.\r
+  @param[in, out] DataSize           Size of Data found. If size is less than the\r
+                                     data, this value contains the required size.\r
+  @param[out]     Data               Data pointer.\r
+                      \r
+  @retval EFI_INVALID_PARAMETER      Invalid parameter.\r
+  @retval EFI_SUCCESS                Find the specified variable.\r
+  @retval EFI_NOT_FOUND              Not found.\r
+  @retval EFI_BUFFER_TO_SMALL        DataSize is too small for the result.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+RuntimeServiceGetVariable (\r
+  IN      CHAR16                            *VariableName,\r
+  IN      EFI_GUID                          *VendorGuid,\r
+  OUT     UINT32                            *Attributes OPTIONAL,\r
+  IN OUT  UINTN                             *DataSize,\r
+  OUT     VOID                              *Data\r
+  )\r
+{\r
+  EFI_STATUS                                Status;\r
+  UINTN                                     PayloadSize;\r
+  SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE  *SmmVariableHeader;\r
+\r
+  if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((*DataSize != 0) && (Data == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  \r
+  //\r
+  // Init the communicate buffer. The buffer data size is:\r
+  // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.\r
+  //\r
+  PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + StrSize (VariableName);\r
+  Status = InitCommunicateBuffer (&SmmVariableHeader, PayloadSize, SMM_VARIABLE_FUNCTION_GET_VARIABLE);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  ASSERT (SmmVariableHeader != NULL);\r
+\r
+  CopyGuid (&SmmVariableHeader->Guid, VendorGuid);\r
+  SmmVariableHeader->DataSize   = *DataSize;\r
+  SmmVariableHeader->NameSize   = StrSize (VariableName);\r
+  if (Attributes == NULL) {\r
+    SmmVariableHeader->Attributes = 0;\r
+  } else {\r
+    SmmVariableHeader->Attributes = *Attributes;\r
+  }\r
+  CopyMem (SmmVariableHeader->Name, VariableName, SmmVariableHeader->NameSize);\r
+\r
+  //\r
+  // Send data to SMM.\r
+  //\r
+  Status = SendCommunicateBuffer (PayloadSize);\r
+\r
+  //\r
+  // Get data from SMM.\r
+  //\r
+  *DataSize = SmmVariableHeader->DataSize;\r
+  if (Attributes != NULL) {\r
+    *Attributes = SmmVariableHeader->Attributes;\r
+  }\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  CopyMem (Data, (UINT8 *)SmmVariableHeader->Name + SmmVariableHeader->NameSize, SmmVariableHeader->DataSize);\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  This code Finds the Next available variable.\r
+\r
+  @param[in, out] VariableNameSize   Size of the variable name.\r
+  @param[in, out] VariableName       Pointer to variable name.\r
+  @param[in, out] VendorGuid         Variable Vendor Guid.\r
+\r
+  @retval EFI_INVALID_PARAMETER      Invalid parameter.\r
+  @retval EFI_SUCCESS                Find the specified variable.\r
+  @retval EFI_NOT_FOUND              Not found.\r
+  @retval EFI_BUFFER_TO_SMALL        DataSize is too small for the result.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+RuntimeServiceGetNextVariableName (\r
+  IN OUT  UINTN                             *VariableNameSize,\r
+  IN OUT  CHAR16                            *VariableName,\r
+  IN OUT  EFI_GUID                          *VendorGuid\r
+  )\r
+{\r
+  EFI_STATUS                                      Status;\r
+  UINTN                                           PayloadSize;\r
+  SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *SmmGetNextVariableName;\r
+\r
+  if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  \r
+  //\r
+  // Init the communicate buffer. The buffer data size is:\r
+  // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.\r
+  //\r
+  PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name) + *VariableNameSize; \r
+  Status = InitCommunicateBuffer (&SmmGetNextVariableName, PayloadSize, SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  ASSERT (SmmGetNextVariableName != NULL);\r
+\r
+  SmmGetNextVariableName->NameSize = *VariableNameSize;\r
+  CopyGuid (&SmmGetNextVariableName->Guid, VendorGuid);\r
+  CopyMem (SmmGetNextVariableName->Name, VariableName, *VariableNameSize);\r
+\r
+  //\r
+  // Send data to SMM\r
+  //\r
+  Status = SendCommunicateBuffer (PayloadSize);\r
+\r
+  //\r
+  // Get data from SMM.\r
+  //\r
+  *VariableNameSize = SmmGetNextVariableName->NameSize;    \r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  \r
+  CopyGuid (VendorGuid, &SmmGetNextVariableName->Guid);\r
+  CopyMem (VariableName, SmmGetNextVariableName->Name, SmmGetNextVariableName->NameSize);  \r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  This code sets variable in storage blocks (Volatile or Non-Volatile).\r
+\r
+  @param[in] VariableName                 Name of Variable to be found.\r
+  @param[in] VendorGuid                   Variable vendor GUID.\r
+  @param[in] Attributes                   Attribute value of the variable found\r
+  @param[in] DataSize                     Size of Data found. If size is less than the\r
+                                          data, this value contains the required size.\r
+  @param[in] Data                         Data pointer.\r
+\r
+  @retval EFI_INVALID_PARAMETER           Invalid parameter.\r
+  @retval EFI_SUCCESS                     Set successfully.\r
+  @retval EFI_OUT_OF_RESOURCES            Resource not enough to set variable.\r
+  @retval EFI_NOT_FOUND                   Not found.\r
+  @retval EFI_WRITE_PROTECTED             Variable is read-only.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+RuntimeServiceSetVariable (\r
+  IN CHAR16                                 *VariableName,\r
+  IN EFI_GUID                               *VendorGuid,\r
+  IN UINT32                                 Attributes,\r
+  IN UINTN                                  DataSize,\r
+  IN VOID                                   *Data\r
+  )\r
+{\r
+  EFI_STATUS                                Status;\r
+  UINTN                                     PayloadSize; \r
+  SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE  *SmmVariableHeader;\r
+    \r
+  //\r
+  // Check input parameters.\r
+  //\r
+  if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  } \r
+\r
+  if (DataSize != 0 && Data == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  \r
+  //\r
+  // Init the communicate buffer. The buffer data size is:\r
+  // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.\r
+  //\r
+  PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + StrSize (VariableName) + DataSize;\r
+  Status = InitCommunicateBuffer (&SmmVariableHeader, PayloadSize, SMM_VARIABLE_FUNCTION_SET_VARIABLE);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  ASSERT (SmmVariableHeader != NULL);\r
+\r
+  CopyGuid ((EFI_GUID *) &SmmVariableHeader->Guid, VendorGuid);\r
+  SmmVariableHeader->DataSize   = DataSize;\r
+  SmmVariableHeader->NameSize   = StrSize (VariableName);\r
+  SmmVariableHeader->Attributes = Attributes;\r
+  CopyMem (SmmVariableHeader->Name, VariableName, SmmVariableHeader->NameSize);\r
+  CopyMem ((UINT8 *) SmmVariableHeader->Name + SmmVariableHeader->NameSize, Data, DataSize);\r
+\r
+  //\r
+  // Send data to SMM.\r
+  //\r
+  Status = SendCommunicateBuffer (PayloadSize);\r
\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  This code returns information about the EFI variables.\r
+\r
+  @param[in]  Attributes                   Attributes bitmask to specify the type of variables\r
+                                           on which to return information.\r
+  @param[out] MaximumVariableStorageSize   Pointer to the maximum size of the storage space available\r
+                                           for the EFI variables associated with the attributes specified.\r
+  @param[out] RemainingVariableStorageSize Pointer to the remaining size of the storage space available\r
+                                           for EFI variables associated with the attributes specified.\r
+  @param[out] MaximumVariableSize          Pointer to the maximum size of an individual EFI variables\r
+                                           associated with the attributes specified.\r
+\r
+  @retval EFI_INVALID_PARAMETER            An invalid combination of attribute bits was supplied.\r
+  @retval EFI_SUCCESS                      Query successfully.\r
+  @retval EFI_UNSUPPORTED                  The attribute is not supported on this platform.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+RuntimeServiceQueryVariableInfo (\r
+  IN  UINT32                                Attributes,\r
+  OUT UINT64                                *MaximumVariableStorageSize,\r
+  OUT UINT64                                *RemainingVariableStorageSize,\r
+  OUT UINT64                                *MaximumVariableSize\r
+  )\r
+{\r
+  EFI_STATUS                                Status;\r
+  UINTN                                     PayloadSize;\r
+  SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO *SmmQueryVariableInfo;\r
+\r
+  if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  \r
+  //\r
+  // Init the communicate buffer. The buffer data size is:\r
+  // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize;\r
+  //\r
+  PayloadSize = sizeof (SMM_VARIABLE_COMMUNICATE_VARIABLE_INFO_ENTRY);\r
+  Status = InitCommunicateBuffer (&SmmQueryVariableInfo, PayloadSize, SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  ASSERT (SmmQueryVariableInfo != NULL);\r
+\r
+  SmmQueryVariableInfo->Attributes  = Attributes;\r
+\r
+  //\r
+  // Send data to SMM.\r
+  //\r
+  Status = SendCommunicateBuffer (PayloadSize);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Get data from SMM.\r
+  //\r
+  *MaximumVariableSize          = SmmQueryVariableInfo->MaximumVariableSize;\r
+  *MaximumVariableStorageSize   = SmmQueryVariableInfo->MaximumVariableStorageSize;\r
+  *RemainingVariableStorageSize = SmmQueryVariableInfo->RemainingVariableStorageSize; \r
\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Exit Boot Services Event notification handler.\r
+\r
+  Notify SMM variable driver about the event.\r
+\r
+  @param[in]  Event     Event whose notification function is being invoked.\r
+  @param[in]  Context   Pointer to the notification function's context.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+OnExitBootServices (\r
+  IN      EFI_EVENT                         Event,\r
+  IN      VOID                              *Context\r
+  )\r
+{\r
+  //\r
+  // Init the communicate buffer. The buffer data size is:\r
+  // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.\r
+  //\r
+  InitCommunicateBuffer (NULL, 0, SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE); \r
+\r
+  //\r
+  // Send data to SMM.\r
+  //\r
+  SendCommunicateBuffer (0);\r
+}\r
+\r
+\r
+/**\r
+  On Ready To Boot Services Event notification handler.\r
+\r
+  Notify SMM variable driver about the event.\r
+\r
+  @param[in]  Event     Event whose notification function is being invoked\r
+  @param[in]  Context   Pointer to the notification function's context\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+OnReadyToBoot (\r
+  IN      EFI_EVENT                         Event,\r
+  IN      VOID                              *Context\r
+  )\r
+{\r
+  //\r
+  // Init the communicate buffer. The buffer data size is:\r
+  // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.\r
+  //\r
+  InitCommunicateBuffer (NULL, 0, SMM_VARIABLE_FUNCTION_READY_TO_BOOT);\r
+  \r
+  //\r
+  // Send data to SMM.\r
+  //\r
+  SendCommunicateBuffer (0);\r
+}\r
+\r
+\r
+/**\r
+  Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.\r
+\r
+  This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.\r
+  It convers pointer to new virtual address.\r
+\r
+  @param[in]  Event        Event whose notification function is being invoked.\r
+  @param[in]  Context      Pointer to the notification function's context.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+VariableAddressChangeEvent (\r
+  IN EFI_EVENT                              Event,\r
+  IN VOID                                   *Context\r
+  )\r
+{\r
+  EfiConvertPointer (0x0, (VOID **) &mVariableBuffer);\r
+  EfiConvertPointer (0x0, (VOID **) &mSmmCommunication);\r
+}\r
+\r
+\r
+/**\r
+  Initialize variable service and install Variable Architectural protocol.\r
+\r
+  @param[in] Event    Event whose notification function is being invoked.\r
+  @param[in] Context  Pointer to the notification function's context.\r
\r
+**/\r
+VOID\r
+EFIAPI\r
+SmmVariableReady (\r
+  IN  EFI_EVENT                             Event,\r
+  IN  VOID                                  *Context\r
+  )\r
+{\r
+  EFI_STATUS                                Status;\r
+\r
+  Status = gBS->LocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID **)&mSmmVariable);\r
+  if (EFI_ERROR (Status)) {\r
+    return;\r
+  }\r
+  \r
+  Status = gBS->LocateProtocol (&gEfiSmmCommunicationProtocolGuid, NULL, (VOID **) &mSmmCommunication);\r
+  ASSERT_EFI_ERROR (Status);\r
+  \r
+  //\r
+  // Allocate memory for variable store.\r
+  //\r
+  mVariableBufferSize  = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;\r
+  mVariableBufferSize += MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize));\r
+  mVariableBuffer      = AllocateRuntimePool (mVariableBufferSize);\r
+  ASSERT (mVariableBuffer != NULL);\r
+\r
+  //\r
+  // Save the buffer physical address used for SMM conmunication.\r
+  //\r
+  mVariableBufferPhysical = mVariableBuffer;\r
+\r
+  gRT->GetVariable         = RuntimeServiceGetVariable;\r
+  gRT->GetNextVariableName = RuntimeServiceGetNextVariableName;\r
+  gRT->SetVariable         = RuntimeServiceSetVariable;\r
+  gRT->QueryVariableInfo   = RuntimeServiceQueryVariableInfo;\r
\r
+  //\r
+  // Install the Variable Architectural Protocol on a new handle.\r
+  //\r
+  Status = gBS->InstallProtocolInterface (\r
+                  &mHandle,\r
+                  &gEfiVariableArchProtocolGuid, \r
+                  EFI_NATIVE_INTERFACE,\r
+                  NULL\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+}\r
+\r
+\r
+/**\r
+  SMM Non-Volatile variable write service is ready notify event handler.\r
+\r
+  @param[in] Event    Event whose notification function is being invoked.\r
+  @param[in] Context  Pointer to the notification function's context.\r
+  \r
+**/\r
+VOID\r
+EFIAPI\r
+SmmVariableWriteReady (\r
+  IN  EFI_EVENT                             Event,\r
+  IN  VOID                                  *Context\r
+  )\r
+{\r
+  EFI_STATUS                                Status;\r
+  VOID                                      *ProtocolOps;\r
+\r
+  //\r
+  // Check whether the protocol is installed or not.\r
+  //\r
+  Status = gBS->LocateProtocol (&mSmmVariableWriteGuid, NULL, (VOID **) &ProtocolOps);\r
+  if (EFI_ERROR (Status)) {\r
+    return;\r
+  }\r
\r
+  Status = gBS->InstallProtocolInterface (\r
+                  &mHandle,\r
+                  &gEfiVariableWriteArchProtocolGuid, \r
+                  EFI_NATIVE_INTERFACE,\r
+                  NULL\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);  \r
+}\r
+\r
+\r
+/**\r
+  Variable Driver main entry point. The Variable driver places the 4 EFI\r
+  runtime services in the EFI System Table and installs arch protocols \r
+  for variable read and write services being availible. It also registers\r
+  a notification function for an EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.\r
+\r
+  @param[in] ImageHandle    The firmware allocated handle for the EFI image.  \r
+  @param[in] SystemTable    A pointer to the EFI System Table.\r
+  \r
+  @retval EFI_SUCCESS       Variable service successfully initialized.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+VariableSmmRuntimeInitialize (\r
+  IN EFI_HANDLE                             ImageHandle,\r
+  IN EFI_SYSTEM_TABLE                       *SystemTable\r
+  )\r
+{\r
+  VOID                                      *SmmVariableRegistration;\r
+  VOID                                      *SmmVariableWriteRegistration;\r
+  EFI_EVENT                                 OnReadyToBootEvent;\r
+  EFI_EVENT                                 ExitBootServiceEvent;\r
+  \r
+  //\r
+  // Smm variable service is ready\r
+  //\r
+  EfiCreateProtocolNotifyEvent (\r
+    &gEfiSmmVariableProtocolGuid, \r
+    TPL_CALLBACK, \r
+    SmmVariableReady, \r
+    NULL, \r
+    &SmmVariableRegistration\r
+    );\r
+\r
+  //\r
+  // Smm Non-Volatile variable write service is ready\r
+  //\r
+  EfiCreateProtocolNotifyEvent (\r
+    &mSmmVariableWriteGuid, \r
+    TPL_CALLBACK, \r
+    SmmVariableWriteReady, \r
+    NULL, \r
+    &SmmVariableWriteRegistration\r
+    );\r
+\r
+  //\r
+  // Register the event to reclaim variable for OS usage.\r
+  //\r
+  EfiCreateEventReadyToBootEx (\r
+    TPL_NOTIFY, \r
+    OnReadyToBoot, \r
+    NULL, \r
+    &OnReadyToBootEvent\r
+    );             \r
+\r
+  //\r
+  // Register the event to inform SMM variable that it is at runtime.\r
+  //\r
+  gBS->CreateEventEx (\r
+         EVT_NOTIFY_SIGNAL,\r
+         TPL_NOTIFY,\r
+         OnExitBootServices,\r
+         NULL,\r
+         &gEfiEventExitBootServicesGuid,\r
+         &ExitBootServiceEvent\r
+         ); \r
+\r
+  //\r
+  // Register the event to convert the pointer for runtime.\r
+  //\r
+  gBS->CreateEventEx (\r
+         EVT_NOTIFY_SIGNAL,\r
+         TPL_NOTIFY,\r
+         VariableAddressChangeEvent,\r
+         NULL,\r
+         &gEfiEventVirtualAddressChangeGuid,\r
+         &mVirtualAddressChangeEvent\r
+         );\r
+  \r
+  return EFI_SUCCESS;\r
+}\r
+\r
diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf
new file mode 100644 (file)
index 0000000..9f1a6ff
--- /dev/null
@@ -0,0 +1,69 @@
+## @file\r
+#  Component description file for Variable SmmRuntimeDxe module.\r
+#\r
+#  This module is the Runtime DXE part correspond to SMM variable module. It \r
+#  installs variable arch protocol and variable write arch protocol and works \r
+#  with SMM variable module together. \r
+# Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>\r
+#\r
+#  This program and the accompanying materials\r
+#  are licensed and made available under the terms and conditions of the BSD License\r
+#  which accompanies this distribution. The full text of the license may be found at\r
+#  http://opensource.org/licenses/bsd-license.php\r
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+#\r
+##\r
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = VariableSmmRuntimeDxe\r
+  FILE_GUID                      = 9F7DCADE-11EA-448a-A46F-76E003657DD1\r
+  MODULE_TYPE                    = DXE_RUNTIME_DRIVER\r
+  VERSION_STRING                 = 1.0\r
+  ENTRY_POINT                    = VariableSmmRuntimeInitialize\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64\r
+#\r
+#  VIRTUAL_ADDRESS_MAP_CALLBACK  =  VariableAddressChangeEvent\r
+#\r
+\r
+[Sources]\r
+  VariableSmmRuntimeDxe.c\r
+  VariableSmmCommon.h\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+  SecurityPkg/SecurityPkg.dec\r
+\r
+[LibraryClasses]\r
+  MemoryAllocationLib\r
+  BaseLib  \r
+  UefiBootServicesTableLib\r
+  DebugLib\r
+  UefiRuntimeLib\r
+  DxeServicesTableLib\r
+  UefiDriverEntryPoint\r
+  PcdLib  \r
+\r
+[Protocols]\r
+  gEfiVariableWriteArchProtocolGuid             ## ALWAYS_PRODUCES\r
+  gEfiVariableArchProtocolGuid                  ## ALWAYS_PRODUCES  \r
+  gEfiSmmCommunicationProtocolGuid\r
+  gEfiSmmVariableProtocolGuid\r
+\r
+[Guids]\r
+  gEfiEventVirtualAddressChangeGuid             ## PRODUCES ## Event\r
+\r
+[Pcd]\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxHardwareErrorVariableSize\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase\r
+  \r
+[Depex]\r
+  gEfiSmmCommunicationProtocolGuid\r