Add SMM Variable implementation.

git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@11151 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
gdong1 2010-12-10 09:27:54 +00:00
parent d3b4af2bca
commit 8a2d49964e
24 changed files with 3914 additions and 1334 deletions

View File

@ -157,4 +157,90 @@ struct _VARIABLE_INFO_ENTRY {
BOOLEAN Volatile; ///< TRUE if volatile, FALSE if non-volatile.
};
//
// This structure is used for SMM variable. the collected statistics data is saved in SMRAM. It can be got from
// SMI handler. The communication buffer should be:
// EFI_SMM_COMMUNICATE_HEADER + SMM_VARIABLE_COMMUNICATE_HEADER + payload.
//
typedef struct {
UINTN Function;
EFI_STATUS ReturnStatus;
UINT8 Data[1];
} SMM_VARIABLE_COMMUNICATE_HEADER;
//
// The payload for this function is SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE.
//
#define SMM_VARIABLE_FUNCTION_GET_VARIABLE 1
//
// The payload for this function is SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME.
//
#define SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME 2
//
// The payload for this function is SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE.
//
#define SMM_VARIABLE_FUNCTION_SET_VARIABLE 3
//
// The payload for this function is SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO.
//
#define SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO 4
//
// It is a notify event, no extra payload for this function.
//
#define SMM_VARIABLE_FUNCTION_READY_TO_BOOT 5
//
// It is a notify event, no extra payload for this function.
//
#define SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE 6
//
// The payload for this function is VARIABLE_INFO_ENTRY. The GUID in EFI_SMM_COMMUNICATE_HEADER
// is gEfiSmmVariableProtocolGuid.
//
#define SMM_VARIABLE_FUNCTION_GET_STATISTICS 7
///
/// Size of SMM communicate header, without including the payload.
///
#define SMM_COMMUNICATE_HEADER_SIZE (OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data))
///
/// Size of SMM variable communicate header, without including the payload.
///
#define SMM_VARIABLE_COMMUNICATE_HEADER_SIZE (OFFSET_OF (SMM_VARIABLE_COMMUNICATE_HEADER, Data))
///
/// This structure is used to communicate with SMI handler by SetVariable and GetVariable.
///
typedef struct {
EFI_GUID Guid;
UINTN DataSize;
UINTN NameSize;
UINT32 Attributes;
CHAR16 Name[1];
} SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE;
///
/// This structure is used to communicate with SMI handler by GetNextVariableName.
///
typedef struct {
EFI_GUID Guid;
UINTN NameSize;
CHAR16 Name[1];
} SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME;
///
/// This structure is used to communicate with SMI handler by QueryVariableInfo.
///
typedef struct {
UINT64 MaximumVariableStorageSize;
UINT64 RemainingVariableStorageSize;
UINT64 MaximumVariableSize;
UINT32 Attributes;
} SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO;
///
/// This structure is used to communicate with SMI handler to get variable statistics information.
///
typedef VARIABLE_INFO_ENTRY SMM_VARIABLE_COMMUNICATE_VARIABLE_INFO_ENTRY;
#endif // _EFI_VARIABLE_H_

View File

@ -0,0 +1,38 @@
/** @file
SMM Fault Tolerant Write protocol is related to EDK II-specific implementation of FTW,
provides boot-time service for fault tolerant write capability for block devices in
EFI SMM environment. The protocol provides for non-volatile storage of the intermediate
data and private information a caller would need to recover from a critical fault,
such as a power failure.
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 that 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.
**/
#ifndef __SMM_FAULT_TOLERANT_WRITE_H__
#define __SMM_FAULT_TOLERANT_WRITE_H__
#include <Protocol/FaultTolerantWrite.h>
#define EFI_SMM_FAULT_TOLERANT_WRITE_PROTOCOL_GUID \
{ \
0x3868fc3b, 0x7e45, 0x43a7, { 0x90, 0x6c, 0x4b, 0xa4, 0x7d, 0xe1, 0x75, 0x4d } \
}
//
// SMM Fault Tolerant Write protocol structure is the same as Fault Tolerant Write protocol.
// The SMM one is intend to run in SMM environment, which means it can be used by
// SMM drivers after ExitPmAuth.
//
typedef EFI_FAULT_TOLERANT_WRITE_PROTOCOL EFI_SMM_FAULT_TOLERANT_WRITE_PROTOCOL;
extern EFI_GUID gEfiSmmFaultTolerantWriteProtocolGuid;
#endif

View File

@ -0,0 +1,36 @@
/** @file
SMM Firmware Volume Block protocol is related to EDK II-specific implementation of
FVB driver, provides control over block-oriented firmware devices and is intended
to use in the EFI SMM environment.
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 that 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.
**/
#ifndef __SMM_FIRMWARE_VOLUME_BLOCK_H__
#define __SMM_FIRMWARE_VOLUME_BLOCK_H__
#include <Protocol/FirmwareVolumeBlock.h>
#define EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL_GUID \
{ \
0xf52fc9ff, 0x8025, 0x4432, { 0xa5, 0x3b, 0xb4, 0x7b, 0x5e, 0x9, 0xdb, 0xf9 } \
}
//
// SMM Firmware Volume Block protocol structure is the same as Firmware Volume Block
// protocol. The SMM one is intend to run in SMM environment, which means it can be
// used by SMM drivers after ExitPmAuth.
//
typedef EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL;
extern EFI_GUID gEfiSmmFirmwareVolumeBlockProtocolGuid;
#endif

View File

@ -0,0 +1,40 @@
/** @file
The EFI_SMM_SWAP_ADDRESS_RANGE_PROTOCOL is related to EDK II-specific implementation
and used to abstract the swap operation of boot block and backup block of FV in EFI
SMM environment. This swap is especially needed when updating the boot block of FV.
If a power failure happens during the boot block update, the swapped backup block
(now the boot block) can boot the machine with the old boot block backed up in it.
The swap operation is platform dependent, so other protocols such as SMM FTW (Fault
Tolerant Write) should use this protocol instead of handling hardware directly.
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 that 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.
**/
#ifndef __SMM_SWAP_ADDRESS_RANGE_H__
#define __SMM_SWAP_ADDRESS_RANGE_H__
#include <Protocol/SwapAddressRange.h>
#define EFI_SMM_SWAP_ADDRESS_RANGE_PROTOCOL_GUID \
{ \
0x67c4f112, 0x3385, 0x4e55, { 0x9c, 0x5b, 0xc0, 0x5b, 0x71, 0x7c, 0x42, 0x28 } \
}
//
// SMM Swap Address Range protocol structure is the same as Swap Address Range protocol.
// The SMM one is intend to run in SMM environment, which means it can be used by
// SMM drivers after ExitPmAuth.
//
typedef EFI_SWAP_ADDRESS_RANGE_PROTOCOL EFI_SMM_SWAP_ADDRESS_RANGE_PROTOCOL;
extern EFI_GUID gEfiSmmSwapAddressRangeProtocolGuid;
#endif

View File

@ -0,0 +1,39 @@
/** @file
EFI SMM Variable Protocol is related to EDK II-specific implementation of variables
and intended for use as a means to store data in the EFI SMM environment.
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.
**/
#ifndef __SMM_VARIABLE_H__
#define __SMM_VARIABLE_H__
#define EFI_SMM_VARIABLE_PROTOCOL_GUID \
{ \
0xed32d533, 0x99e6, 0x4209, { 0x9c, 0xc0, 0x2d, 0x72, 0xcd, 0xd9, 0x98, 0xa7 } \
}
typedef struct _EFI_SMM_VARIABLE_PROTOCOL EFI_SMM_VARIABLE_PROTOCOL;
///
/// EFI SMM Variable Protocol is intended for use as a means
/// to store data in the EFI SMM environment.
///
struct _EFI_SMM_VARIABLE_PROTOCOL {
EFI_GET_VARIABLE SmmGetVariable;
EFI_GET_NEXT_VARIABLE_NAME SmmGetNextVariableName;
EFI_SET_VARIABLE SmmSetVariable;
EFI_QUERY_VARIABLE_INFO SmmQueryVariableInfo;
};
extern EFI_GUID gEfiSmmVariableProtocolGuid;
#endif

View File

@ -171,9 +171,25 @@
# Include/Protocol/FaultTolerantWrite.h
gEfiFaultTolerantWriteProtocolGuid = { 0x3EBD9E82, 0x2C78, 0x4DE6, { 0x97, 0x86, 0x8D, 0x4B, 0xFC, 0xB7, 0xC8, 0x81 }}
## This protocol provides boot-time service to do fault tolerant write capability for block devices in SMM environment.
# Include/Protocol/SmmFaultTolerantWrite.h
gEfiSmmFaultTolerantWriteProtocolGuid = { 0x3868fc3b, 0x7e45, 0x43a7, { 0x90, 0x6c, 0x4b, 0xa4, 0x7d, 0xe1, 0x75, 0x4d }}
## This protocol is used to abstract the swap operation of boot block and backup block of boot FV.
# Include/Protocol/SwapAddressRange.h
gEfiSwapAddressRangeProtocolGuid = { 0x1259F60D, 0xB754, 0x468E, { 0xA7, 0x89, 0x4D, 0xB8, 0x5D, 0x55, 0xE8, 0x7E }}
## This protocol is used to abstract the swap operation of boot block and backup block of boot FV in SMM environment.
# Include/Protocol/SmmSwapAddressRange.h
gEfiSmmSwapAddressRangeProtocolGuid = { 0x67c4f112, 0x3385, 0x4e55, { 0x9c, 0x5b, 0xc0, 0x5b, 0x71, 0x7c, 0x42, 0x28 }}
## This protocol is intended for use as a means to store data in the EFI SMM environment.
# Include/Protocol/SmmVariableProtocol.h
gEfiSmmVariableProtocolGuid = { 0xed32d533, 0x99e6, 0x4209, { 0x9c, 0xc0, 0x2d, 0x72, 0xcd, 0xd9, 0x98, 0xa7 }}
## This protocol is similar with DXE FVB protocol and used in the UEFI SMM evvironment.
# Include/Protocol/SmmFirmwareVolumeBlock.h
gEfiSmmFirmwareVolumeBlockProtocolGuid = { 0xd326d041, 0xbd31, 0x4c01, { 0xb5, 0xa8, 0x62, 0x8b, 0xe8, 0x7f, 0x6, 0x53 }}
[PcdsFeatureFlag]
## Indicate whether platform can support update capsule across a system reset
@ -224,6 +240,10 @@
# interrupt to access usb device in the case of absence of usb stack.
# DUET platform requires the token to be TRUE.
gEfiMdeModulePkgTokenSpaceGuid.PcdTurnOffUsbLegacySupport|FALSE|BOOLEAN|0x00010047
## If TRUE, the variable services are provided in DXE_SMM. The SMM driver can use SMM variable protocol
# to access variable. Otherwise the variable services are provided in DXE_RUNTIME.
gEfiMdeModulePkgTokenSpaceGuid.PcdSmmVariableEnable|TRUE|BOOLEAN|0x00010048
## If TRUE, HiiImageProtocol will be installed.
# FALSE is for size reduction.

View File

@ -257,6 +257,7 @@
MdeModulePkg/Universal/Variable/Pei/VariablePei.inf
MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimer.inf
MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf
MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.inf
MdeModulePkg/Universal/Acpi/AcpiPlatformDxe/AcpiPlatformDxe.inf
MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableDxe.inf
@ -278,6 +279,8 @@
[Components.IA32, Components.X64]
MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf
MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf
MdeModulePkg/Library/SmmReportStatusCodeLib/SmmReportStatusCodeLib.inf
MdeModulePkg/Universal/StatusCodeHandler/Smm/StatusCodeHandlerSmm.inf
MdeModulePkg/Universal/ReportStatusCodeRouter/Smm/ReportStatusCodeRouterSmm.inf

View File

@ -1,44 +1,7 @@
/** @file
This is a simple fault tolerant write driver.
This boot service protocol only provides fault tolerant write capability for
block devices. The protocol has internal non-volatile intermediate storage
of the data and private information. It should be able to recover
automatically from a critical fault, such as power failure.
The implementation uses an FTW (Fault Tolerant Write) Work Space.
This work space is a memory copy of the work space on the Working Block,
the size of the work space is the FTW_WORK_SPACE_SIZE bytes.
The work space stores each write record as EFI_FTW_RECORD structure.
The spare block stores the write buffer before write to the target block.
The write record has three states to specify the different phase of write operation.
1) WRITE_ALLOCATED is that the record is allocated in write space.
The information of write operation is stored in write record structure.
2) SPARE_COMPLETED is that the data from write buffer is writed into the spare block as the backup.
3) WRITE_COMPLETED is that the data is copied from the spare block to the target block.
This driver operates the data as the whole size of spare block.
It first read the SpareAreaLength data from the target block into the spare memory buffer.
Then copy the write buffer data into the spare memory buffer.
Then write the spare memory buffer into the spare block.
Final copy the data from the spare block to the target block.
To make this drive work well, the following conditions must be satisfied:
1. The write NumBytes data must be fit within Spare area.
Offset + NumBytes <= SpareAreaLength
2. The whole flash range has the same block size.
3. Working block is an area which contains working space in its last block and has the same size as spare block.
4. Working Block area must be in the single one Firmware Volume Block range which FVB protocol is produced on.
5. Spare area must be in the single one Firmware Volume Block range which FVB protocol is produced on.
6. Any write data area (SpareAreaLength Area) which the data will be written into must be
in the single one Firmware Volume Block range which FVB protocol is produced on.
7. If write data area (such as Variable range) is enlarged, the spare area range must be enlarged.
The spare area must be enough large to store the write data before write them into the target range.
If one of them is not satisfied, FtwWrite may fail.
Usually, Spare area only takes one block. That's SpareAreaLength = BlockSize, NumberOfSpareBlock = 1.
These are the common Fault Tolerant Write (FTW) functions that are shared
by DXE FTW driver and SMM FTW driver.
Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
@ -53,8 +16,6 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#include "FaultTolerantWrite.h"
EFI_EVENT mFvbRegistration = NULL;
//
// Fault Tolerant Write Protocol API
//
@ -237,7 +198,7 @@ FtwWriteRecord (
//
// Spare Complete but Destination not complete,
// Recover the targt block with the spare block.
// Recover the target block with the spare block.
//
Header = FtwDevice->FtwLastWriteHeader;
Record = FtwDevice->FtwLastWriteRecord;
@ -864,390 +825,3 @@ FtwGetLastWrite (
return Status;
}
/**
Firmware Volume Block Protocol notification event handler.
Initialization for Fault Tolerant Write is done in this handler.
@param[in] Event Event whose notification function is being invoked.
@param[in] Context Pointer to the notification function's context.
**/
VOID
EFIAPI
FvbNotificationEvent (
IN EFI_EVENT Event,
IN VOID *Context
)
{
EFI_STATUS Status;
EFI_HANDLE *HandleBuffer;
UINTN HandleCount;
UINTN Index;
EFI_PHYSICAL_ADDRESS FvbBaseAddress;
EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
EFI_FVB_ATTRIBUTES_2 Attributes;
EFI_FTW_DEVICE *FtwDevice;
EFI_FV_BLOCK_MAP_ENTRY *FvbMapEntry;
UINT32 LbaIndex;
UINTN Length;
EFI_FAULT_TOLERANT_WRITE_HEADER *FtwHeader;
UINTN Offset;
EFI_HANDLE FvbHandle;
FtwDevice = (EFI_FTW_DEVICE *)Context;
FvbHandle = NULL;
Fvb = NULL;
FtwDevice->WorkSpaceAddress = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageFtwWorkingBase64);
if (FtwDevice->WorkSpaceAddress == 0) {
FtwDevice->WorkSpaceAddress = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageFtwWorkingBase);
}
FtwDevice->SpareAreaAddress = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageFtwSpareBase64);
if (FtwDevice->SpareAreaAddress == 0) {
FtwDevice->SpareAreaAddress = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageFtwSpareBase);
}
//
// Locate all handles of Fvb protocol
//
Status = gBS->LocateHandleBuffer (
ByProtocol,
&gEfiFirmwareVolumeBlockProtocolGuid,
NULL,
&HandleCount,
&HandleBuffer
);
if (EFI_ERROR (Status)) {
return;
}
//
// Get the FVB to access variable store
//
for (Index = 0; Index < HandleCount; Index += 1) {
Status = gBS->HandleProtocol (
HandleBuffer[Index],
&gEfiFirmwareVolumeBlockProtocolGuid,
(VOID **) &Fvb
);
if (EFI_ERROR (Status)) {
Status = EFI_NOT_FOUND;
break;
}
//
// Ensure this FVB protocol supported Write operation.
//
Status = Fvb->GetAttributes (Fvb, &Attributes);
if (EFI_ERROR (Status) || ((Attributes & EFI_FVB2_WRITE_STATUS) == 0)) {
continue;
}
//
// Compare the address and select the right one
//
Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress);
if (EFI_ERROR (Status)) {
continue;
}
FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvbBaseAddress);
if ((FtwDevice->FtwFvBlock == NULL) && (FtwDevice->WorkSpaceAddress >= FvbBaseAddress) &&
((FtwDevice->WorkSpaceAddress + FtwDevice->WorkSpaceLength) <= (FvbBaseAddress + FwVolHeader->FvLength))
) {
FtwDevice->FtwFvBlock = Fvb;
//
// To get the LBA of work space
//
if ((FwVolHeader->FvLength) > (FwVolHeader->HeaderLength)) {
//
// Now, one FV has one type of BlockLength
//
FvbMapEntry = &FwVolHeader->BlockMap[0];
for (LbaIndex = 1; LbaIndex <= FvbMapEntry->NumBlocks; LbaIndex += 1) {
if ((FtwDevice->WorkSpaceAddress >= (FvbBaseAddress + FvbMapEntry->Length * (LbaIndex - 1)))
&& (FtwDevice->WorkSpaceAddress < (FvbBaseAddress + FvbMapEntry->Length * LbaIndex))) {
FtwDevice->FtwWorkSpaceLba = LbaIndex - 1;
//
// Get the Work space size and Base(Offset)
//
FtwDevice->FtwWorkSpaceSize = FtwDevice->WorkSpaceLength;
FtwDevice->FtwWorkSpaceBase = (UINTN) (FtwDevice->WorkSpaceAddress - (FvbBaseAddress + FvbMapEntry->Length * (LbaIndex - 1)));
break;
}
}
}
}
if ((FtwDevice->FtwBackupFvb == NULL) && (FtwDevice->SpareAreaAddress >= FvbBaseAddress) &&
((FtwDevice->SpareAreaAddress + FtwDevice->SpareAreaLength) <= (FvbBaseAddress + FwVolHeader->FvLength))
) {
FtwDevice->FtwBackupFvb = Fvb;
//
// To get the LBA of spare
//
if ((FwVolHeader->FvLength) > (FwVolHeader->HeaderLength)) {
//
// Now, one FV has one type of BlockLength
//
FvbMapEntry = &FwVolHeader->BlockMap[0];
for (LbaIndex = 1; LbaIndex <= FvbMapEntry->NumBlocks; LbaIndex += 1) {
if ((FtwDevice->SpareAreaAddress >= (FvbBaseAddress + FvbMapEntry->Length * (LbaIndex - 1)))
&& (FtwDevice->SpareAreaAddress < (FvbBaseAddress + FvbMapEntry->Length * LbaIndex))) {
//
// Get the NumberOfSpareBlock and BlockSize
//
FtwDevice->FtwSpareLba = LbaIndex - 1;
FtwDevice->BlockSize = FvbMapEntry->Length;
FtwDevice->NumberOfSpareBlock = FtwDevice->SpareAreaLength / FtwDevice->BlockSize;
//
// Check the range of spare area to make sure that it's in FV range
//
if ((FtwDevice->FtwSpareLba + FtwDevice->NumberOfSpareBlock) > FvbMapEntry->NumBlocks) {
DEBUG ((EFI_D_ERROR, "Ftw: Spare area is out of FV range\n"));
ASSERT (FALSE);
return;
}
break;
}
}
}
}
}
if ((FtwDevice->FtwBackupFvb == NULL) || (FtwDevice->FtwFvBlock == NULL) ||
(FtwDevice->FtwWorkSpaceLba == (EFI_LBA) (-1)) || (FtwDevice->FtwSpareLba == (EFI_LBA) (-1))) {
return;
}
DEBUG ((EFI_D_INFO, "Ftw: Working and spare FVB is ready\n"));
//
// Calculate the start LBA of working block. Working block is an area which
// contains working space in its last block and has the same size as spare
// block, unless there are not enough blocks before the block that contains
// working space.
//
FtwDevice->FtwWorkBlockLba = FtwDevice->FtwWorkSpaceLba - FtwDevice->NumberOfSpareBlock + 1;
ASSERT ((INT64) (FtwDevice->FtwWorkBlockLba) >= 0);
//
// Initialize other parameters, and set WorkSpace as FTW_ERASED_BYTE.
//
FtwDevice->FtwWorkSpace = (UINT8 *) (FtwDevice + 1);
FtwDevice->FtwWorkSpaceHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *) FtwDevice->FtwWorkSpace;
FtwDevice->FtwLastWriteHeader = NULL;
FtwDevice->FtwLastWriteRecord = NULL;
//
// Refresh the working space data from working block
//
Status = WorkSpaceRefresh (FtwDevice);
ASSERT_EFI_ERROR (Status);
//
// If the working block workspace is not valid, try the spare block
//
if (!IsValidWorkSpace (FtwDevice->FtwWorkSpaceHeader)) {
//
// Read from spare block
//
Length = FtwDevice->FtwWorkSpaceSize;
Status = FtwDevice->FtwBackupFvb->Read (
FtwDevice->FtwBackupFvb,
FtwDevice->FtwSpareLba,
FtwDevice->FtwWorkSpaceBase,
&Length,
FtwDevice->FtwWorkSpace
);
ASSERT_EFI_ERROR (Status);
//
// If spare block is valid, then replace working block content.
//
if (IsValidWorkSpace (FtwDevice->FtwWorkSpaceHeader)) {
Status = FlushSpareBlockToWorkingBlock (FtwDevice);
DEBUG ((EFI_D_ERROR, "Ftw: Restart working block update in Init() - %r\n", Status));
FtwAbort (&FtwDevice->FtwInstance);
//
// Refresh work space.
//
Status = WorkSpaceRefresh (FtwDevice);
ASSERT_EFI_ERROR (Status);
} else {
DEBUG ((EFI_D_ERROR, "Ftw: Both are invalid, init workspace\n"));
//
// If both are invalid, then initialize work space.
//
SetMem (
FtwDevice->FtwWorkSpace,
FtwDevice->FtwWorkSpaceSize,
FTW_ERASED_BYTE
);
InitWorkSpaceHeader (FtwDevice->FtwWorkSpaceHeader);
//
// Initialize the work space
//
Status = FtwReclaimWorkSpace (FtwDevice, FALSE);
ASSERT_EFI_ERROR (Status);
}
}
//
// If the FtwDevice->FtwLastWriteRecord is 1st record of write header &&
// (! SpareComplete) THEN call Abort().
//
if ((FtwDevice->FtwLastWriteHeader->HeaderAllocated == FTW_VALID_STATE) &&
(FtwDevice->FtwLastWriteRecord->SpareComplete != FTW_VALID_STATE) &&
IsFirstRecordOfWrites (FtwDevice->FtwLastWriteHeader, FtwDevice->FtwLastWriteRecord)
) {
DEBUG ((EFI_D_ERROR, "Ftw: Init.. find first record not SpareCompleted, abort()\n"));
FtwAbort (&FtwDevice->FtwInstance);
}
//
// If Header is incompleted and the last record has completed, then
// call Abort() to set the Header->Complete FLAG.
//
if ((FtwDevice->FtwLastWriteHeader->Complete != FTW_VALID_STATE) &&
(FtwDevice->FtwLastWriteRecord->DestinationComplete == FTW_VALID_STATE) &&
IsLastRecordOfWrites (FtwDevice->FtwLastWriteHeader, FtwDevice->FtwLastWriteRecord)
) {
DEBUG ((EFI_D_ERROR, "Ftw: Init.. find last record completed but header not, abort()\n"));
FtwAbort (&FtwDevice->FtwInstance);
}
//
// To check the workspace buffer following last Write header/records is EMPTY or not.
// If it's not EMPTY, FTW also need to call reclaim().
//
FtwHeader = FtwDevice->FtwLastWriteHeader;
Offset = (UINT8 *) FtwHeader - FtwDevice->FtwWorkSpace;
if (FtwDevice->FtwWorkSpace[Offset] != FTW_ERASED_BYTE) {
Offset += WRITE_TOTAL_SIZE (FtwHeader->NumberOfWrites, FtwHeader->PrivateDataSize);
}
if (!IsErasedFlashBuffer (FtwDevice->FtwWorkSpace + Offset, FtwDevice->FtwWorkSpaceSize - Offset)) {
Status = FtwReclaimWorkSpace (FtwDevice, TRUE);
ASSERT_EFI_ERROR (Status);
}
//
// Restart if it's boot block
//
if ((FtwDevice->FtwLastWriteHeader->Complete != FTW_VALID_STATE) &&
(FtwDevice->FtwLastWriteRecord->SpareComplete == FTW_VALID_STATE)
) {
if (FtwDevice->FtwLastWriteRecord->BootBlockUpdate == FTW_VALID_STATE) {
Status = FlushSpareBlockToBootBlock (FtwDevice);
DEBUG ((EFI_D_ERROR, "Ftw: Restart boot block update - %r\n", Status));
ASSERT_EFI_ERROR (Status);
FtwAbort (&FtwDevice->FtwInstance);
} else {
//
// if (SpareCompleted) THEN Restart to fault tolerant write.
//
FvbHandle = GetFvbByAddress (FtwDevice->FtwLastWriteRecord->FvBaseAddress, &Fvb);
if (FvbHandle != NULL) {
Status = FtwRestart (&FtwDevice->FtwInstance, FvbHandle);
DEBUG ((EFI_D_ERROR, "FtwLite: Restart last write - %r\n", Status));
ASSERT_EFI_ERROR (Status);
}
FtwAbort (&FtwDevice->FtwInstance);
}
}
//
// Hook the protocol API
//
FtwDevice->FtwInstance.GetMaxBlockSize = FtwGetMaxBlockSize;
FtwDevice->FtwInstance.Allocate = FtwAllocate;
FtwDevice->FtwInstance.Write = FtwWrite;
FtwDevice->FtwInstance.Restart = FtwRestart;
FtwDevice->FtwInstance.Abort = FtwAbort;
FtwDevice->FtwInstance.GetLastWrite = FtwGetLastWrite;
//
// Install protocol interface
//
Status = gBS->InstallProtocolInterface (
&FtwDevice->Handle,
&gEfiFaultTolerantWriteProtocolGuid,
EFI_NATIVE_INTERFACE,
&FtwDevice->FtwInstance
);
ASSERT_EFI_ERROR (Status);
//
// Close the notify event to avoid install FaultTolerantWriteProtocol again.
//
Status = gBS->CloseEvent (Event);
ASSERT_EFI_ERROR (Status);
return;
}
/**
This function is the entry point of the Fault Tolerant Write driver.
@param ImageHandle A handle for the image that is initializing this driver
@param SystemTable A pointer to the EFI system table
@return EFI_SUCCESS FTW has finished the initialization
@retval EFI_NOT_FOUND Locate FVB protocol error
@retval EFI_OUT_OF_RESOURCES Allocate memory error
@retval EFI_VOLUME_CORRUPTED Firmware volume is error
@retval EFI_ABORTED FTW initialization error
**/
EFI_STATUS
EFIAPI
InitializeFaultTolerantWrite (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_FTW_DEVICE *FtwDevice;
//
// Allocate Private data of this driver,
// INCLUDING THE FtwWorkSpace[FTW_WORK_SPACE_SIZE].
//
FtwDevice = NULL;
FtwDevice = AllocateZeroPool (sizeof (EFI_FTW_DEVICE) + PcdGet32 (PcdFlashNvStorageFtwWorkingSize));
if (FtwDevice == NULL) {
return EFI_OUT_OF_RESOURCES;
}
ZeroMem (FtwDevice, sizeof (EFI_FTW_DEVICE));
FtwDevice->Signature = FTW_DEVICE_SIGNATURE;
//
// Initialize other parameters, and set WorkSpace as FTW_ERASED_BYTE.
//
FtwDevice->WorkSpaceLength = (UINTN) PcdGet32 (PcdFlashNvStorageFtwWorkingSize);
FtwDevice->SpareAreaLength = (UINTN) PcdGet32 (PcdFlashNvStorageFtwSpareSize);
if ((FtwDevice->WorkSpaceLength == 0) || (FtwDevice->SpareAreaLength == 0)) {
DEBUG ((EFI_D_ERROR, "Ftw: Workspace or Spare block does not exist!\n"));
FreePool (FtwDevice);
return EFI_OUT_OF_RESOURCES;
}
FtwDevice->FtwFvBlock = NULL;
FtwDevice->FtwBackupFvb = NULL;
FtwDevice->FtwWorkSpaceLba = (EFI_LBA) (-1);
FtwDevice->FtwSpareLba = (EFI_LBA) (-1);
//
// Register FvbNotificationEvent () notify function.
//
EfiCreateProtocolNotifyEvent (
&gEfiFirmwareVolumeBlockProtocolGuid,
TPL_CALLBACK,
FvbNotificationEvent,
(VOID *)FtwDevice,
&mFvbRegistration
);
return EFI_SUCCESS;
}

View File

@ -3,7 +3,7 @@
The internal header file includes the common header files, defines
internal structure and functions used by FtwLite module.
Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR>
Copyright (c) 2006 - 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
@ -670,4 +670,71 @@ GetFvbByAddress (
OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvBlock
);
/**
Retrive the proper Swap Address Range protocol interface.
@param[out] SarProtocol The interface of SAR protocol
@retval EFI_SUCCESS The SAR protocol instance was found and returned in SarProtocol.
@retval EFI_NOT_FOUND The SAR protocol instance was not found.
@retval EFI_INVALID_PARAMETER SarProtocol is NULL.
**/
EFI_STATUS
FtwGetSarProtocol (
OUT VOID **SarProtocol
);
/**
Function returns an array of handles that support the FVB protocol
in a buffer allocated from pool.
@param[out] NumberHandles The number of handles returned in Buffer.
@param[out] Buffer A pointer to the buffer to return the requested
array of handles that support FVB protocol.
@retval EFI_SUCCESS The array of handles was returned in Buffer, and the number of
handles in Buffer was returned in NumberHandles.
@retval EFI_NOT_FOUND No FVB handle was found.
@retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the matching results.
@retval EFI_INVALID_PARAMETER NumberHandles is NULL or Buffer is NULL.
**/
EFI_STATUS
GetFvbCountAndBuffer (
OUT UINTN *NumberHandles,
OUT EFI_HANDLE **Buffer
);
/**
Allocate private data for FTW driver and initialize it.
@param[out] FtwData Pointer to the FTW device structure
@retval EFI_SUCCESS Initialize the FTW device successfully.
@retval EFI_OUT_OF_RESOURCES Allocate memory error
@retval EFI_INVALID_PARAMETER Workspace or Spare block does not exist
**/
EFI_STATUS
InitFtwDevice (
OUT EFI_FTW_DEVICE **FtwData
);
/**
Initialization for Fault Tolerant Write is done in this handler.
@param[in,out] FtwData Pointer to the FTW device structure
@retval EFI_SUCCESS Initialize the FTW protocol successfully.
@retval EFI_NOT_FOUND No proper FVB protocol was found.
**/
EFI_STATUS
InitFtwProtocol (
IN OUT EFI_FTW_DEVICE *FtwDevice
);
#endif

View File

@ -0,0 +1,250 @@
/** @file
This is a simple fault tolerant write driver.
This boot service protocol only provides fault tolerant write capability for
block devices. The protocol has internal non-volatile intermediate storage
of the data and private information. It should be able to recover
automatically from a critical fault, such as power failure.
The implementation uses an FTW (Fault Tolerant Write) Work Space.
This work space is a memory copy of the work space on the Working Block,
the size of the work space is the FTW_WORK_SPACE_SIZE bytes.
The work space stores each write record as EFI_FTW_RECORD structure.
The spare block stores the write buffer before write to the target block.
The write record has three states to specify the different phase of write operation.
1) WRITE_ALLOCATED is that the record is allocated in write space.
The information of write operation is stored in write record structure.
2) SPARE_COMPLETED is that the data from write buffer is writed into the spare block as the backup.
3) WRITE_COMPLETED is that the data is copied from the spare block to the target block.
This driver operates the data as the whole size of spare block.
It first read the SpareAreaLength data from the target block into the spare memory buffer.
Then copy the write buffer data into the spare memory buffer.
Then write the spare memory buffer into the spare block.
Final copy the data from the spare block to the target block.
To make this drive work well, the following conditions must be satisfied:
1. The write NumBytes data must be fit within Spare area.
Offset + NumBytes <= SpareAreaLength
2. The whole flash range has the same block size.
3. Working block is an area which contains working space in its last block and has the same size as spare block.
4. Working Block area must be in the single one Firmware Volume Block range which FVB protocol is produced on.
5. Spare area must be in the single one Firmware Volume Block range which FVB protocol is produced on.
6. Any write data area (SpareAreaLength Area) which the data will be written into must be
in the single one Firmware Volume Block range which FVB protocol is produced on.
7. If write data area (such as Variable range) is enlarged, the spare area range must be enlarged.
The spare area must be enough large to store the write data before write them into the target range.
If one of them is not satisfied, FtwWrite may fail.
Usually, Spare area only takes one block. That's SpareAreaLength = BlockSize, NumberOfSpareBlock = 1.
Copyright (c) 2006 - 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.
**/
#include "FaultTolerantWrite.h"
EFI_EVENT mFvbRegistration = NULL;
/**
Retrive the FVB protocol interface by HANDLE.
@param[in] FvBlockHandle The handle of FVB protocol that provides services for
reading, writing, and erasing the target block.
@param[out] FvBlock The interface of FVB protocol
@retval EFI_SUCCESS The interface information for the specified protocol was returned.
@retval EFI_UNSUPPORTED The device does not support the FVB protocol.
@retval EFI_INVALID_PARAMETER FvBlockHandle is not a valid EFI_HANDLE or FvBlock is NULL.
**/
EFI_STATUS
FtwGetFvbByHandle (
IN EFI_HANDLE FvBlockHandle,
OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvBlock
)
{
//
// To get the FVB protocol interface on the handle
//
return gBS->HandleProtocol (
FvBlockHandle,
&gEfiFirmwareVolumeBlockProtocolGuid,
(VOID **) FvBlock
);
}
/**
Retrive the Swap Address Range protocol interface.
@param[out] SarProtocol The interface of SAR protocol
@retval EFI_SUCCESS The SAR protocol instance was found and returned in SarProtocol.
@retval EFI_NOT_FOUND The SAR protocol instance was not found.
@retval EFI_INVALID_PARAMETER SarProtocol is NULL.
**/
EFI_STATUS
FtwGetSarProtocol (
OUT VOID **SarProtocol
)
{
EFI_STATUS Status;
//
// Locate Swap Address Range protocol
//
Status = gBS->LocateProtocol (
&gEfiSwapAddressRangeProtocolGuid,
NULL,
SarProtocol
);
return Status;
}
/**
Function returns an array of handles that support the FVB protocol
in a buffer allocated from pool.
@param[out] NumberHandles The number of handles returned in Buffer.
@param[out] Buffer A pointer to the buffer to return the requested
array of handles that support FVB protocol.
@retval EFI_SUCCESS The array of handles was returned in Buffer, and the number of
handles in Buffer was returned in NumberHandles.
@retval EFI_NOT_FOUND No FVB handle was found.
@retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the matching results.
@retval EFI_INVALID_PARAMETER NumberHandles is NULL or Buffer is NULL.
**/
EFI_STATUS
GetFvbCountAndBuffer (
OUT UINTN *NumberHandles,
OUT EFI_HANDLE **Buffer
)
{
EFI_STATUS Status;
//
// Locate all handles of Fvb protocol
//
Status = gBS->LocateHandleBuffer (
ByProtocol,
&gEfiFirmwareVolumeBlockProtocolGuid,
NULL,
NumberHandles,
Buffer
);
return Status;
}
/**
Firmware Volume Block Protocol notification event handler.
@param[in] Event Event whose notification function is being invoked.
@param[in] Context Pointer to the notification function's context.
**/
VOID
EFIAPI
FvbNotificationEvent (
IN EFI_EVENT Event,
IN VOID *Context
)
{
EFI_STATUS Status;
EFI_FAULT_TOLERANT_WRITE_PROTOCOL *FtwProtocol;
EFI_FTW_DEVICE *FtwDevice;
//
// Just return to avoid install SMM FaultTolerantWriteProtocol again
// if Fault Tolerant Write protocol had been installed.
//
Status = gBS->LocateProtocol (
&gEfiFaultTolerantWriteProtocolGuid,
NULL,
(VOID **) &FtwProtocol
);
if (!EFI_ERROR (Status)) {
return ;
}
//
// Found proper FVB protocol and initialize FtwDevice for protocol installation
//
FtwDevice = (EFI_FTW_DEVICE *)Context;
Status = InitFtwProtocol (FtwDevice);
if (EFI_ERROR(Status)) {
return ;
}
//
// Install protocol interface
//
Status = gBS->InstallProtocolInterface (
&FtwDevice->Handle,
&gEfiFaultTolerantWriteProtocolGuid,
EFI_NATIVE_INTERFACE,
&FtwDevice->FtwInstance
);
ASSERT_EFI_ERROR (Status);
Status = gBS->CloseEvent (Event);
ASSERT_EFI_ERROR (Status);
return;
}
/**
This function is the entry point of the Fault Tolerant Write driver.
@param[in] ImageHandle A handle for the image that is initializing this driver
@param[in] SystemTable A pointer to the EFI system table
@retval EFI_SUCCESS The initialization finished successfully.
@retval EFI_OUT_OF_RESOURCES Allocate memory error
@retval EFI_INVALID_PARAMETER Workspace or Spare block does not exist
**/
EFI_STATUS
EFIAPI
FaultTolerantWriteInitialize (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
EFI_FTW_DEVICE *FtwDevice;
//
// Allocate private data structure for FTW protocol and do some initialization
//
Status = InitFtwDevice (&FtwDevice);
if (EFI_ERROR(Status)) {
return Status;
}
//
// Register FvbNotificationEvent () notify function.
//
EfiCreateProtocolNotifyEvent (
&gEfiFirmwareVolumeBlockProtocolGuid,
TPL_CALLBACK,
FvbNotificationEvent,
(VOID *)FtwDevice,
&mFvbRegistration
);
return EFI_SUCCESS;
}

View File

@ -20,7 +20,7 @@
FILE_GUID = FE5CEA76-4F72-49e8-986F-2CD899DFFE5D
MODULE_TYPE = DXE_DRIVER
VERSION_STRING = 1.0
ENTRY_POINT = InitializeFaultTolerantWrite
ENTRY_POINT = FaultTolerantWriteInitialize
#
# The following information is for reference only and not required by the build tools.
@ -32,6 +32,7 @@
FtwMisc.c
UpdateWorkingBlock.c
FaultTolerantWrite.c
FaultTolerantWriteDxe.c
FaultTolerantWrite.h
[Packages]

View File

@ -0,0 +1,281 @@
/** @file
This is a simple fault tolerant write driver that is intended to use in the SMM environment.
This boot service protocol only provides fault tolerant write capability for
block devices. The protocol has internal non-volatile intermediate storage
of the data and private information. It should be able to recover
automatically from a critical fault, such as power failure.
The implementation uses an FTW (Fault Tolerant Write) Work Space.
This work space is a memory copy of the work space on the Working Block,
the size of the work space is the FTW_WORK_SPACE_SIZE bytes.
The work space stores each write record as EFI_FTW_RECORD structure.
The spare block stores the write buffer before write to the target block.
The write record has three states to specify the different phase of write operation.
1) WRITE_ALLOCATED is that the record is allocated in write space.
The information of write operation is stored in write record structure.
2) SPARE_COMPLETED is that the data from write buffer is writed into the spare block as the backup.
3) WRITE_COMPLETED is that the data is copied from the spare block to the target block.
This driver operates the data as the whole size of spare block.
It first read the SpareAreaLength data from the target block into the spare memory buffer.
Then copy the write buffer data into the spare memory buffer.
Then write the spare memory buffer into the spare block.
Final copy the data from the spare block to the target block.
To make this drive work well, the following conditions must be satisfied:
1. The write NumBytes data must be fit within Spare area.
Offset + NumBytes <= SpareAreaLength
2. The whole flash range has the same block size.
3. Working block is an area which contains working space in its last block and has the same size as spare block.
4. Working Block area must be in the single one Firmware Volume Block range which FVB protocol is produced on.
5. Spare area must be in the single one Firmware Volume Block range which FVB protocol is produced on.
6. Any write data area (SpareAreaLength Area) which the data will be written into must be
in the single one Firmware Volume Block range which FVB protocol is produced on.
7. If write data area (such as Variable range) is enlarged, the spare area range must be enlarged.
The spare area must be enough large to store the write data before write them into the target range.
If one of them is not satisfied, FtwWrite may fail.
Usually, Spare area only takes one block. That's SpareAreaLength = BlockSize, NumberOfSpareBlock = 1.
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.
**/
#include <Library/SmmServicesTableLib.h>
#include "FaultTolerantWrite.h"
#include <Protocol/SmmFirmwareVolumeBlock.h>
#include <Protocol/SmmSwapAddressRange.h>
#include <Protocol/SmmFaultTolerantWrite.h>
EFI_EVENT mFvbRegistration = NULL;
EFI_FTW_DEVICE *gFtwDevice = NULL;
/**
Retrive the SMM FVB protocol interface by HANDLE.
@param[in] FvBlockHandle The handle of SMM FVB protocol that provides services for
reading, writing, and erasing the target block.
@param[out] FvBlock The interface of SMM FVB protocol
@retval EFI_SUCCESS The interface information for the specified protocol was returned.
@retval EFI_UNSUPPORTED The device does not support the SMM FVB protocol.
@retval EFI_INVALID_PARAMETER FvBlockHandle is not a valid EFI_HANDLE or FvBlock is NULL.
**/
EFI_STATUS
FtwGetFvbByHandle (
IN EFI_HANDLE FvBlockHandle,
OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvBlock
)
{
//
// To get the SMM FVB protocol interface on the handle
//
return gSmst->SmmHandleProtocol (
FvBlockHandle,
&gEfiSmmFirmwareVolumeBlockProtocolGuid,
(VOID **) FvBlock
);
}
/**
Retrive the SMM Swap Address Range protocol interface.
@param[out] SarProtocol The interface of SMM SAR protocol
@retval EFI_SUCCESS The SMM SAR protocol instance was found and returned in SarProtocol.
@retval EFI_NOT_FOUND The SMM SAR protocol instance was not found.
@retval EFI_INVALID_PARAMETER SarProtocol is NULL.
**/
EFI_STATUS
FtwGetSarProtocol (
OUT VOID **SarProtocol
)
{
EFI_STATUS Status;
//
// Locate Smm Swap Address Range protocol
//
Status = gSmst->SmmLocateProtocol (
&gEfiSmmSwapAddressRangeProtocolGuid,
NULL,
SarProtocol
);
return Status;
}
/**
Function returns an array of handles that support the SMM FVB protocol
in a buffer allocated from pool.
@param[out] NumberHandles The number of handles returned in Buffer.
@param[out] Buffer A pointer to the buffer to return the requested
array of handles that support SMM FVB protocol.
@retval EFI_SUCCESS The array of handles was returned in Buffer, and the number of
handles in Buffer was returned in NumberHandles.
@retval EFI_NOT_FOUND No SMM FVB handle was found.
@retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the matching results.
@retval EFI_INVALID_PARAMETER NumberHandles is NULL or Buffer is NULL.
**/
EFI_STATUS
GetFvbCountAndBuffer (
OUT UINTN *NumberHandles,
OUT EFI_HANDLE **Buffer
)
{
EFI_STATUS Status;
UINTN BufferSize;
if ((NumberHandles == NULL) || (Buffer == NULL)) {
return EFI_INVALID_PARAMETER;
}
BufferSize = 0;
*NumberHandles = 0;
*Buffer = NULL;
Status = gSmst->SmmLocateHandle (
ByProtocol,
&gEfiSmmFirmwareVolumeBlockProtocolGuid,
NULL,
&BufferSize,
*Buffer
);
if (EFI_ERROR(Status) && Status != EFI_BUFFER_TOO_SMALL) {
return EFI_NOT_FOUND;
}
*Buffer = AllocatePool (BufferSize);
if (*Buffer == NULL) {
return EFI_OUT_OF_RESOURCES;
}
Status = gSmst->SmmLocateHandle (
ByProtocol,
&gEfiSmmFirmwareVolumeBlockProtocolGuid,
NULL,
&BufferSize,
*Buffer
);
*NumberHandles = BufferSize / sizeof(EFI_HANDLE);
if (EFI_ERROR(Status)) {
*NumberHandles = 0;
}
return Status;
}
/**
SMM Firmware Volume Block Protocol notification event handler.
@param[in] Protocol Points to the protocol's unique identifier
@param[in] Interface Points to the interface instance
@param[in] Handle The handle on which the interface was installed
@retval EFI_SUCCESS SmmEventCallback runs successfully
**/
EFI_STATUS
EFIAPI
FvbNotificationEvent (
IN CONST EFI_GUID *Protocol,
IN VOID *Interface,
IN EFI_HANDLE Handle
)
{
EFI_STATUS Status;
EFI_SMM_FAULT_TOLERANT_WRITE_PROTOCOL *FtwProtocol;
//
// Just return to avoid install SMM FaultTolerantWriteProtocol again
// if SMM Fault Tolerant Write protocol had been installed.
//
Status = gSmst->SmmLocateProtocol (
&gEfiSmmFaultTolerantWriteProtocolGuid,
NULL,
(VOID **) &FtwProtocol
);
if (!EFI_ERROR (Status)) {
return EFI_SUCCESS;
}
//
// Found proper FVB protocol and initialize FtwDevice for protocol installation
//
Status = InitFtwProtocol (gFtwDevice);
if (EFI_ERROR(Status)) {
return Status;
}
//
// Install protocol interface
//
Status = gSmst->SmmInstallProtocolInterface (
&gFtwDevice->Handle,
&gEfiSmmFaultTolerantWriteProtocolGuid,
EFI_NATIVE_INTERFACE,
&gFtwDevice->FtwInstance
);
ASSERT_EFI_ERROR (Status);
return EFI_SUCCESS;
}
/**
This function is the entry point of the Fault Tolerant Write driver.
@param[in] ImageHandle A handle for the image that is initializing this driver
@param[in] SystemTable A pointer to the EFI system table
@retval EFI_SUCCESS The initialization finished successfully.
@retval EFI_OUT_OF_RESOURCES Allocate memory error
@retval EFI_INVALID_PARAMETER Workspace or Spare block does not exist
**/
EFI_STATUS
EFIAPI
SmmFaultTolerantWriteInitialize (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
//
// Allocate private data structure for SMM FTW protocol and do some initialization
//
Status = InitFtwDevice (&gFtwDevice);
if (EFI_ERROR(Status)) {
return Status;
}
//
// Register FvbNotificationEvent () notify function.
//
Status = gSmst->SmmRegisterProtocolNotify (
&gEfiSmmFirmwareVolumeBlockProtocolGuid,
FvbNotificationEvent,
&mFvbRegistration
);
ASSERT_EFI_ERROR (Status);
FvbNotificationEvent (NULL, NULL, NULL);
return EFI_SUCCESS;
}

View File

@ -0,0 +1,73 @@
## @file
# This driver installs SMM Fault Tolerant Write (FTW) protocol, which provides fault
# tolerant write capability in SMM environment for block devices. Its implementation
# depends on the full functionality SMM FVB protocol that support read, write/erase
# flash access.
#
# 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 = SmmFaultTolerantWriteDxe
FILE_GUID = 470CB248-E8AC-473c-BB4F-81069A1FE6FD
MODULE_TYPE = DXE_SMM_DRIVER
VERSION_STRING = 1.0
PI_SPECIFICATION_VERSION = 0x0001000A
ENTRY_POINT = SmmFaultTolerantWriteInitialize
#
# The following information is for reference only and not required by the build tools.
#
# VALID_ARCHITECTURES = IA32 X64
#
[Sources]
FtwMisc.c
UpdateWorkingBlock.c
FaultTolerantWrite.c
FaultTolerantWriteSmm.c
FaultTolerantWrite.h
[Packages]
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
[LibraryClasses]
SmmServicesTableLib
MemoryAllocationLib
BaseMemoryLib
UefiDriverEntryPoint
DebugLib
UefiLib
[Guids]
gEfiSystemNvDataFvGuid ## CONSUMES ## FV Signature of Working Space Header
[Protocols]
gEfiSmmSwapAddressRangeProtocolGuid | PcdFullFtwServiceEnable ## CONSUMES
gEfiSmmFirmwareVolumeBlockProtocolGuid ## CONSUMES
gEfiSmmFaultTolerantWriteProtocolGuid ## PRODUCES
[FeaturePcd]
gEfiMdeModulePkgTokenSpaceGuid.PcdFullFtwServiceEnable
[Pcd]
gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase
gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase64
gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize
gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase
gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase64
gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize
[Depex]
gEfiSmmFirmwareVolumeBlockProtocolGuid

View File

@ -2,7 +2,7 @@
Internal generic functions to operate flash block.
Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR>
Copyright (c) 2006 - 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
@ -104,34 +104,6 @@ FtwEraseSpareBlock (
);
}
/**
Retrive the proper FVB protocol interface by HANDLE.
@param FvBlockHandle The handle of FVB protocol that provides services for
reading, writing, and erasing the target block.
@param FvBlock The interface of FVB protocol
@retval EFI_SUCCESS The function completed successfully
@retval EFI_ABORTED The function could not complete successfully
**/
EFI_STATUS
FtwGetFvbByHandle (
IN EFI_HANDLE FvBlockHandle,
OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvBlock
)
{
//
// To get the FVB protocol interface on the handle
//
return gBS->HandleProtocol (
FvBlockHandle,
&gEfiFirmwareVolumeBlockProtocolGuid,
(VOID **) FvBlock
);
}
/**
Is it in working block?
@ -195,13 +167,7 @@ GetFvbByAddress (
//
// Locate all handles of Fvb protocol
//
Status = gBS->LocateHandleBuffer (
ByProtocol,
&gEfiFirmwareVolumeBlockProtocolGuid,
NULL,
&HandleCount,
&HandleBuffer
);
Status = GetFvbCountAndBuffer (&HandleCount, &HandleBuffer);
if (EFI_ERROR (Status)) {
return NULL;
}
@ -209,11 +175,7 @@ GetFvbByAddress (
// Get the FVB to access variable store
//
for (Index = 0; Index < HandleCount; Index += 1) {
Status = gBS->HandleProtocol (
HandleBuffer[Index],
&gEfiFirmwareVolumeBlockProtocolGuid,
(VOID **) &Fvb
);
Status = FtwGetFvbByHandle (HandleBuffer[Index], &Fvb);
if (EFI_ERROR (Status)) {
break;
}
@ -269,7 +231,7 @@ IsBootBlock (
return FALSE;
}
Status = gBS->LocateProtocol (&gEfiSwapAddressRangeProtocolGuid, NULL, (VOID **) &SarProtocol);
Status = FtwGetSarProtocol ((VOID **) &SarProtocol);
if (EFI_ERROR (Status)) {
return FALSE;
}
@ -358,7 +320,7 @@ FlushSpareBlockToBootBlock (
//
// Locate swap address range protocol
//
Status = gBS->LocateProtocol (&gEfiSwapAddressRangeProtocolGuid, NULL, (VOID **) &SarProtocol);
Status = FtwGetSarProtocol ((VOID **) &SarProtocol);
if (EFI_ERROR (Status)) {
return Status;
}
@ -969,3 +931,371 @@ GetPreviousRecordOfWrites (
*FtwRecord = (EFI_FAULT_TOLERANT_WRITE_RECORD *) Ptr;
return EFI_SUCCESS;
}
/**
Allocate private data for FTW driver and initialize it.
@param[out] FtwData Pointer to the FTW device structure
@retval EFI_SUCCESS Initialize the FTW device successfully.
@retval EFI_OUT_OF_RESOURCES Allocate memory error
@retval EFI_INVALID_PARAMETER Workspace or Spare block does not exist
**/
EFI_STATUS
InitFtwDevice (
OUT EFI_FTW_DEVICE **FtwData
)
{
EFI_FTW_DEVICE *FtwDevice;
//
// Allocate private data of this driver,
// Including the FtwWorkSpace[FTW_WORK_SPACE_SIZE].
//
FtwDevice = AllocateZeroPool (sizeof (EFI_FTW_DEVICE) + PcdGet32 (PcdFlashNvStorageFtwWorkingSize));
if (FtwDevice == NULL) {
return EFI_OUT_OF_RESOURCES;
}
//
// Initialize other parameters, and set WorkSpace as FTW_ERASED_BYTE.
//
FtwDevice->WorkSpaceLength = (UINTN) PcdGet32 (PcdFlashNvStorageFtwWorkingSize);
FtwDevice->SpareAreaLength = (UINTN) PcdGet32 (PcdFlashNvStorageFtwSpareSize);
if ((FtwDevice->WorkSpaceLength == 0) || (FtwDevice->SpareAreaLength == 0)) {
DEBUG ((EFI_D_ERROR, "Ftw: Workspace or Spare block does not exist!\n"));
FreePool (FtwDevice);
return EFI_INVALID_PARAMETER;
}
FtwDevice->Signature = FTW_DEVICE_SIGNATURE;
FtwDevice->FtwFvBlock = NULL;
FtwDevice->FtwBackupFvb = NULL;
FtwDevice->FtwWorkSpaceLba = (EFI_LBA) (-1);
FtwDevice->FtwSpareLba = (EFI_LBA) (-1);
FtwDevice->WorkSpaceAddress = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageFtwWorkingBase64);
if (FtwDevice->WorkSpaceAddress == 0) {
FtwDevice->WorkSpaceAddress = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageFtwWorkingBase);
}
FtwDevice->SpareAreaAddress = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageFtwSpareBase64);
if (FtwDevice->SpareAreaAddress == 0) {
FtwDevice->SpareAreaAddress = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageFtwSpareBase);
}
*FtwData = FtwDevice;
return EFI_SUCCESS;
}
/**
Initialization for Fault Tolerant Write is done in this handler.
@param[in,out] FtwData Pointer to the FTW device structure
@retval EFI_SUCCESS Initialize the FTW device successfully.
@retval EFI_NOT_FOUND No proper FVB protocol was found.
@retval EFI_ABORTED Some data can not be got or be invalid.
**/
EFI_STATUS
FindFvbForFtw (
IN OUT EFI_FTW_DEVICE *FtwDevice
)
{
EFI_STATUS Status;
EFI_HANDLE *HandleBuffer;
UINTN HandleCount;
UINTN Index;
EFI_PHYSICAL_ADDRESS FvbBaseAddress;
EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
EFI_FVB_ATTRIBUTES_2 Attributes;
EFI_FV_BLOCK_MAP_ENTRY *FvbMapEntry;
UINT32 LbaIndex;
//
// Get all FVB handle.
//
Status = GetFvbCountAndBuffer (&HandleCount, &HandleBuffer);
if (EFI_ERROR (Status)) {
return EFI_NOT_FOUND;
}
//
// Get the FVB to access variable store
//
Fvb = NULL;
for (Index = 0; Index < HandleCount; Index += 1) {
Status = FtwGetFvbByHandle (HandleBuffer[Index], &Fvb);
if (EFI_ERROR (Status)) {
Status = EFI_NOT_FOUND;
break;
}
//
// Ensure this FVB protocol support Write operation.
//
Status = Fvb->GetAttributes (Fvb, &Attributes);
if (EFI_ERROR (Status) || ((Attributes & EFI_FVB2_WRITE_STATUS) == 0)) {
continue;
}
//
// Compare the address and select the right one
//
Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress);
if (EFI_ERROR (Status)) {
continue;
}
FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvbBaseAddress);
if ((FtwDevice->FtwFvBlock == NULL) && (FtwDevice->WorkSpaceAddress >= FvbBaseAddress) &&
((FtwDevice->WorkSpaceAddress + FtwDevice->WorkSpaceLength) <= (FvbBaseAddress + FwVolHeader->FvLength))
) {
FtwDevice->FtwFvBlock = Fvb;
//
// To get the LBA of work space
//
if ((FwVolHeader->FvLength) > (FwVolHeader->HeaderLength)) {
//
// Now, one FV has one type of BlockLength
//
FvbMapEntry = &FwVolHeader->BlockMap[0];
for (LbaIndex = 1; LbaIndex <= FvbMapEntry->NumBlocks; LbaIndex += 1) {
if ((FtwDevice->WorkSpaceAddress >= (FvbBaseAddress + FvbMapEntry->Length * (LbaIndex - 1)))
&& (FtwDevice->WorkSpaceAddress < (FvbBaseAddress + FvbMapEntry->Length * LbaIndex))) {
FtwDevice->FtwWorkSpaceLba = LbaIndex - 1;
//
// Get the Work space size and Base(Offset)
//
FtwDevice->FtwWorkSpaceSize = FtwDevice->WorkSpaceLength;
FtwDevice->FtwWorkSpaceBase = (UINTN) (FtwDevice->WorkSpaceAddress - (FvbBaseAddress + FvbMapEntry->Length * (LbaIndex - 1)));
break;
}
}
}
}
if ((FtwDevice->FtwBackupFvb == NULL) && (FtwDevice->SpareAreaAddress >= FvbBaseAddress) &&
((FtwDevice->SpareAreaAddress + FtwDevice->SpareAreaLength) <= (FvbBaseAddress + FwVolHeader->FvLength))
) {
FtwDevice->FtwBackupFvb = Fvb;
//
// To get the LBA of spare
//
if ((FwVolHeader->FvLength) > (FwVolHeader->HeaderLength)) {
//
// Now, one FV has one type of BlockLength
//
FvbMapEntry = &FwVolHeader->BlockMap[0];
for (LbaIndex = 1; LbaIndex <= FvbMapEntry->NumBlocks; LbaIndex += 1) {
if ((FtwDevice->SpareAreaAddress >= (FvbBaseAddress + FvbMapEntry->Length * (LbaIndex - 1)))
&& (FtwDevice->SpareAreaAddress < (FvbBaseAddress + FvbMapEntry->Length * LbaIndex))) {
//
// Get the NumberOfSpareBlock and BlockSize
//
FtwDevice->FtwSpareLba = LbaIndex - 1;
FtwDevice->BlockSize = FvbMapEntry->Length;
FtwDevice->NumberOfSpareBlock = FtwDevice->SpareAreaLength / FtwDevice->BlockSize;
//
// Check the range of spare area to make sure that it's in FV range
//
if ((FtwDevice->FtwSpareLba + FtwDevice->NumberOfSpareBlock) > FvbMapEntry->NumBlocks) {
DEBUG ((EFI_D_ERROR, "Ftw: Spare area is out of FV range\n"));
FreePool (HandleBuffer);
ASSERT (FALSE);
return EFI_ABORTED;
}
break;
}
}
}
}
}
FreePool (HandleBuffer);
if ((FtwDevice->FtwBackupFvb == NULL) || (FtwDevice->FtwFvBlock == NULL) ||
(FtwDevice->FtwWorkSpaceLba == (EFI_LBA) (-1)) || (FtwDevice->FtwSpareLba == (EFI_LBA) (-1))) {
return EFI_ABORTED;
}
return EFI_SUCCESS;
}
/**
Initialization for Fault Tolerant Write protocol.
@param[in,out] FtwData Pointer to the FTW device structure
@retval EFI_SUCCESS Initialize the FTW protocol successfully.
@retval EFI_NOT_FOUND No proper FVB protocol was found.
**/
EFI_STATUS
InitFtwProtocol (
IN OUT EFI_FTW_DEVICE *FtwDevice
)
{
EFI_STATUS Status;
EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
UINTN Length;
EFI_FAULT_TOLERANT_WRITE_HEADER *FtwHeader;
UINTN Offset;
EFI_HANDLE FvbHandle;
//
// Find the right SMM Fvb protocol instance for FTW.
//
Status = FindFvbForFtw (FtwDevice);
if (EFI_ERROR (Status)) {
return EFI_NOT_FOUND;
}
//
// Calculate the start LBA of working block. Working block is an area which
// contains working space in its last block and has the same size as spare
// block, unless there are not enough blocks before the block that contains
// working space.
//
FtwDevice->FtwWorkBlockLba = FtwDevice->FtwWorkSpaceLba - FtwDevice->NumberOfSpareBlock + 1;
ASSERT ((INT64) (FtwDevice->FtwWorkBlockLba) >= 0);
//
// Initialize other parameters, and set WorkSpace as FTW_ERASED_BYTE.
//
FtwDevice->FtwWorkSpace = (UINT8 *) (FtwDevice + 1);
FtwDevice->FtwWorkSpaceHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *) FtwDevice->FtwWorkSpace;
FtwDevice->FtwLastWriteHeader = NULL;
FtwDevice->FtwLastWriteRecord = NULL;
//
// Refresh the working space data from working block
//
Status = WorkSpaceRefresh (FtwDevice);
ASSERT_EFI_ERROR (Status);
//
// If the working block workspace is not valid, try the spare block
//
if (!IsValidWorkSpace (FtwDevice->FtwWorkSpaceHeader)) {
//
// Read from spare block
//
Length = FtwDevice->FtwWorkSpaceSize;
Status = FtwDevice->FtwBackupFvb->Read (
FtwDevice->FtwBackupFvb,
FtwDevice->FtwSpareLba,
FtwDevice->FtwWorkSpaceBase,
&Length,
FtwDevice->FtwWorkSpace
);
ASSERT_EFI_ERROR (Status);
//
// If spare block is valid, then replace working block content.
//
if (IsValidWorkSpace (FtwDevice->FtwWorkSpaceHeader)) {
Status = FlushSpareBlockToWorkingBlock (FtwDevice);
DEBUG ((EFI_D_ERROR, "Ftw: Restart working block update in InitFtwProtocol() - %r\n", Status));
FtwAbort (&FtwDevice->FtwInstance);
//
// Refresh work space.
//
Status = WorkSpaceRefresh (FtwDevice);
ASSERT_EFI_ERROR (Status);
} else {
DEBUG ((EFI_D_ERROR, "Ftw: Both are invalid, init workspace\n"));
//
// If both are invalid, then initialize work space.
//
SetMem (
FtwDevice->FtwWorkSpace,
FtwDevice->FtwWorkSpaceSize,
FTW_ERASED_BYTE
);
InitWorkSpaceHeader (FtwDevice->FtwWorkSpaceHeader);
//
// Initialize the work space
//
Status = FtwReclaimWorkSpace (FtwDevice, FALSE);
ASSERT_EFI_ERROR (Status);
}
}
//
// If the FtwDevice->FtwLastWriteRecord is 1st record of write header &&
// (! SpareComplete) THEN call Abort().
//
if ((FtwDevice->FtwLastWriteHeader->HeaderAllocated == FTW_VALID_STATE) &&
(FtwDevice->FtwLastWriteRecord->SpareComplete != FTW_VALID_STATE) &&
IsFirstRecordOfWrites (FtwDevice->FtwLastWriteHeader, FtwDevice->FtwLastWriteRecord)
) {
DEBUG ((EFI_D_ERROR, "Ftw: Init.. find first record not SpareCompleted, abort()\n"));
FtwAbort (&FtwDevice->FtwInstance);
}
//
// If Header is incompleted and the last record has completed, then
// call Abort() to set the Header->Complete FLAG.
//
if ((FtwDevice->FtwLastWriteHeader->Complete != FTW_VALID_STATE) &&
(FtwDevice->FtwLastWriteRecord->DestinationComplete == FTW_VALID_STATE) &&
IsLastRecordOfWrites (FtwDevice->FtwLastWriteHeader, FtwDevice->FtwLastWriteRecord)
) {
DEBUG ((EFI_D_ERROR, "Ftw: Init.. find last record completed but header not, abort()\n"));
FtwAbort (&FtwDevice->FtwInstance);
}
//
// To check the workspace buffer following last Write header/records is EMPTY or not.
// If it's not EMPTY, FTW also need to call reclaim().
//
FtwHeader = FtwDevice->FtwLastWriteHeader;
Offset = (UINT8 *) FtwHeader - FtwDevice->FtwWorkSpace;
if (FtwDevice->FtwWorkSpace[Offset] != FTW_ERASED_BYTE) {
Offset += WRITE_TOTAL_SIZE (FtwHeader->NumberOfWrites, FtwHeader->PrivateDataSize);
}
if (!IsErasedFlashBuffer (FtwDevice->FtwWorkSpace + Offset, FtwDevice->FtwWorkSpaceSize - Offset)) {
Status = FtwReclaimWorkSpace (FtwDevice, TRUE);
ASSERT_EFI_ERROR (Status);
}
//
// Restart if it's boot block
//
if ((FtwDevice->FtwLastWriteHeader->Complete != FTW_VALID_STATE) &&
(FtwDevice->FtwLastWriteRecord->SpareComplete == FTW_VALID_STATE)
) {
if (FtwDevice->FtwLastWriteRecord->BootBlockUpdate == FTW_VALID_STATE) {
Status = FlushSpareBlockToBootBlock (FtwDevice);
DEBUG ((EFI_D_ERROR, "Ftw: Restart boot block update - %r\n", Status));
ASSERT_EFI_ERROR (Status);
FtwAbort (&FtwDevice->FtwInstance);
} else {
//
// if (SpareCompleted) THEN Restart to fault tolerant write.
//
FvbHandle = NULL;
FvbHandle = GetFvbByAddress (FtwDevice->FtwLastWriteRecord->FvBaseAddress, &Fvb);
if (FvbHandle != NULL) {
Status = FtwRestart (&FtwDevice->FtwInstance, FvbHandle);
DEBUG ((EFI_D_ERROR, "FtwLite: Restart last write - %r\n", Status));
ASSERT_EFI_ERROR (Status);
}
FtwAbort (&FtwDevice->FtwInstance);
}
}
//
// Hook the protocol API
//
FtwDevice->FtwInstance.GetMaxBlockSize = FtwGetMaxBlockSize;
FtwDevice->FtwInstance.Allocate = FtwAllocate;
FtwDevice->FtwInstance.Write = FtwWrite;
FtwDevice->FtwInstance.Restart = FtwRestart;
FtwDevice->FtwInstance.Abort = FtwAbort;
FtwDevice->FtwInstance.GetLastWrite = FtwGetLastWrite;
return EFI_SUCCESS;
}

View File

@ -3,7 +3,7 @@
Handles non-volatile variable store garbage collection, using FTW
(Fault Tolerant Write) protocol.
Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR>
Copyright (c) 2006 - 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
@ -14,105 +14,23 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include "Variable.h"
/**
Gets firmware volume block handle by given address.
This function gets firmware volume block handle whose
address range contains the parameter Address.
@param Address Address which should be contained
by returned FVB handle
@param FvbHandle Pointer to FVB handle for output
@retval EFI_SUCCESS FVB handle successfully returned
@retval EFI_NOT_FOUND Fail to find FVB handle by address
**/
EFI_STATUS
GetFvbHandleByAddress (
IN EFI_PHYSICAL_ADDRESS Address,
OUT EFI_HANDLE *FvbHandle
)
{
EFI_STATUS Status;
EFI_HANDLE *HandleBuffer;
UINTN HandleCount;
UINTN Index;
EFI_PHYSICAL_ADDRESS FvbBaseAddress;
EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
EFI_FVB_ATTRIBUTES_2 Attributes;
*FvbHandle = NULL;
//
// Locate all handles of Fvb protocol
//
Status = gBS->LocateHandleBuffer (
ByProtocol,
&gEfiFirmwareVolumeBlockProtocolGuid,
NULL,
&HandleCount,
&HandleBuffer
);
if (EFI_ERROR (Status)) {
return EFI_NOT_FOUND;
}
//
// Get the FVB to access variable store
//
for (Index = 0; Index < HandleCount; Index += 1) {
Status = gBS->HandleProtocol (
HandleBuffer[Index],
&gEfiFirmwareVolumeBlockProtocolGuid,
(VOID **) &Fvb
);
if (EFI_ERROR (Status)) {
Status = EFI_NOT_FOUND;
break;
}
Status = Fvb->GetAttributes (Fvb, &Attributes);
if (EFI_ERROR (Status) || ((Attributes & EFI_FVB2_WRITE_STATUS) == 0)) {
continue;
}
//
// Compare the address and select the right one
//
Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress);
if (EFI_ERROR (Status)) {
continue;
}
FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvbBaseAddress);
if ((Address >= FvbBaseAddress) && (Address <= (FvbBaseAddress + FwVolHeader->FvLength))) {
*FvbHandle = HandleBuffer[Index];
Status = EFI_SUCCESS;
break;
}
}
FreePool (HandleBuffer);
return Status;
}
/**
Gets LBA of block and offset by given address.
This function gets the Logical Block Address (LBA) of firmware
volume block containing the given address, and the offset of
This function gets the Logical Block Address (LBA) of a firmware
volume block containing the given address, and the offset of the
address on the block.
@param Address Address which should be contained
by returned FVB handle
@param Lba Pointer to LBA for output
@param Offset Pointer to offset for output
by returned FVB handle.
@param Lba Pointer to LBA for output.
@param Offset Pointer to offset for output.
@retval EFI_SUCCESS LBA and offset successfully returned
@retval EFI_NOT_FOUND Fail to find FVB handle by address
@retval EFI_ABORTED Fail to find valid LBA and offset
@retval EFI_SUCCESS LBA and offset successfully returned.
@retval EFI_NOT_FOUND Fail to find FVB handle by address.
@retval EFI_ABORTED Fail to find valid LBA and offset.
**/
EFI_STATUS
@ -123,7 +41,6 @@ GetLbaAndOffsetByAddress (
)
{
EFI_STATUS Status;
EFI_HANDLE FvbHandle;
EFI_PHYSICAL_ADDRESS FvbBaseAddress;
EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
@ -132,25 +49,17 @@ GetLbaAndOffsetByAddress (
*Lba = (EFI_LBA) (-1);
*Offset = 0;
//
// Get the proper FVB
// Get the proper FVB protocol.
//
Status = GetFvbHandleByAddress (Address, &FvbHandle);
Status = GetFvbInfoByAddress (Address, NULL, &Fvb);
if (EFI_ERROR (Status)) {
return Status;
}
Status = gBS->HandleProtocol (
FvbHandle,
&gEfiFirmwareVolumeBlockProtocolGuid,
(VOID **) &Fvb
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Get the Base Address of FV
// Get the Base Address of FV.
//
Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress);
if (EFI_ERROR (Status)) {
@ -160,24 +69,22 @@ GetLbaAndOffsetByAddress (
FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvbBaseAddress);
//
// Get the (LBA, Offset) of Address
// Get the (LBA, Offset) of Address.
//
if ((Address >= FvbBaseAddress) && (Address <= (FvbBaseAddress + FwVolHeader->FvLength))) {
if ((FwVolHeader->FvLength) > (FwVolHeader->HeaderLength)) {
//
// BUGBUG: Assume one FV has one type of BlockLength
//
FvbMapEntry = &FwVolHeader->BlockMap[0];
for (LbaIndex = 1; LbaIndex <= FvbMapEntry->NumBlocks; LbaIndex += 1) {
if (Address < (FvbBaseAddress + FvbMapEntry->Length * LbaIndex)) {
//
// Found the (Lba, Offset)
//
*Lba = LbaIndex - 1;
*Offset = (UINTN) (Address - (FvbBaseAddress + FvbMapEntry->Length * (LbaIndex - 1)));
return EFI_SUCCESS;
}
}
if ((FwVolHeader->FvLength) > (FwVolHeader->HeaderLength)) {
//
// BUGBUG: Assume one FV has one type of BlockLength.
//
FvbMapEntry = &FwVolHeader->BlockMap[0];
for (LbaIndex = 1; LbaIndex <= FvbMapEntry->NumBlocks; LbaIndex += 1) {
if (Address < (FvbBaseAddress + FvbMapEntry->Length * LbaIndex)) {
//
// Found the (Lba, Offset).
//
*Lba = LbaIndex - 1;
*Offset = (UINTN) (Address - (FvbBaseAddress + FvbMapEntry->Length * (LbaIndex - 1)));
return EFI_SUCCESS;
}
}
}
@ -187,17 +94,17 @@ GetLbaAndOffsetByAddress (
/**
Writes a buffer to variable storage space, in the working block.
This function writes a buffer to variable storage space into firmware
This function writes a buffer to variable storage space into a firmware
volume block device. The destination is specified by parameter
VariableBase. Fault Tolerant Write protocol is used for writing.
@param VariableBase Base address of variable to write
@param Buffer Point to the data buffer
@param BufferSize The number of bytes of the data Buffer
@param Buffer Point to the data buffer.
@param BufferSize The number of bytes of the data Buffer.
@retval EFI_SUCCESS The function completed successfully
@retval EFI_NOT_FOUND Fail to locate Fault Tolerant Write protocol
@retval EFI_ABORTED The function could not complete successfully
@retval EFI_SUCCESS The function completed successfully.
@retval EFI_NOT_FOUND Fail to locate Fault Tolerant Write protocol.
@retval EFI_ABORTED The function could not complete successfully.
**/
EFI_STATUS
@ -216,35 +123,31 @@ FtwVariableSpace (
EFI_FAULT_TOLERANT_WRITE_PROTOCOL *FtwProtocol;
//
// Locate fault tolerant write protocol
// Locate fault tolerant write protocol.
//
Status = gBS->LocateProtocol (
&gEfiFaultTolerantWriteProtocolGuid,
NULL,
(VOID **) &FtwProtocol
);
Status = GetFtwProtocol((VOID **) &FtwProtocol);
if (EFI_ERROR (Status)) {
return EFI_NOT_FOUND;
}
//
// Locate Fvb handle by address
// Locate Fvb handle by address.
//
Status = GetFvbHandleByAddress (VariableBase, &FvbHandle);
Status = GetFvbInfoByAddress (VariableBase, &FvbHandle, NULL);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Get LBA and Offset by address
// Get LBA and Offset by address.
//
Status = GetLbaAndOffsetByAddress (VariableBase, &VarLba, &VarOffset);
if (EFI_ERROR (Status)) {
return EFI_ABORTED;
}
//
// Prepare for the variable data
// Prepare for the variable data.
//
FtwBufferSize = ((VARIABLE_STORE_HEADER *) ((UINTN) VariableBase))->Size;
FtwBuffer = AllocateRuntimePool (FtwBufferSize);
FtwBuffer = AllocatePool (FtwBufferSize);
if (FtwBuffer == NULL) {
return EFI_OUT_OF_RESOURCES;
}
@ -253,17 +156,17 @@ FtwVariableSpace (
CopyMem (FtwBuffer, Buffer, BufferSize);
//
// FTW write record
// FTW write record.
//
Status = FtwProtocol->Write (
FtwProtocol,
VarLba, // LBA
VarOffset, // Offset
FtwBufferSize, // NumBytes
NULL, // PrivateData NULL
FvbHandle, // Fvb Handle
FtwBuffer // write buffer
);
FtwProtocol,
VarLba, // LBA
VarOffset, // Offset
FtwBufferSize, // NumBytes
NULL, // PrivateData NULL
FvbHandle, // Fvb Handle
FtwBuffer // write buffer
);
FreePool (FtwBuffer);
return Status;

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
/** @file
The internal header file includes the common header files, defines
internal structure and functions used by RuntimeVariable module.
internal structure and functions used by Variable modules.
Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
@ -82,17 +82,17 @@ typedef struct {
/**
Writes a buffer to variable storage space, in the working block.
This function writes a buffer to variable storage space into firmware
volume block device. The destination is specified by parameter
This function writes a buffer to variable storage space into a firmware
volume block device. The destination is specified by the parameter
VariableBase. Fault Tolerant Write protocol is used for writing.
@param VariableBase Base address of variable to write
@param Buffer Point to the data buffer
@param BufferSize The number of bytes of the data Buffer
@param VariableBase Base address of the variable to write.
@param Buffer Point to the data buffer.
@param BufferSize The number of bytes of the data Buffer.
@retval EFI_SUCCESS The function completed successfully
@retval EFI_NOT_FOUND Fail to locate Fault Tolerant Write protocol
@retval EFI_ABORTED The function could not complete successfully
@retval EFI_SUCCESS The function completed successfully.
@retval EFI_NOT_FOUND Fail to locate Fault Tolerant Write protocol.
@retval EFI_ABORTED The function could not complete successfully.
**/
EFI_STATUS
@ -103,4 +103,329 @@ FtwVariableSpace (
);
/**
Update the variable region with Variable information. These are the same
arguments as the EFI Variable services.
@param[in] VariableName Name of variable.
@param[in] VendorGuid Guid of variable.
@param[in] Data Variable data.
@param[in] DataSize Size of data. 0 means delete.
@param[in] Attributes Attribues of the variable.
@param[in] Variable The variable information that is used to keep track of variable usage.
@retval EFI_SUCCESS The update operation is success.
@retval EFI_OUT_OF_RESOURCES Variable region is full, cannot write other data into this region.
**/
EFI_STATUS
UpdateVariable (
IN CHAR16 *VariableName,
IN EFI_GUID *VendorGuid,
IN VOID *Data,
IN UINTN DataSize,
IN UINT32 Attributes OPTIONAL,
IN VARIABLE_POINTER_TRACK *Variable
);
/**
Return TRUE if ExitBootServices () has been called.
@retval TRUE If ExitBootServices () has been called.
**/
BOOLEAN
AtRuntime (
VOID
);
/**
Initializes a basic mutual exclusion lock.
This function initializes a basic mutual exclusion lock to the released state
and returns the lock. Each lock provides mutual exclusion access at its task
priority level. Since there is no preemption or multiprocessor support in EFI,
acquiring the lock only consists of raising to the locks TPL.
If Lock is NULL, then ASSERT().
If Priority is not a valid TPL value, then ASSERT().
@param Lock A pointer to the lock data structure to initialize.
@param Priority EFI TPL is associated with the lock.
@return The lock.
**/
EFI_LOCK *
InitializeLock (
IN OUT EFI_LOCK *Lock,
IN EFI_TPL Priority
);
/**
Acquires lock only at boot time. Simply returns at runtime.
This is a temperary function that will be removed when
EfiAcquireLock() in UefiLib can handle the call in UEFI
Runtimer driver in RT phase.
It calls EfiAcquireLock() at boot time, and simply returns
at runtime.
@param Lock A pointer to the lock to acquire.
**/
VOID
AcquireLockOnlyAtBootTime (
IN EFI_LOCK *Lock
);
/**
Releases lock only at boot time. Simply returns at runtime.
This is a temperary function which will be removed when
EfiReleaseLock() in UefiLib can handle the call in UEFI
Runtimer driver in RT phase.
It calls EfiReleaseLock() at boot time and simply returns
at runtime.
@param Lock A pointer to the lock to release.
**/
VOID
ReleaseLockOnlyAtBootTime (
IN EFI_LOCK *Lock
);
/**
Retrive the FVB protocol interface by HANDLE.
@param[in] FvBlockHandle The handle of FVB protocol that provides services for
reading, writing, and erasing the target block.
@param[out] FvBlock The interface of FVB protocol
@retval EFI_SUCCESS The interface information for the specified protocol was returned.
@retval EFI_UNSUPPORTED The device does not support the FVB protocol.
@retval EFI_INVALID_PARAMETER FvBlockHandle is not a valid EFI_HANDLE or FvBlock is NULL.
**/
EFI_STATUS
GetFvbByHandle (
IN EFI_HANDLE FvBlockHandle,
OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvBlock
);
/**
Retrive the Swap Address Range protocol interface.
@param[out] SarProtocol The interface of SAR protocol
@retval EFI_SUCCESS The SAR protocol instance was found and returned in SarProtocol.
@retval EFI_NOT_FOUND The SAR protocol instance was not found.
@retval EFI_INVALID_PARAMETER SarProtocol is NULL.
**/
EFI_STATUS
GetSarProtocol (
OUT VOID **SarProtocol
);
/**
Function returns an array of handles that support the FVB protocol
in a buffer allocated from pool.
@param[out] NumberHandles The number of handles returned in Buffer.
@param[out] Buffer A pointer to the buffer to return the requested
array of handles that support FVB protocol.
@retval EFI_SUCCESS The array of handles was returned in Buffer, and the number of
handles in Buffer was returned in NumberHandles.
@retval EFI_NOT_FOUND No FVB handle was found.
@retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the matching results.
@retval EFI_INVALID_PARAMETER NumberHandles is NULL or Buffer is NULL.
**/
EFI_STATUS
GetFvbCountAndBuffer (
OUT UINTN *NumberHandles,
OUT EFI_HANDLE **Buffer
);
/**
Initializes variable store area for non-volatile and volatile variable.
@retval EFI_SUCCESS Function successfully executed.
@retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.
**/
EFI_STATUS
VariableCommonInitialize (
VOID
);
/**
This function reclaims variable storage if free size is below the threshold.
**/
VOID
ReclaimForOS(
VOID
);
/**
Initializes variable write service after FVB was ready.
@retval EFI_SUCCESS Function successfully executed.
@retval Others Fail to initialize the variable service.
**/
EFI_STATUS
VariableWriteServiceInitialize (
VOID
);
/**
Retrive the SMM Fault Tolerent Write protocol interface.
@param[out] FtwProtocol The interface of SMM Ftw protocol
@retval EFI_SUCCESS The SMM SAR protocol instance was found and returned in SarProtocol.
@retval EFI_NOT_FOUND The SMM SAR protocol instance was not found.
@retval EFI_INVALID_PARAMETER SarProtocol is NULL.
**/
EFI_STATUS
GetFtwProtocol (
OUT VOID **FtwProtocol
);
/**
Get the proper fvb handle and/or fvb protocol by the given Flash address.
@param[in] Address The Flash address.
@param[out] FvbHandle In output, if it is not NULL, it points to the proper FVB handle.
@param[out] FvbProtocol In output, if it is not NULL, it points to the proper FVB protocol.
**/
EFI_STATUS
GetFvbInfoByAddress (
IN EFI_PHYSICAL_ADDRESS Address,
OUT EFI_HANDLE *FvbHandle OPTIONAL,
OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvbProtocol OPTIONAL
);
/**
This code finds variable in storage blocks (Volatile or Non-Volatile).
@param VariableName Name of Variable to be found.
@param VendorGuid Variable vendor GUID.
@param Attributes Attribute value of the variable found.
@param DataSize Size of Data found. If size is less than the
data, this value contains the required size.
@param Data Data pointer.
@return EFI_INVALID_PARAMETER Invalid parameter.
@return EFI_SUCCESS Find the specified variable.
@return EFI_NOT_FOUND Not found.
@return EFI_BUFFER_TO_SMALL DataSize is too small for the result.
**/
EFI_STATUS
EFIAPI
VariableServiceGetVariable (
IN CHAR16 *VariableName,
IN EFI_GUID *VendorGuid,
OUT UINT32 *Attributes OPTIONAL,
IN OUT UINTN *DataSize,
OUT VOID *Data
);
/**
This code Finds the Next available variable.
@param VariableNameSize Size of the variable name.
@param VariableName Pointer to variable name.
@param VendorGuid Variable Vendor Guid.
@return EFI_INVALID_PARAMETER Invalid parameter.
@return EFI_SUCCESS Find the specified variable.
@return EFI_NOT_FOUND Not found.
@return EFI_BUFFER_TO_SMALL DataSize is too small for the result.
**/
EFI_STATUS
EFIAPI
VariableServiceGetNextVariableName (
IN OUT UINTN *VariableNameSize,
IN OUT CHAR16 *VariableName,
IN OUT EFI_GUID *VendorGuid
);
/**
This code sets variable in storage blocks (Volatile or Non-Volatile).
@param VariableName Name of Variable to be found.
@param VendorGuid Variable vendor GUID.
@param Attributes Attribute value of the variable found
@param DataSize Size of Data found. If size is less than the
data, this value contains the required size.
@param Data Data pointer.
@return EFI_INVALID_PARAMETER Invalid parameter.
@return EFI_SUCCESS Set successfully.
@return EFI_OUT_OF_RESOURCES Resource not enough to set variable.
@return EFI_NOT_FOUND Not found.
@return EFI_WRITE_PROTECTED Variable is read-only.
**/
EFI_STATUS
EFIAPI
VariableServiceSetVariable (
IN CHAR16 *VariableName,
IN EFI_GUID *VendorGuid,
IN UINT32 Attributes,
IN UINTN DataSize,
IN VOID *Data
);
/**
This code returns information about the EFI variables.
@param Attributes Attributes bitmask to specify the type of variables
on which to return information.
@param MaximumVariableStorageSize Pointer to the maximum size of the storage space available
for the EFI variables associated with the attributes specified.
@param RemainingVariableStorageSize Pointer to the remaining size of the storage space available
for EFI variables associated with the attributes specified.
@param MaximumVariableSize Pointer to the maximum size of an individual EFI variables
associated with the attributes specified.
@return EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied.
@return EFI_SUCCESS Query successfully.
@return EFI_UNSUPPORTED The attribute is not supported on this platform.
**/
EFI_STATUS
EFIAPI
VariableServiceQueryVariableInfo (
IN UINT32 Attributes,
OUT UINT64 *MaximumVariableStorageSize,
OUT UINT64 *RemainingVariableStorageSize,
OUT UINT64 *MaximumVariableSize
);
extern VARIABLE_MODULE_GLOBAL *mVariableModuleGlobal;
#endif

View File

@ -0,0 +1,402 @@
/** @file
Implement all four UEFI Runtime Variable services for the nonvolatile
and volatile storage space and install variable architecture protocol.
Copyright (c) 2006 - 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.
**/
#include "Variable.h"
extern VARIABLE_STORE_HEADER *mNvVariableCache;
VARIABLE_INFO_ENTRY *gVariableInfo;
EFI_HANDLE mHandle = NULL;
EFI_EVENT mVirtualAddressChangeEvent = NULL;
EFI_EVENT mFtwRegistration = NULL;
/**
Return TRUE if ExitBootServices () has been called
@retval TRUE If ExitBootServices () has been called
**/
BOOLEAN
AtRuntime (
VOID
)
{
return EfiAtRuntime ();
}
/**
Initializes a basic mutual exclusion lock.
This function initializes a basic mutual exclusion lock to the released state
and returns the lock. Each lock provides mutual exclusion access at its task
priority level. Since there is no preemption or multiprocessor support in EFI,
acquiring the lock only consists of raising to the locks TPL.
If Lock is NULL, then ASSERT().
If Priority is not a valid TPL value, then ASSERT().
@param Lock A pointer to the lock data structure to initialize.
@param Priority EFI TPL is associated with the lock.
@return The lock.
**/
EFI_LOCK *
InitializeLock (
IN OUT EFI_LOCK *Lock,
IN EFI_TPL Priority
)
{
return EfiInitializeLock (Lock, Priority);
}
/**
Acquires lock only at boot time. Simply returns at runtime.
This is a temperary function that will be removed when
EfiAcquireLock() in UefiLib can handle the call in UEFI
Runtimer driver in RT phase.
It calls EfiAcquireLock() at boot time, and simply returns
at runtime.
@param Lock A pointer to the lock to acquire.
**/
VOID
AcquireLockOnlyAtBootTime (
IN EFI_LOCK *Lock
)
{
if (!AtRuntime ()) {
EfiAcquireLock (Lock);
}
}
/**
Releases lock only at boot time. Simply returns at runtime.
This is a temperary function which will be removed when
EfiReleaseLock() in UefiLib can handle the call in UEFI
Runtimer driver in RT phase.
It calls EfiReleaseLock() at boot time and simply returns
at runtime.
@param Lock A pointer to the lock to release.
**/
VOID
ReleaseLockOnlyAtBootTime (
IN EFI_LOCK *Lock
)
{
if (!AtRuntime ()) {
EfiReleaseLock (Lock);
}
}
/**
Retrive the Fault Tolerent Write protocol interface.
@param[out] FtwProtocol The interface of Ftw protocol
@retval EFI_SUCCESS The FTW protocol instance was found and returned in FtwProtocol.
@retval EFI_NOT_FOUND The FTW protocol instance was not found.
@retval EFI_INVALID_PARAMETER SarProtocol is NULL.
**/
EFI_STATUS
GetFtwProtocol (
OUT VOID **FtwProtocol
)
{
EFI_STATUS Status;
//
// Locate Fault Tolerent Write protocol
//
Status = gBS->LocateProtocol (
&gEfiFaultTolerantWriteProtocolGuid,
NULL,
FtwProtocol
);
return Status;
}
/**
Retrive the FVB protocol interface by HANDLE.
@param[in] FvBlockHandle The handle of FVB protocol that provides services for
reading, writing, and erasing the target block.
@param[out] FvBlock The interface of FVB protocol
@retval EFI_SUCCESS The interface information for the specified protocol was returned.
@retval EFI_UNSUPPORTED The device does not support the FVB protocol.
@retval EFI_INVALID_PARAMETER FvBlockHandle is not a valid EFI_HANDLE or FvBlock is NULL.
**/
EFI_STATUS
GetFvbByHandle (
IN EFI_HANDLE FvBlockHandle,
OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvBlock
)
{
//
// To get the FVB protocol interface on the handle
//
return gBS->HandleProtocol (
FvBlockHandle,
&gEfiFirmwareVolumeBlockProtocolGuid,
(VOID **) FvBlock
);
}
/**
Function returns an array of handles that support the FVB protocol
in a buffer allocated from pool.
@param[out] NumberHandles The number of handles returned in Buffer.
@param[out] Buffer A pointer to the buffer to return the requested
array of handles that support FVB protocol.
@retval EFI_SUCCESS The array of handles was returned in Buffer, and the number of
handles in Buffer was returned in NumberHandles.
@retval EFI_NOT_FOUND No FVB handle was found.
@retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the matching results.
@retval EFI_INVALID_PARAMETER NumberHandles is NULL or Buffer is NULL.
**/
EFI_STATUS
GetFvbCountAndBuffer (
OUT UINTN *NumberHandles,
OUT EFI_HANDLE **Buffer
)
{
EFI_STATUS Status;
//
// Locate all handles of Fvb protocol
//
Status = gBS->LocateHandleBuffer (
ByProtocol,
&gEfiFirmwareVolumeBlockProtocolGuid,
NULL,
NumberHandles,
Buffer
);
return Status;
}
/**
Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.
This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
It convers pointer to new virtual address.
@param Event Event whose notification function is being invoked.
@param Context Pointer to the notification function's context.
**/
VOID
EFIAPI
VariableClassAddressChangeEvent (
IN EFI_EVENT Event,
IN VOID *Context
)
{
EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetBlockSize);
EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetPhysicalAddress);
EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetAttributes);
EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->SetAttributes);
EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->Read);
EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->Write);
EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->EraseBlocks);
EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance);
EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->PlatformLangCodes);
EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->LangCodes);
EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->PlatformLang);
EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase);
EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);
EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal);
EfiConvertPointer (0x0, (VOID **) &mNvVariableCache);
}
/**
Notification function of EVT_GROUP_READY_TO_BOOT event group.
This is a notification function registered on EVT_GROUP_READY_TO_BOOT event group.
When the Boot Manager is about to load and execute a boot option, it reclaims variable
storage if free size is below the threshold.
@param Event Event whose notification function is being invoked.
@param Context Pointer to the notification function's context.
**/
VOID
EFIAPI
OnReadyToBoot (
EFI_EVENT Event,
VOID *Context
)
{
ReclaimForOS ();
}
/**
Fault Tolerant Write protocol notification event handler.
Non-Volatile variable write may needs FTW protocol to reclaim when
writting variable.
@param[in] Event Event whose notification function is being invoked.
@param[in] Context Pointer to the notification function's context.
**/
VOID
EFIAPI
FtwNotificationEvent (
IN EFI_EVENT Event,
IN VOID *Context
)
{
EFI_STATUS Status;
EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol;
EFI_FAULT_TOLERANT_WRITE_PROTOCOL *FtwProtocol;
EFI_PHYSICAL_ADDRESS NvStorageVariableBase;
//
// Ensure FTW protocol is installed.
//
Status = GetFtwProtocol (&FtwProtocol);
if (EFI_ERROR (Status)) {
return ;
}
//
// Find the proper FVB protocol for variable.
//
NvStorageVariableBase = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageVariableBase64);
if (NvStorageVariableBase == 0) {
NvStorageVariableBase = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageVariableBase);
}
Status = GetFvbInfoByAddress (NvStorageVariableBase, NULL, &FvbProtocol);
if (EFI_ERROR (Status)) {
return ;
}
mVariableModuleGlobal->FvbInstance = FvbProtocol;
Status = VariableWriteServiceInitialize ();
ASSERT_EFI_ERROR (Status);
//
// Install the Variable Write Architectural protocol. //
Status = gBS->InstallProtocolInterface (
&mHandle,
&gEfiVariableWriteArchProtocolGuid,
EFI_NATIVE_INTERFACE,
NULL
);
ASSERT_EFI_ERROR (Status);
//
// Close the notify event to avoid install gEfiVariableWriteArchProtocolGuid again.
//
gBS->CloseEvent (Event);
}
/**
Variable Driver main entry point. The Variable driver places the 4 EFI
runtime services in the EFI System Table and installs arch protocols
for variable read and write services being availible. It also registers
a notification function for an EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
@param[in] ImageHandle The firmware allocated handle for the EFI image.
@param[in] SystemTable A pointer to the EFI System Table.
@retval EFI_SUCCESS Variable service successfully initialized.
**/
EFI_STATUS
EFIAPI
VariableServiceInitialize (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
EFI_EVENT ReadyToBootEvent;
Status = VariableCommonInitialize ();
ASSERT_EFI_ERROR (Status);
SystemTable->RuntimeServices->GetVariable = VariableServiceGetVariable;
SystemTable->RuntimeServices->GetNextVariableName = VariableServiceGetNextVariableName;
SystemTable->RuntimeServices->SetVariable = VariableServiceSetVariable;
SystemTable->RuntimeServices->QueryVariableInfo = VariableServiceQueryVariableInfo;
//
// Now install the Variable Runtime Architectural protocol on a new handle.
//
Status = gBS->InstallProtocolInterface (
&mHandle,
&gEfiVariableArchProtocolGuid,
EFI_NATIVE_INTERFACE,
NULL
);
ASSERT_EFI_ERROR (Status);
//
// Register FtwNotificationEvent () notify function.
//
EfiCreateProtocolNotifyEvent (
&gEfiFaultTolerantWriteProtocolGuid,
TPL_CALLBACK,
FtwNotificationEvent,
(VOID *)SystemTable,
&mFtwRegistration
);
Status = gBS->CreateEventEx (
EVT_NOTIFY_SIGNAL,
TPL_NOTIFY,
VariableClassAddressChangeEvent,
NULL,
&gEfiEventVirtualAddressChangeGuid,
&mVirtualAddressChangeEvent
);
ASSERT_EFI_ERROR (Status);
//
// Register the event handling function to reclaim variable for OS usage.
//
Status = EfiCreateEventReadyToBootEx (
TPL_NOTIFY,
OnReadyToBoot,
NULL,
&ReadyToBootEvent
);
if (FeaturePcdGet (PcdVariableCollectStatistics)) {
gBS->InstallConfigurationTable (&gEfiVariableGuid, gVariableInfo);
}
return EFI_SUCCESS;
}

View File

@ -33,6 +33,7 @@
[Sources]
Reclaim.c
Variable.c
VariableDxe.c
Variable.h
[Packages]
@ -76,7 +77,7 @@
gEfiMdeModulePkgTokenSpaceGuid.PcdVariableCollectStatistics ## SOMETIME_CONSUMES (statistic the information of variable.)
[Depex]
gEfiFirmwareVolumeBlockProtocolGuid AND gEfiFaultTolerantWriteProtocolGuid
TRUE
# [Event]
# ##
@ -84,4 +85,5 @@
# #
# EVENT_TYPE_NOTIFY_SIGNAL ## PRODUCES
#
#
#

View File

@ -0,0 +1,585 @@
/** @file
The sample implementation for SMM variable protocol. And this driver
implements an SMI handler to communicate with the DXE runtime driver
to provide variable services.
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.
**/
#include <Protocol/SmmFaultTolerantWrite.h>
#include <Library/SmmServicesTableLib.h>
#include "Variable.h"
#include "VariableSmmCommon.h"
extern SMM_VARIABLE_COMMUNICATE_VARIABLE_INFO_ENTRY *gVariableInfo;
EFI_HANDLE mSmmVariableHandle = NULL;
EFI_HANDLE mVariableHandle = NULL;
BOOLEAN mAtRuntime = FALSE;
EFI_GUID mZeroGuid = {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}};
EFI_GUID mSmmVariableWriteGuid = EFI_SMM_VARIABLE_WRITE_GUID;
EFI_SMM_VARIABLE_PROTOCOL gSmmVariable = {
VariableServiceGetVariable,
VariableServiceGetNextVariableName,
VariableServiceSetVariable,
VariableServiceQueryVariableInfo
};
/**
Return TRUE if ExitBootServices () has been called.
@retval TRUE If ExitBootServices () has been called.
**/
BOOLEAN
AtRuntime (
VOID
)
{
return mAtRuntime;
}
/**
Initializes a basic mutual exclusion lock.
This function initializes a basic mutual exclusion lock to the released state
and returns the lock. Each lock provides mutual exclusion access at its task
priority level. Since there is no preemption or multiprocessor support in EFI,
acquiring the lock only consists of raising to the locks TPL.
If Lock is NULL, then ASSERT().
If Priority is not a valid TPL value, then ASSERT().
@param Lock A pointer to the lock data structure to initialize.
@param Priority EFI TPL is associated with the lock.
@return The lock.
**/
EFI_LOCK *
InitializeLock (
IN OUT EFI_LOCK *Lock,
IN EFI_TPL Priority
)
{
return Lock;
}
/**
Acquires lock only at boot time. Simply returns at runtime.
This is a temperary function that will be removed when
EfiAcquireLock() in UefiLib can handle the call in UEFI
Runtimer driver in RT phase.
It calls EfiAcquireLock() at boot time, and simply returns
at runtime.
@param Lock A pointer to the lock to acquire.
**/
VOID
AcquireLockOnlyAtBootTime (
IN EFI_LOCK *Lock
)
{
}
/**
Releases lock only at boot time. Simply returns at runtime.
This is a temperary function which will be removed when
EfiReleaseLock() in UefiLib can handle the call in UEFI
Runtimer driver in RT phase.
It calls EfiReleaseLock() at boot time and simply returns
at runtime.
@param Lock A pointer to the lock to release.
**/
VOID
ReleaseLockOnlyAtBootTime (
IN EFI_LOCK *Lock
)
{
}
/**
Retrive the SMM Fault Tolerent Write protocol interface.
@param[out] FtwProtocol The interface of SMM Ftw protocol
@retval EFI_SUCCESS The SMM FTW protocol instance was found and returned in FtwProtocol.
@retval EFI_NOT_FOUND The SMM FTW protocol instance was not found.
@retval EFI_INVALID_PARAMETER SarProtocol is NULL.
**/
EFI_STATUS
GetFtwProtocol (
OUT VOID **FtwProtocol
)
{
EFI_STATUS Status;
//
// Locate Smm Fault Tolerent Write protocol
//
Status = gSmst->SmmLocateProtocol (
&gEfiSmmFaultTolerantWriteProtocolGuid,
NULL,
FtwProtocol
);
return Status;
}
/**
Retrive the SMM FVB protocol interface by HANDLE.
@param[in] FvBlockHandle The handle of SMM FVB protocol that provides services for
reading, writing, and erasing the target block.
@param[out] FvBlock The interface of SMM FVB protocol
@retval EFI_SUCCESS The interface information for the specified protocol was returned.
@retval EFI_UNSUPPORTED The device does not support the SMM FVB protocol.
@retval EFI_INVALID_PARAMETER FvBlockHandle is not a valid EFI_HANDLE or FvBlock is NULL.
**/
EFI_STATUS
GetFvbByHandle (
IN EFI_HANDLE FvBlockHandle,
OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvBlock
)
{
//
// To get the SMM FVB protocol interface on the handle
//
return gSmst->SmmHandleProtocol (
FvBlockHandle,
&gEfiSmmFirmwareVolumeBlockProtocolGuid,
(VOID **) FvBlock
);
}
/**
Function returns an array of handles that support the SMM FVB protocol
in a buffer allocated from pool.
@param[out] NumberHandles The number of handles returned in Buffer.
@param[out] Buffer A pointer to the buffer to return the requested
array of handles that support SMM FVB protocol.
@retval EFI_SUCCESS The array of handles was returned in Buffer, and the number of
handles in Buffer was returned in NumberHandles.
@retval EFI_NOT_FOUND No SMM FVB handle was found.
@retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the matching results.
@retval EFI_INVALID_PARAMETER NumberHandles is NULL or Buffer is NULL.
**/
EFI_STATUS
GetFvbCountAndBuffer (
OUT UINTN *NumberHandles,
OUT EFI_HANDLE **Buffer
)
{
EFI_STATUS Status;
UINTN BufferSize;
if ((NumberHandles == NULL) || (Buffer == NULL)) {
return EFI_INVALID_PARAMETER;
}
BufferSize = 0;
*NumberHandles = 0;
*Buffer = NULL;
Status = gSmst->SmmLocateHandle (
ByProtocol,
&gEfiSmmFirmwareVolumeBlockProtocolGuid,
NULL,
&BufferSize,
*Buffer
);
if (EFI_ERROR(Status) && Status != EFI_BUFFER_TOO_SMALL) {
return EFI_NOT_FOUND;
}
*Buffer = AllocatePool (BufferSize);
if (*Buffer == NULL) {
return EFI_OUT_OF_RESOURCES;
}
Status = gSmst->SmmLocateHandle (
ByProtocol,
&gEfiSmmFirmwareVolumeBlockProtocolGuid,
NULL,
&BufferSize,
*Buffer
);
*NumberHandles = BufferSize / sizeof(EFI_HANDLE);
if (EFI_ERROR(Status)) {
*NumberHandles = 0;
}
return Status;
}
/**
Get the variable statistics information from the information buffer pointed by gVariableInfo.
@param[in, out] InfoEntry A pointer to the buffer of variable information entry.
On input, point to the variable information returned last time. if
InfoEntry->VendorGuid is zero, return the first information.
On output, point to the next variable information.
@param[in, out] InfoSize On input, the size of the variable information buffer.
On output, the returned variable information size.
@retval EFI_SUCCESS The variable information is found and returned successfully.
@retval EFI_UNSUPPORTED No variable inoformation exists in variable driver. The
PcdVariableCollectStatistics should be set TRUE to support it.
@retval EFI_BUFFER_TOO_SMALL The buffer is too small to hold the next variable information.
**/
EFI_STATUS
SmmVariableGetStatistics (
IN OUT SMM_VARIABLE_COMMUNICATE_VARIABLE_INFO_ENTRY *InfoEntry,
IN OUT UINTN *InfoSize
)
{
SMM_VARIABLE_COMMUNICATE_VARIABLE_INFO_ENTRY *VariableInfo;
UINTN NameLength;
UINTN StatisticsInfoSize;
CHAR16 *InfoName;
ASSERT (InfoEntry != NULL);
VariableInfo = gVariableInfo;
if (VariableInfo == NULL) {
return EFI_UNSUPPORTED;
}
StatisticsInfoSize = sizeof (SMM_VARIABLE_COMMUNICATE_VARIABLE_INFO_ENTRY) + StrSize (VariableInfo->Name);
if (*InfoSize < sizeof (SMM_VARIABLE_COMMUNICATE_VARIABLE_INFO_ENTRY)) {
*InfoSize = StatisticsInfoSize;
return EFI_BUFFER_TOO_SMALL;
}
InfoName = (CHAR16 *)(InfoEntry + 1);
if (CompareGuid (&InfoEntry->VendorGuid, &mZeroGuid)) {
//
// Return the first variable info
//
CopyMem (InfoEntry, VariableInfo, sizeof (SMM_VARIABLE_COMMUNICATE_VARIABLE_INFO_ENTRY));
CopyMem (InfoName, VariableInfo->Name, StrSize (VariableInfo->Name));
*InfoSize = StatisticsInfoSize;
return EFI_SUCCESS;
}
//
// Get the next variable info
//
while (VariableInfo != NULL) {
if (CompareGuid (&VariableInfo->VendorGuid, &InfoEntry->VendorGuid)) {
NameLength = StrSize (VariableInfo->Name);
if (NameLength == StrSize (InfoName)) {
if (CompareMem (VariableInfo->Name, InfoName, NameLength) == 0) {
//
// Find the match one
//
VariableInfo = VariableInfo->Next;
break;
}
}
}
VariableInfo = VariableInfo->Next;
};
if (VariableInfo == NULL) {
*InfoSize = 0;
return EFI_SUCCESS;
}
//
// Output the new variable info
//
StatisticsInfoSize = sizeof (SMM_VARIABLE_COMMUNICATE_VARIABLE_INFO_ENTRY) + StrSize (VariableInfo->Name);
if (*InfoSize < StatisticsInfoSize) {
*InfoSize = StatisticsInfoSize;
return EFI_BUFFER_TOO_SMALL;
}
CopyMem (InfoEntry, VariableInfo, sizeof (SMM_VARIABLE_COMMUNICATE_VARIABLE_INFO_ENTRY));
CopyMem (InfoName, VariableInfo->Name, StrSize (VariableInfo->Name));
*InfoSize = StatisticsInfoSize;
return EFI_SUCCESS;
}
/**
Communication service SMI Handler entry.
This SMI handler provides services for the variable wrapper driver.
@param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
@param[in] RegisterContext Points to an optional handler context which was specified when the
handler was registered.
@param[in, out] CommBuffer A pointer to a collection of data in memory that will
be conveyed from a non-SMM environment into an SMM environment.
@param[in, out] CommBufferSize The size of the CommBuffer.
@retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers
should still be called.
@retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has been quiesced but other handlers should
still be called.
@retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pending and other handlers should still
be called.
@retval EFI_INTERRUPT_PENDING The interrupt could not be quiesced.
**/
EFI_STATUS
EFIAPI
SmmVariableHandler (
IN EFI_HANDLE DispatchHandle,
IN CONST VOID *RegisterContext,
IN OUT VOID *CommBuffer,
IN OUT UINTN *CommBufferSize
)
{
EFI_STATUS Status;
SMM_VARIABLE_COMMUNICATE_HEADER *SmmVariableFunctionHeader;
SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *SmmVariableHeader;
SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *GetNextVariableName;
SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO *QueryVariableInfo;
SMM_VARIABLE_COMMUNICATE_VARIABLE_INFO_ENTRY *VariableInfo;
UINTN InfoSize;
ASSERT (CommBuffer != NULL);
SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *)CommBuffer;
switch (SmmVariableFunctionHeader->Function) {
case SMM_VARIABLE_FUNCTION_GET_VARIABLE:
SmmVariableHeader = (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *) SmmVariableFunctionHeader->Data;
Status = VariableServiceGetVariable (
SmmVariableHeader->Name,
&SmmVariableHeader->Guid,
&SmmVariableHeader->Attributes,
&SmmVariableHeader->DataSize,
(UINT8 *)SmmVariableHeader->Name + SmmVariableHeader->NameSize
);
break;
case SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME:
GetNextVariableName = (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *) SmmVariableFunctionHeader->Data;
Status = VariableServiceGetNextVariableName (
&GetNextVariableName->NameSize,
GetNextVariableName->Name,
&GetNextVariableName->Guid
);
break;
case SMM_VARIABLE_FUNCTION_SET_VARIABLE:
SmmVariableHeader = (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *) SmmVariableFunctionHeader->Data;
Status = VariableServiceSetVariable (
SmmVariableHeader->Name,
&SmmVariableHeader->Guid,
SmmVariableHeader->Attributes,
SmmVariableHeader->DataSize,
(UINT8 *)SmmVariableHeader->Name + SmmVariableHeader->NameSize
);
break;
case SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO:
QueryVariableInfo = (SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO *) SmmVariableFunctionHeader->Data;
Status = VariableServiceQueryVariableInfo (
QueryVariableInfo->Attributes,
&QueryVariableInfo->MaximumVariableStorageSize,
&QueryVariableInfo->RemainingVariableStorageSize,
&QueryVariableInfo->MaximumVariableSize
);
break;
case SMM_VARIABLE_FUNCTION_READY_TO_BOOT:
ReclaimForOS ();
Status = EFI_SUCCESS;
break;
case SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE:
mAtRuntime = TRUE;
Status = EFI_SUCCESS;
break;
case SMM_VARIABLE_FUNCTION_GET_STATISTICS:
VariableInfo = (SMM_VARIABLE_COMMUNICATE_VARIABLE_INFO_ENTRY *) SmmVariableFunctionHeader->Data;
InfoSize = *CommBufferSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_HEADER, Data);
Status = SmmVariableGetStatistics (VariableInfo, &InfoSize);
*CommBufferSize = InfoSize + OFFSET_OF (SMM_VARIABLE_COMMUNICATE_HEADER, Data);
break;
default:
ASSERT (FALSE);
Status = EFI_UNSUPPORTED;
}
SmmVariableFunctionHeader->ReturnStatus = Status;
return EFI_SUCCESS;
}
/**
SMM Fault Tolerant Write protocol notification event handler.
Non-Volatile variable write may needs FTW protocol to reclaim when
writting variable.
@param Protocol Points to the protocol's unique identifier
@param Interface Points to the interface instance
@param Handle The handle on which the interface was installed
@retval EFI_SUCCESS SmmEventCallback runs successfully
@retval EFI_NOT_FOUND The Fvb protocol for variable is not found.
**/
EFI_STATUS
EFIAPI
SmmFtwNotificationEvent (
IN CONST EFI_GUID *Protocol,
IN VOID *Interface,
IN EFI_HANDLE Handle
)
{
EFI_STATUS Status;
EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol;
EFI_SMM_FAULT_TOLERANT_WRITE_PROTOCOL *FtwProtocol;
EFI_PHYSICAL_ADDRESS NvStorageVariableBase;
if (mVariableModuleGlobal->FvbInstance != NULL) {
return EFI_SUCCESS;
}
//
// Ensure SMM FTW protocol is installed.
//
Status = GetFtwProtocol (&FtwProtocol);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Find the proper FVB protocol for variable.
//
NvStorageVariableBase = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageVariableBase64);
if (NvStorageVariableBase == 0) {
NvStorageVariableBase = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageVariableBase);
}
Status = GetFvbInfoByAddress (NvStorageVariableBase, NULL, &FvbProtocol);
if (EFI_ERROR (Status)) {
return EFI_NOT_FOUND;
}
mVariableModuleGlobal->FvbInstance = FvbProtocol;
Status = VariableWriteServiceInitialize ();
ASSERT_EFI_ERROR (Status);
//
// Notify the variable wrapper driver the variable write service is ready
//
Status = gBS->InstallProtocolInterface (
&mSmmVariableHandle,
&mSmmVariableWriteGuid,
EFI_NATIVE_INTERFACE,
NULL
);
ASSERT_EFI_ERROR (Status);
return EFI_SUCCESS;
}
/**
Variable Driver main entry point. The Variable driver places the 4 EFI
runtime services in the EFI System Table and installs arch protocols
for variable read and write services being availible. It also registers
a notification function for an EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
@param[in] ImageHandle The firmware allocated handle for the EFI image.
@param[in] SystemTable A pointer to the EFI System Table.
@retval EFI_SUCCESS Variable service successfully initialized.
**/
EFI_STATUS
EFIAPI
VariableServiceInitialize (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
EFI_HANDLE VariableHandle;
VOID *SmmFtwRegistration;
//
// Variable initialize.
//
Status = VariableCommonInitialize ();
ASSERT_EFI_ERROR (Status);
//
// Install the Smm Variable Protocol on a new handle.
//
VariableHandle = NULL;
Status = gSmst->SmmInstallProtocolInterface (
&VariableHandle,
&gEfiSmmVariableProtocolGuid,
EFI_NATIVE_INTERFACE,
&gSmmVariable
);
ASSERT_EFI_ERROR (Status);
///
/// Register SMM variable SMI handler
///
VariableHandle = NULL;
Status = gSmst->SmiHandlerRegister (SmmVariableHandler, &gEfiSmmVariableProtocolGuid, &VariableHandle);
ASSERT_EFI_ERROR (Status);
//
// Notify the variable wrapper driver the variable service is ready
//
Status = SystemTable->BootServices->InstallProtocolInterface (
&mVariableHandle,
&gEfiSmmVariableProtocolGuid,
EFI_NATIVE_INTERFACE,
&gSmmVariable
);
ASSERT_EFI_ERROR (Status);
//
// Register FtwNotificationEvent () notify function.
//
Status = gSmst->SmmRegisterProtocolNotify (
&gEfiSmmFaultTolerantWriteProtocolGuid,
SmmFtwNotificationEvent,
&SmmFtwRegistration
);
ASSERT_EFI_ERROR (Status);
SmmFtwNotificationEvent (NULL, NULL, NULL);
return EFI_SUCCESS;
}

View File

@ -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

View File

@ -0,0 +1,40 @@
/** @file
The internal header file includes the common header files shared
by VariableSmm module and VariableSmmRuntimeDxe 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.
**/
#ifndef _VARIABLE_SMM_COMMON_H_
#define _VARIABLE_SMM_COMMON_H_
#include <PiDxe.h>
#include <Protocol/SmmVariable.h>
#include <Protocol/SmmFirmwareVolumeBlock.h>
#include <Guid/VariableFormat.h>
#define EFI_SMM_VARIABLE_WRITE_GUID \
{ 0x93ba1826, 0xdffb, 0x45dd, { 0x82, 0xa7, 0xe7, 0xdc, 0xaa, 0x3b, 0xbd, 0xf3 } }
///
/// Size of SMM communicate header, without including the payload.
///
#define SMM_COMMUNICATE_HEADER_SIZE (OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data))
///
/// Size of SMM variable communicate header, without including the payload.
///
#define SMM_VARIABLE_COMMUNICATE_HEADER_SIZE (OFFSET_OF (SMM_VARIABLE_COMMUNICATE_HEADER, Data))
#endif

View File

@ -0,0 +1,650 @@
/** @file
Implement all four UEFI Runtime Variable services for the nonvolatile
and volatile storage space and install variable architecture 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.
**/
#include <Protocol/VariableWrite.h>
#include <Protocol/Variable.h>
#include <Protocol/SmmCommunication.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiRuntimeServicesTableLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/UefiDriverEntryPoint.h>
#include <Library/UefiRuntimeLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h>
#include <Library/PcdLib.h>
#include <Library/UefiLib.h>
#include <Library/BaseLib.h>
#include <Guid/EventGroup.h>
#include "VariableSmmCommon.h"
EFI_HANDLE mHandle = NULL;
EFI_SMM_VARIABLE_PROTOCOL *mSmmVariable = NULL;
EFI_EVENT mVirtualAddressChangeEvent = NULL;
EFI_SMM_COMMUNICATION_PROTOCOL *mSmmCommunication = NULL;
UINT8 *mVariableBuffer = NULL;
UINT8 *mVariableBufferPhysical = NULL;
EFI_GUID mSmmVariableWriteGuid = EFI_SMM_VARIABLE_WRITE_GUID;
UINTN mVariableBufferSize;
/**
Initialize the communicate buffer using DataSize and Function.
The communicate size is: SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE +
DataSize.
@param[out] DataPtr Points to the data in the communicate buffer.
@param[in] DataSize The data size to send to SMM.
@param[in] Function The function number to initialize the communicate header.
@retval EFI_INVALID_PARAMETER The data size is too big.
@retval EFI_SUCCESS Find the specified variable.
**/
EFI_STATUS
InitCommunicateBuffer (
OUT VOID **DataPtr OPTIONAL,
IN UINTN DataSize,
IN UINTN Function
)
{
EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;
SMM_VARIABLE_COMMUNICATE_HEADER *SmmVariableFunctionHeader;
if (DataSize + SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE > mVariableBufferSize) {
return EFI_INVALID_PARAMETER;
}
SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) mVariableBuffer;
CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmVariableProtocolGuid);
SmmCommunicateHeader->MessageLength = DataSize + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *) SmmCommunicateHeader->Data;
SmmVariableFunctionHeader->Function = Function;
if (DataPtr != NULL) {
*DataPtr = SmmVariableFunctionHeader->Data;
}
return EFI_SUCCESS;
}
/**
Send the data in communicate buffer to SMM.
@param[in] DataSize This size of the function header and the data.
@RetVal EFI_SUCCESS Success is returned from the functin in SMM.
@RetVal Others Failure is returned from the function in SMM.
**/
EFI_STATUS
SendCommunicateBuffer (
IN UINTN DataSize
)
{
EFI_STATUS Status;
UINTN CommSize;
EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;
SMM_VARIABLE_COMMUNICATE_HEADER *SmmVariableFunctionHeader;
CommSize = DataSize + SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
Status = mSmmCommunication->Communicate (mSmmCommunication, mVariableBufferPhysical, &CommSize);
ASSERT_EFI_ERROR (Status);
SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) mVariableBuffer;
SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *)SmmCommunicateHeader->Data;
return SmmVariableFunctionHeader->ReturnStatus;
}
/**
This code finds variable in storage blocks (Volatile or Non-Volatile).
@param[in] VariableName Name of Variable to be found.
@param[in] VendorGuid Variable vendor GUID.
@param[out] Attributes Attribute value of the variable found.
@param[in, out] DataSize Size of Data found. If size is less than the
data, this value contains the required size.
@param[out] Data Data pointer.
@retval EFI_INVALID_PARAMETER Invalid parameter.
@retval EFI_SUCCESS Find the specified variable.
@retval EFI_NOT_FOUND Not found.
@retval EFI_BUFFER_TO_SMALL DataSize is too small for the result.
**/
EFI_STATUS
EFIAPI
RuntimeServiceGetVariable (
IN CHAR16 *VariableName,
IN EFI_GUID *VendorGuid,
OUT UINT32 *Attributes OPTIONAL,
IN OUT UINTN *DataSize,
OUT VOID *Data
)
{
EFI_STATUS Status;
UINTN PayloadSize;
SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *SmmVariableHeader;
if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {
return EFI_INVALID_PARAMETER;
}
if ((*DataSize != 0) && (Data == NULL)) {
return EFI_INVALID_PARAMETER;
}
//
// Init the communicate buffer. The buffer data size is:
// SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
//
PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + StrSize (VariableName);
Status = InitCommunicateBuffer (&SmmVariableHeader, PayloadSize, SMM_VARIABLE_FUNCTION_GET_VARIABLE);
if (EFI_ERROR (Status)) {
return Status;
}
ASSERT (SmmVariableHeader != NULL);
CopyGuid (&SmmVariableHeader->Guid, VendorGuid);
SmmVariableHeader->DataSize = *DataSize;
SmmVariableHeader->NameSize = StrSize (VariableName);
if (Attributes == NULL) {
SmmVariableHeader->Attributes = 0;
} else {
SmmVariableHeader->Attributes = *Attributes;
}
CopyMem (SmmVariableHeader->Name, VariableName, SmmVariableHeader->NameSize);
//
// Send data to SMM.
//
Status = SendCommunicateBuffer (PayloadSize);
//
// Get data from SMM.
//
*DataSize = SmmVariableHeader->DataSize;
if (Attributes != NULL) {
*Attributes = SmmVariableHeader->Attributes;
}
if (EFI_ERROR (Status)) {
return Status;
}
CopyMem (Data, (UINT8 *)SmmVariableHeader->Name + SmmVariableHeader->NameSize, SmmVariableHeader->DataSize);
return Status;
}
/**
This code Finds the Next available variable.
@param[in, out] VariableNameSize Size of the variable name.
@param[in, out] VariableName Pointer to variable name.
@param[in, out] VendorGuid Variable Vendor Guid.
@retval EFI_INVALID_PARAMETER Invalid parameter.
@retval EFI_SUCCESS Find the specified variable.
@retval EFI_NOT_FOUND Not found.
@retval EFI_BUFFER_TO_SMALL DataSize is too small for the result.
**/
EFI_STATUS
EFIAPI
RuntimeServiceGetNextVariableName (
IN OUT UINTN *VariableNameSize,
IN OUT CHAR16 *VariableName,
IN OUT EFI_GUID *VendorGuid
)
{
EFI_STATUS Status;
UINTN PayloadSize;
SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *SmmGetNextVariableName;
if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) {
return EFI_INVALID_PARAMETER;
}
//
// Init the communicate buffer. The buffer data size is:
// SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
//
PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name) + *VariableNameSize;
Status = InitCommunicateBuffer (&SmmGetNextVariableName, PayloadSize, SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME);
if (EFI_ERROR (Status)) {
return Status;
}
ASSERT (SmmGetNextVariableName != NULL);
SmmGetNextVariableName->NameSize = *VariableNameSize;
CopyGuid (&SmmGetNextVariableName->Guid, VendorGuid);
CopyMem (SmmGetNextVariableName->Name, VariableName, *VariableNameSize);
//
// Send data to SMM
//
Status = SendCommunicateBuffer (PayloadSize);
//
// Get data from SMM.
//
*VariableNameSize = SmmGetNextVariableName->NameSize;
if (EFI_ERROR (Status)) {
return Status;
}
CopyGuid (VendorGuid, &SmmGetNextVariableName->Guid);
CopyMem (VariableName, SmmGetNextVariableName->Name, SmmGetNextVariableName->NameSize);
return Status;
}
/**
This code sets variable in storage blocks (Volatile or Non-Volatile).
@param[in] VariableName Name of Variable to be found.
@param[in] VendorGuid Variable vendor GUID.
@param[in] Attributes Attribute value of the variable found
@param[in] DataSize Size of Data found. If size is less than the
data, this value contains the required size.
@param[in] Data Data pointer.
@retval EFI_INVALID_PARAMETER Invalid parameter.
@retval EFI_SUCCESS Set successfully.
@retval EFI_OUT_OF_RESOURCES Resource not enough to set variable.
@retval EFI_NOT_FOUND Not found.
@retval EFI_WRITE_PROTECTED Variable is read-only.
**/
EFI_STATUS
EFIAPI
RuntimeServiceSetVariable (
IN CHAR16 *VariableName,
IN EFI_GUID *VendorGuid,
IN UINT32 Attributes,
IN UINTN DataSize,
IN VOID *Data
)
{
EFI_STATUS Status;
UINTN PayloadSize;
SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *SmmVariableHeader;
//
// Check input parameters.
//
if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {
return EFI_INVALID_PARAMETER;
}
if (DataSize != 0 && Data == NULL) {
return EFI_INVALID_PARAMETER;
}
//
// Init the communicate buffer. The buffer data size is:
// SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
//
PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + StrSize (VariableName) + DataSize;
Status = InitCommunicateBuffer (&SmmVariableHeader, PayloadSize, SMM_VARIABLE_FUNCTION_SET_VARIABLE);
if (EFI_ERROR (Status)) {
return Status;
}
ASSERT (SmmVariableHeader != NULL);
CopyGuid ((EFI_GUID *) &SmmVariableHeader->Guid, VendorGuid);
SmmVariableHeader->DataSize = DataSize;
SmmVariableHeader->NameSize = StrSize (VariableName);
SmmVariableHeader->Attributes = Attributes;
CopyMem (SmmVariableHeader->Name, VariableName, SmmVariableHeader->NameSize);
CopyMem ((UINT8 *) SmmVariableHeader->Name + SmmVariableHeader->NameSize, Data, DataSize);
//
// Send data to SMM.
//
Status = SendCommunicateBuffer (PayloadSize);
return Status;
}
/**
This code returns information about the EFI variables.
@param[in] Attributes Attributes bitmask to specify the type of variables
on which to return information.
@param[out] MaximumVariableStorageSize Pointer to the maximum size of the storage space available
for the EFI variables associated with the attributes specified.
@param[out] RemainingVariableStorageSize Pointer to the remaining size of the storage space available
for EFI variables associated with the attributes specified.
@param[out] MaximumVariableSize Pointer to the maximum size of an individual EFI variables
associated with the attributes specified.
@retval EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied.
@retval EFI_SUCCESS Query successfully.
@retval EFI_UNSUPPORTED The attribute is not supported on this platform.
**/
EFI_STATUS
EFIAPI
RuntimeServiceQueryVariableInfo (
IN UINT32 Attributes,
OUT UINT64 *MaximumVariableStorageSize,
OUT UINT64 *RemainingVariableStorageSize,
OUT UINT64 *MaximumVariableSize
)
{
EFI_STATUS Status;
UINTN PayloadSize;
SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO *SmmQueryVariableInfo;
if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) {
return EFI_INVALID_PARAMETER;
}
//
// Init the communicate buffer. The buffer data size is:
// SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize;
//
PayloadSize = sizeof (SMM_VARIABLE_COMMUNICATE_VARIABLE_INFO_ENTRY);
Status = InitCommunicateBuffer (&SmmQueryVariableInfo, PayloadSize, SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO);
if (EFI_ERROR (Status)) {
return Status;
}
ASSERT (SmmQueryVariableInfo != NULL);
SmmQueryVariableInfo->Attributes = Attributes;
//
// Send data to SMM.
//
Status = SendCommunicateBuffer (PayloadSize);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Get data from SMM.
//
*MaximumVariableSize = SmmQueryVariableInfo->MaximumVariableSize;
*MaximumVariableStorageSize = SmmQueryVariableInfo->MaximumVariableStorageSize;
*RemainingVariableStorageSize = SmmQueryVariableInfo->RemainingVariableStorageSize;
return EFI_SUCCESS;
}
/**
Exit Boot Services Event notification handler.
Notify SMM variable driver about the event.
@param[in] Event Event whose notification function is being invoked.
@param[in] Context Pointer to the notification function's context.
**/
VOID
EFIAPI
OnExitBootServices (
IN EFI_EVENT Event,
IN VOID *Context
)
{
//
// Init the communicate buffer. The buffer data size is:
// SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.
//
InitCommunicateBuffer (NULL, 0, SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE);
//
// Send data to SMM.
//
SendCommunicateBuffer (0);
}
/**
On Ready To Boot Services Event notification handler.
Notify SMM variable driver about the event.
@param[in] Event Event whose notification function is being invoked
@param[in] Context Pointer to the notification function's context
**/
VOID
EFIAPI
OnReadyToBoot (
IN EFI_EVENT Event,
IN VOID *Context
)
{
//
// Init the communicate buffer. The buffer data size is:
// SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.
//
InitCommunicateBuffer (NULL, 0, SMM_VARIABLE_FUNCTION_READY_TO_BOOT);
//
// Send data to SMM.
//
SendCommunicateBuffer (0);
}
/**
Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.
This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
It convers pointer to new virtual address.
@param[in] Event Event whose notification function is being invoked.
@param[in] Context Pointer to the notification function's context.
**/
VOID
EFIAPI
VariableAddressChangeEvent (
IN EFI_EVENT Event,
IN VOID *Context
)
{
EfiConvertPointer (0x0, (VOID **) &mVariableBuffer);
EfiConvertPointer (0x0, (VOID **) &mSmmCommunication);
}
/**
Initialize variable service and install Variable Architectural protocol.
@param[in] Event Event whose notification function is being invoked.
@param[in] Context Pointer to the notification function's context.
**/
VOID
EFIAPI
SmmVariableReady (
IN EFI_EVENT Event,
IN VOID *Context
)
{
EFI_STATUS Status;
Status = gBS->LocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID **)&mSmmVariable);
if (EFI_ERROR (Status)) {
return;
}
Status = gBS->LocateProtocol (&gEfiSmmCommunicationProtocolGuid, NULL, (VOID **) &mSmmCommunication);
ASSERT_EFI_ERROR (Status);
//
// Allocate memory for variable store.
//
mVariableBufferSize = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
mVariableBufferSize += MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize));
mVariableBuffer = AllocateRuntimePool (mVariableBufferSize);
ASSERT (mVariableBuffer != NULL);
//
// Save the buffer physical address used for SMM conmunication.
//
mVariableBufferPhysical = mVariableBuffer;
gRT->GetVariable = RuntimeServiceGetVariable;
gRT->GetNextVariableName = RuntimeServiceGetNextVariableName;
gRT->SetVariable = RuntimeServiceSetVariable;
gRT->QueryVariableInfo = RuntimeServiceQueryVariableInfo;
//
// Install the Variable Architectural Protocol on a new handle.
//
Status = gBS->InstallProtocolInterface (
&mHandle,
&gEfiVariableArchProtocolGuid,
EFI_NATIVE_INTERFACE,
NULL
);
ASSERT_EFI_ERROR (Status);
}
/**
SMM Non-Volatile variable write service is ready notify event handler.
@param[in] Event Event whose notification function is being invoked.
@param[in] Context Pointer to the notification function's context.
**/
VOID
EFIAPI
SmmVariableWriteReady (
IN EFI_EVENT Event,
IN VOID *Context
)
{
EFI_STATUS Status;
VOID *ProtocolOps;
//
// Check whether the protocol is installed or not.
//
Status = gBS->LocateProtocol (&mSmmVariableWriteGuid, NULL, (VOID **) &ProtocolOps);
if (EFI_ERROR (Status)) {
return;
}
Status = gBS->InstallProtocolInterface (
&mHandle,
&gEfiVariableWriteArchProtocolGuid,
EFI_NATIVE_INTERFACE,
NULL
);
ASSERT_EFI_ERROR (Status);
}
/**
Variable Driver main entry point. The Variable driver places the 4 EFI
runtime services in the EFI System Table and installs arch protocols
for variable read and write services being availible. It also registers
a notification function for an EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
@param[in] ImageHandle The firmware allocated handle for the EFI image.
@param[in] SystemTable A pointer to the EFI System Table.
@retval EFI_SUCCESS Variable service successfully initialized.
**/
EFI_STATUS
EFIAPI
VariableSmmRuntimeInitialize (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
VOID *SmmVariableRegistration;
VOID *SmmVariableWriteRegistration;
EFI_EVENT OnReadyToBootEvent;
EFI_EVENT ExitBootServiceEvent;
//
// Smm variable service is ready
//
EfiCreateProtocolNotifyEvent (
&gEfiSmmVariableProtocolGuid,
TPL_CALLBACK,
SmmVariableReady,
NULL,
&SmmVariableRegistration
);
//
// Smm Non-Volatile variable write service is ready
//
EfiCreateProtocolNotifyEvent (
&mSmmVariableWriteGuid,
TPL_CALLBACK,
SmmVariableWriteReady,
NULL,
&SmmVariableWriteRegistration
);
//
// Register the event to reclaim variable for OS usage.
//
EfiCreateEventReadyToBootEx (
TPL_NOTIFY,
OnReadyToBoot,
NULL,
&OnReadyToBootEvent
);
//
// Register the event to inform SMM variable that it is at runtime.
//
gBS->CreateEventEx (
EVT_NOTIFY_SIGNAL,
TPL_NOTIFY,
OnExitBootServices,
NULL,
&gEfiEventExitBootServicesGuid,
&ExitBootServiceEvent
);
//
// Register the event to convert the pointer for runtime.
//
gBS->CreateEventEx (
EVT_NOTIFY_SIGNAL,
TPL_NOTIFY,
VariableAddressChangeEvent,
NULL,
&gEfiEventVirtualAddressChangeGuid,
&mVirtualAddressChangeEvent
);
return EFI_SUCCESS;
}

View File

@ -0,0 +1,69 @@
## @file
# Component description file for Variable SmmRuntimeDxe module.
#
# This module is the Runtime DXE part correspond to SMM variable module. It
# installs variable arch protocol and variable write arch protocol and works
# with SMM variable module together.
# 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 = VariableSmmRuntimeDxe
FILE_GUID = 9F7DCADE-11EA-448a-A46F-76E003657DD1
MODULE_TYPE = DXE_RUNTIME_DRIVER
VERSION_STRING = 1.0
ENTRY_POINT = VariableSmmRuntimeInitialize
#
# The following information is for reference only and not required by the build tools.
#
# VALID_ARCHITECTURES = IA32 X64
#
# VIRTUAL_ADDRESS_MAP_CALLBACK = VariableAddressChangeEvent
#
[Sources]
VariableSmmRuntimeDxe.c
VariableSmmCommon.h
[Packages]
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
SecurityPkg/SecurityPkg.dec
[LibraryClasses]
MemoryAllocationLib
BaseLib
UefiBootServicesTableLib
DebugLib
UefiRuntimeLib
DxeServicesTableLib
UefiDriverEntryPoint
PcdLib
[Protocols]
gEfiVariableWriteArchProtocolGuid ## ALWAYS_PRODUCES
gEfiVariableArchProtocolGuid ## ALWAYS_PRODUCES
gEfiSmmCommunicationProtocolGuid
gEfiSmmVariableProtocolGuid
[Guids]
gEfiEventVirtualAddressChangeGuid ## PRODUCES ## Event
[Pcd]
gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize
gEfiMdeModulePkgTokenSpaceGuid.PcdMaxHardwareErrorVariableSize
gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase
[Depex]
gEfiSmmCommunicationProtocolGuid