| /**@file | |
| Firmware Volume Block Protocol Runtime Abstraction | |
| mFvbEntry is an array of Handle Fvb pairs. The Fvb Lib Instance matches the | |
| index in the mFvbEntry array. This should be the same sequence as the FVB's | |
| were described in the HOB. We have to remember the handle so we can tell if | |
| the protocol has been reinstalled and it needs updateing. | |
| If you are using any of these lib functions.you must first call FvbInitialize (). | |
| Copyright (c) 2006, Intel Corporation | |
| All rights reserved. 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 "Fvb.h" | |
| // | |
| // Lib will ASSERT if more FVB devices than this are added to the system. | |
| // | |
| STATIC FVB_ENTRY *mFvbEntry; | |
| STATIC EFI_EVENT mFvbRegistration; | |
| STATIC BOOLEAN mEfiFvbInitialized = FALSE; | |
| STATIC UINTN mFvbCount; | |
| /** | |
| Check whether an address is runtime memory or not. | |
| @param Address The Address being checked. | |
| @retval TRUE The address is runtime memory. | |
| @retval FALSE The address is not runtime memory. | |
| **/ | |
| BOOLEAN | |
| IsRuntimeMemory ( | |
| IN VOID *Address | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| UINT8 TmpMemoryMap[1]; | |
| UINTN MapKey; | |
| UINTN DescriptorSize; | |
| UINT32 DescriptorVersion; | |
| UINTN MemoryMapSize; | |
| EFI_MEMORY_DESCRIPTOR *MemoryMap; | |
| EFI_MEMORY_DESCRIPTOR *MemoryMapPtr; | |
| BOOLEAN IsRuntime; | |
| UINTN Index; | |
| IsRuntime = FALSE; | |
| // | |
| // Get System MemoryMapSize | |
| // | |
| MemoryMapSize = 1; | |
| Status = gBS->GetMemoryMap ( | |
| &MemoryMapSize, | |
| (EFI_MEMORY_DESCRIPTOR *)TmpMemoryMap, | |
| &MapKey, | |
| &DescriptorSize, | |
| &DescriptorVersion | |
| ); | |
| ASSERT (Status == EFI_BUFFER_TOO_SMALL); | |
| // | |
| // Enlarge space here, because we will allocate pool now. | |
| // | |
| MemoryMapSize += EFI_PAGE_SIZE; | |
| Status = gBS->AllocatePool ( | |
| EfiBootServicesData, | |
| MemoryMapSize, | |
| (VOID**)&MemoryMap | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| // | |
| // Get System MemoryMap | |
| // | |
| Status = gBS->GetMemoryMap ( | |
| &MemoryMapSize, | |
| MemoryMap, | |
| &MapKey, | |
| &DescriptorSize, | |
| &DescriptorVersion | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| MemoryMapPtr = MemoryMap; | |
| // | |
| // Search the request Address | |
| // | |
| for (Index = 0; Index < (MemoryMapSize / DescriptorSize); Index++) { | |
| if (((EFI_PHYSICAL_ADDRESS)(UINTN)Address >= MemoryMap->PhysicalStart) && | |
| ((EFI_PHYSICAL_ADDRESS)(UINTN)Address < MemoryMap->PhysicalStart | |
| + LShiftU64 (MemoryMap->NumberOfPages, EFI_PAGE_SHIFT))) { | |
| // | |
| // Found it | |
| // | |
| if (MemoryMap->Attribute & EFI_MEMORY_RUNTIME) { | |
| IsRuntime = TRUE; | |
| } | |
| break; | |
| } | |
| // | |
| // Get next item | |
| // | |
| MemoryMap = (EFI_MEMORY_DESCRIPTOR *)((UINTN)MemoryMap + DescriptorSize); | |
| } | |
| // | |
| // Done | |
| // | |
| gBS->FreePool (MemoryMapPtr); | |
| return IsRuntime; | |
| } | |
| /** | |
| Update mFvbEntry. Add new entry, or update existing entry if Fvb protocol is | |
| reinstalled. | |
| @param Event The Event that is being processed | |
| @param Context Event Context | |
| **/ | |
| STATIC | |
| VOID | |
| EFIAPI | |
| FvbNotificationEvent ( | |
| IN EFI_EVENT Event, | |
| IN VOID *Context | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| UINTN BufferSize; | |
| EFI_HANDLE Handle; | |
| UINTN Index; | |
| UINTN UpdateIndex; | |
| while (TRUE) { | |
| BufferSize = sizeof (Handle); | |
| Status = gBS->LocateHandle ( | |
| ByRegisterNotify, | |
| &gEfiFirmwareVolumeBlockProtocolGuid, | |
| mFvbRegistration, | |
| &BufferSize, | |
| &Handle | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| // | |
| // Exit Path of While Loop.... | |
| // | |
| break; | |
| } | |
| UpdateIndex = MAX_FVB_COUNT; | |
| for (Index = 0; Index < mFvbCount; Index++) { | |
| if (mFvbEntry[Index].Handle == Handle) { | |
| // | |
| // If the handle is already in the table just update the protocol | |
| // | |
| UpdateIndex = Index; | |
| break; | |
| } | |
| } | |
| if (UpdateIndex == MAX_FVB_COUNT) { | |
| // | |
| // Use the next free slot for a new entry | |
| // | |
| UpdateIndex = mFvbCount++; | |
| // | |
| // Check the UpdateIndex whether exceed the maximum value. | |
| // | |
| ASSERT (UpdateIndex < MAX_FVB_COUNT); | |
| mFvbEntry[UpdateIndex].Handle = Handle; | |
| } | |
| // | |
| // The array does not have enough entries | |
| // | |
| ASSERT (UpdateIndex < MAX_FVB_COUNT); | |
| // | |
| // Get the interface pointer and if it's ours, skip it | |
| // | |
| Status = gBS->HandleProtocol ( | |
| Handle, | |
| &gEfiFirmwareVolumeBlockProtocolGuid, | |
| (VOID **) &mFvbEntry[UpdateIndex].Fvb | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| Status = gBS->HandleProtocol ( | |
| Handle, | |
| &gEfiFvbExtensionProtocolGuid, | |
| (VOID **) &mFvbEntry[UpdateIndex].FvbExtension | |
| ); | |
| if (Status != EFI_SUCCESS) { | |
| mFvbEntry[UpdateIndex].FvbExtension = NULL; | |
| } | |
| // | |
| // Check the FVB can be accessed in RUNTIME, The FVBs in FVB handle list comes | |
| // from two way: | |
| // 1) Dxe Core. (FVB information is transferred from FV HOB). | |
| // 2) FVB driver. | |
| // The FVB produced Dxe core is used for discoverying DXE driver and dispatch. These | |
| // FVBs can only be accessed in boot time. | |
| // FVB driver will discovery all FV in FLASH and these FVBs can be accessed in runtime. | |
| // The FVB itself produced by FVB driver is allocated in runtime memory. So we can | |
| // determine the what FVB can be accessed in RUNTIME by judging whether FVB itself is allocated | |
| // in RUNTIME memory. | |
| // | |
| mFvbEntry[UpdateIndex].IsRuntimeAccess = IsRuntimeMemory (mFvbEntry[UpdateIndex].Fvb); | |
| } | |
| } | |
| /** | |
| Convert all pointers in mFvbEntry after ExitBootServices. | |
| @param Event The Event that is being processed | |
| @param Context Event Context | |
| **/ | |
| VOID | |
| EFIAPI | |
| FvbVirtualAddressChangeNotifyEvent ( | |
| IN EFI_EVENT Event, | |
| IN VOID *Context | |
| ) | |
| { | |
| UINTN Index; | |
| if (mFvbEntry != NULL) { | |
| for (Index = 0; Index < MAX_FVB_COUNT; Index++) { | |
| if (!mFvbEntry[Index].IsRuntimeAccess) { | |
| continue; | |
| } | |
| if (NULL != mFvbEntry[Index].Fvb) { | |
| EfiConvertPointer (0x0, (VOID **) &mFvbEntry[Index].Fvb->GetBlockSize); | |
| EfiConvertPointer (0x0, (VOID **) &mFvbEntry[Index].Fvb->GetPhysicalAddress); | |
| EfiConvertPointer (0x0, (VOID **) &mFvbEntry[Index].Fvb->GetVolumeAttributes); | |
| EfiConvertPointer (0x0, (VOID **) &mFvbEntry[Index].Fvb->SetVolumeAttributes); | |
| EfiConvertPointer (0x0, (VOID **) &mFvbEntry[Index].Fvb->Read); | |
| EfiConvertPointer (0x0, (VOID **) &mFvbEntry[Index].Fvb->Write); | |
| EfiConvertPointer (0x0, (VOID **) &mFvbEntry[Index].Fvb->EraseBlocks); | |
| EfiConvertPointer (0x0, (VOID **) &mFvbEntry[Index].Fvb); | |
| } | |
| if (NULL != mFvbEntry[Index].FvbExtension) { | |
| EfiConvertPointer (0x0, (VOID **) &mFvbEntry[Index].FvbExtension->EraseFvbCustomBlock); | |
| EfiConvertPointer (0x0, (VOID **) &mFvbEntry[Index].FvbExtension); | |
| } | |
| } | |
| EfiConvertPointer (0x0, (VOID **) &mFvbEntry); | |
| } | |
| } | |
| /** | |
| Library constructor function entry. | |
| @param ImageHandle The handle of image who call this libary. | |
| @param SystemTable The point of System Table. | |
| @retval EFI_SUCESS Sucess construct this library. | |
| @retval Others Fail to contruct this libary. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| FvbLibInitialize ( | |
| IN EFI_HANDLE ImageHandle, | |
| IN EFI_SYSTEM_TABLE *SystemTable | |
| ) | |
| { | |
| UINTN Status; | |
| mFvbCount = 0; | |
| Status = gBS->AllocatePool ( | |
| EfiRuntimeServicesData, | |
| (UINTN) sizeof (FVB_ENTRY) * MAX_FVB_COUNT, | |
| (VOID *) &mFvbEntry | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| ZeroMem (mFvbEntry, sizeof (FVB_ENTRY) * MAX_FVB_COUNT); | |
| EfiCreateProtocolNotifyEvent ( | |
| &gEfiFirmwareVolumeBlockProtocolGuid, | |
| TPL_CALLBACK, | |
| FvbNotificationEvent, | |
| NULL, | |
| &mFvbRegistration | |
| ); | |
| // | |
| // Register SetVirtualAddressMap () notify function | |
| // | |
| // Status = gBS->CreateEvent ( | |
| // EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE, | |
| // TPL_NOTIFY, | |
| // EfiRuntimeLibFvbVirtualNotifyEvent, | |
| // NULL, | |
| // &mEfiFvbVirtualNotifyEvent | |
| // ); | |
| // ASSERT_EFI_ERROR (Status); | |
| // | |
| // | |
| // Register SetVirtualAddressMap () notify function | |
| // | |
| ASSERT_EFI_ERROR (Status); | |
| mEfiFvbInitialized = TRUE; | |
| return EFI_SUCCESS; | |
| } | |
| // | |
| // ============================================================================= | |
| // The following functions wrap Fvb protocol in the Runtime Lib functions. | |
| // The Instance translates into Fvb instance. The Fvb order defined by HOBs and | |
| // thus the sequence of FVB protocol addition define Instance. | |
| // | |
| // EfiFvbInitialize () must be called before any of the following functions | |
| // must be called. | |
| // ============================================================================= | |
| // | |
| /** | |
| Reads specified number of bytes into a buffer from the specified block | |
| @param Instance The FV instance to be read from. | |
| @param Lba The logical block address to be read from | |
| @param Offset Offset into the block at which to begin reading | |
| @param NumBytes Pointer that on input contains the total size of | |
| the buffer. On output, it contains the total number | |
| of bytes read | |
| @param Buffer Pointer to a caller allocated buffer that will be | |
| used to hold the data read | |
| @retval EFI_INVALID_PARAMETER Invalid parameter | |
| @retval EFI_SUCESS Sucess to Read block | |
| @retval Others Fail to read block | |
| **/ | |
| EFI_STATUS | |
| EfiFvbReadBlock ( | |
| IN UINTN Instance, | |
| IN EFI_LBA Lba, | |
| IN UINTN Offset, | |
| IN OUT UINTN *NumBytes, | |
| IN UINT8 *Buffer | |
| ) | |
| { | |
| if (Instance >= mFvbCount) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| if (EfiAtRuntime() && !mFvbEntry[Instance].IsRuntimeAccess) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| return mFvbEntry[Instance].Fvb->Read (mFvbEntry[Instance].Fvb, Lba, Offset, NumBytes, Buffer); | |
| } | |
| /** | |
| Writes specified number of bytes from the input buffer to the block | |
| @param Instance The FV instance to be written to | |
| @param Lba The starting logical block index to write to | |
| @param Offset Offset into the block at which to begin writing | |
| @param NumBytes Pointer that on input contains the total size of | |
| the buffer. On output, it contains the total number | |
| of bytes actually written | |
| @param Buffer Pointer to a caller allocated buffer that contains | |
| the source for the write | |
| @retval EFI_INVALID_PARAMETER Invalid parameter | |
| @retval EFI_SUCESS Sucess to write block | |
| @retval Others Fail to write block | |
| **/ | |
| EFI_STATUS | |
| EfiFvbWriteBlock ( | |
| IN UINTN Instance, | |
| IN EFI_LBA Lba, | |
| IN UINTN Offset, | |
| IN OUT UINTN *NumBytes, | |
| IN UINT8 *Buffer | |
| ) | |
| { | |
| if (Instance >= mFvbCount) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| if (EfiAtRuntime() && !mFvbEntry[Instance].IsRuntimeAccess) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| return mFvbEntry[Instance].Fvb->Write (mFvbEntry[Instance].Fvb, Lba, Offset, NumBytes, Buffer); | |
| } | |
| /** | |
| Erases and initializes a firmware volume block | |
| @param Instance The FV instance to be erased | |
| @param Lba The logical block index to be erased | |
| @retval EFI_INVALID_PARAMETER Invalid parameter | |
| @retval EFI_SUCESS Sucess to erase block | |
| @retval Others Fail to erase block | |
| **/ | |
| EFI_STATUS | |
| EfiFvbEraseBlock ( | |
| IN UINTN Instance, | |
| IN EFI_LBA Lba | |
| ) | |
| { | |
| if (Instance >= mFvbCount) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| if (EfiAtRuntime() && !mFvbEntry[Instance].IsRuntimeAccess) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| return mFvbEntry[Instance].Fvb->EraseBlocks (mFvbEntry[Instance].Fvb, Lba, -1); | |
| } | |
| /** | |
| Retrieves attributes, insures positive polarity of attribute bits, returns | |
| resulting attributes in output parameter | |
| @param Instance The FV instance whose attributes is going to be returned | |
| @param Attributes Output buffer which contains attributes | |
| @retval EFI_INVALID_PARAMETER Invalid parameter | |
| @retval EFI_SUCESS Sucess to get Fv attribute | |
| @retval Others Fail to get Fv attribute | |
| **/ | |
| EFI_STATUS | |
| EfiFvbGetVolumeAttributes ( | |
| IN UINTN Instance, | |
| OUT EFI_FVB_ATTRIBUTES *Attributes | |
| ) | |
| { | |
| if (Instance >= mFvbCount) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| if (EfiAtRuntime() && !mFvbEntry[Instance].IsRuntimeAccess) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| return mFvbEntry[Instance].Fvb->GetVolumeAttributes (mFvbEntry[Instance].Fvb, Attributes); | |
| } | |
| /** | |
| Modifies the current settings of the firmware volume according to the | |
| input parameter, and returns the new setting of the volume | |
| @param Instance The FV instance whose attributes is going to be | |
| modified | |
| @param Attributes On input, it is a pointer to EFI_FVB_ATTRIBUTES | |
| containing the desired firmware volume settings. | |
| On successful return, it contains the new settings | |
| of the firmware volume | |
| @retval EFI_INVALID_PARAMETER Invalid parameter | |
| @retval EFI_SUCESS Sucess to set Fv attribute | |
| @retval Others Fail to set Fv attribute | |
| **/ | |
| EFI_STATUS | |
| EfiFvbSetVolumeAttributes ( | |
| IN UINTN Instance, | |
| IN EFI_FVB_ATTRIBUTES Attributes | |
| ) | |
| { | |
| if (Instance >= mFvbCount) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| if (EfiAtRuntime() && !mFvbEntry[Instance].IsRuntimeAccess) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| return mFvbEntry[Instance].Fvb->SetVolumeAttributes (mFvbEntry[Instance].Fvb, &Attributes); | |
| } | |
| /** | |
| Retrieves the physical address of a memory mapped FV | |
| @param Instance The FV instance whose base address is going to be | |
| returned | |
| @param BaseAddress Pointer to a caller allocated EFI_PHYSICAL_ADDRESS | |
| that on successful return, contains the base address | |
| of the firmware volume. | |
| @retval EFI_INVALID_PARAMETER Invalid parameter | |
| @retval EFI_SUCESS Sucess to get physical address | |
| @retval Others Fail to get physical address | |
| **/ | |
| EFI_STATUS | |
| EfiFvbGetPhysicalAddress ( | |
| IN UINTN Instance, | |
| OUT EFI_PHYSICAL_ADDRESS *BaseAddress | |
| ) | |
| { | |
| if (Instance >= mFvbCount) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| if (EfiAtRuntime() && !mFvbEntry[Instance].IsRuntimeAccess) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| return mFvbEntry[Instance].Fvb->GetPhysicalAddress (mFvbEntry[Instance].Fvb, BaseAddress); | |
| } | |
| /** | |
| Retrieve the size of a logical block | |
| @param Instance The FV instance whose block size is going to be | |
| returned | |
| @param Lba Indicates which block to return the size for. | |
| @param BlockSize A pointer to a caller allocated UINTN in which | |
| the size of the block is returned | |
| @param NumOfBlocks a pointer to a caller allocated UINTN in which the | |
| number of consecutive blocks starting with Lba is | |
| returned. All blocks in this range have a size of | |
| BlockSize | |
| @retval EFI_INVALID_PARAMETER Invalid parameter | |
| @retval EFI_SUCESS Sucess to get block size | |
| @retval Others Fail to get block size | |
| **/ | |
| EFI_STATUS | |
| EfiFvbGetBlockSize ( | |
| IN UINTN Instance, | |
| IN EFI_LBA Lba, | |
| OUT UINTN *BlockSize, | |
| OUT UINTN *NumOfBlocks | |
| ) | |
| { | |
| if (Instance >= mFvbCount) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| if (EfiAtRuntime() && !mFvbEntry[Instance].IsRuntimeAccess) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| return mFvbEntry[Instance].Fvb->GetBlockSize (mFvbEntry[Instance].Fvb, Lba, BlockSize, NumOfBlocks); | |
| } | |
| /** | |
| Erases and initializes a specified range of a firmware volume | |
| @param Instance The FV instance to be erased | |
| @param StartLba The starting logical block index to be erased | |
| @param OffsetStartLba Offset into the starting block at which to | |
| begin erasing | |
| @param LastLba The last logical block index to be erased | |
| @param OffsetLastLba Offset into the last block at which to end erasing | |
| @retval EFI_INVALID_PARAMETER Invalid parameter | |
| @retval EFI_SUCESS Sucess to erase custom block range | |
| @retval Others Fail to erase custom block range | |
| **/ | |
| EFI_STATUS | |
| EfiFvbEraseCustomBlockRange ( | |
| IN UINTN Instance, | |
| IN EFI_LBA StartLba, | |
| IN UINTN OffsetStartLba, | |
| IN EFI_LBA LastLba, | |
| IN UINTN OffsetLastLba | |
| ) | |
| { | |
| if (Instance >= mFvbCount) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| if (EfiAtRuntime() && !mFvbEntry[Instance].IsRuntimeAccess) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| if (!(mFvbEntry[Instance].FvbExtension)) { | |
| return EFI_UNSUPPORTED; | |
| } | |
| if (!(mFvbEntry[Instance].FvbExtension->EraseFvbCustomBlock)) { | |
| return EFI_UNSUPPORTED; | |
| } | |
| return mFvbEntry[Instance].FvbExtension->EraseFvbCustomBlock ( | |
| mFvbEntry[Instance].FvbExtension, | |
| StartLba, | |
| OffsetStartLba, | |
| LastLba, | |
| OffsetLastLba | |
| ); | |
| } |