EFI_STATUS EFIAPI NorFlashFvbInitialize ( IN NOR_FLASH_INSTANCE* Instance ) { EFI_STATUS Status; UINT32 FvbNumLba; EFI_BOOT_MODE BootMode; DEBUG((DEBUG_BLKIO,"NorFlashFvbInitialize\n")); Instance->Initialized = TRUE; // Set the index of the first LBA for the FVB Instance->StartLba = (PcdGet32 (PcdFlashNvStorageVariableBase) - Instance->RegionBaseAddress) / Instance->Media.BlockSize; BootMode = GetBootModeHob (); if (BootMode == BOOT_WITH_DEFAULT_SETTINGS) { Status = EFI_INVALID_PARAMETER; } else { // Determine if there is a valid header at the beginning of the NorFlash Status = ValidateFvHeader (Instance); } // Install the Default FVB header if required if (EFI_ERROR(Status)) { // There is no valid header, so time to install one. DEBUG((EFI_D_ERROR,"NorFlashFvbInitialize: ERROR - The FVB Header is not valid. Installing a correct one for this volume.\n")); // Erase all the NorFlash that is reserved for variable storage FvbNumLba = (PcdGet32(PcdFlashNvStorageVariableSize) + PcdGet32(PcdFlashNvStorageFtwWorkingSize) + PcdGet32(PcdFlashNvStorageFtwSpareSize)) / Instance->Media.BlockSize; Status = FvbEraseBlocks (&Instance->FvbProtocol, (EFI_LBA)0, FvbNumLba, EFI_LBA_LIST_TERMINATOR); if (EFI_ERROR(Status)) { return Status; } // Install all appropriate headers Status = InitializeFvAndVariableStoreHeaders (Instance); if (EFI_ERROR(Status)) { return Status; } } return Status; }
/** Main entry point. @param[in] ImageHandle The firmware allocated handle for the EFI image. @param[in] SystemTable A pointer to the EFI System Table. @retval EFI_SUCCESS Successfully initialized. **/ EFI_STATUS EFIAPI FvbInitialize ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_STATUS Status; VOID *Ptr; VOID *SubPtr; BOOLEAN Initialize; EFI_HANDLE Handle; EFI_PHYSICAL_ADDRESS Address; RETURN_STATUS PcdStatus; DEBUG ((EFI_D_INFO, "EMU Variable FVB Started\n")); // // Verify that the PCD's are set correctly. // if ( (PcdGet32 (PcdVariableStoreSize) + PcdGet32 (PcdFlashNvStorageFtwWorkingSize) ) > EMU_FVB_BLOCK_SIZE ) { DEBUG ((EFI_D_ERROR, "EMU Variable invalid PCD sizes\n")); return EFI_INVALID_PARAMETER; } if (PcdGet64 (PcdFlashNvStorageVariableBase64) != 0) { DEBUG ((EFI_D_INFO, "Disabling EMU Variable FVB since " "flash variables appear to be supported.\n")); return EFI_ABORTED; } // // By default we will initialize the FV contents. But, if // PcdEmuVariableNvStoreReserved is non-zero, then we will // use this location for our buffer. // // If this location does not have a proper FV header, then // we will initialize it. // Initialize = TRUE; if (PcdGet64 (PcdEmuVariableNvStoreReserved) != 0) { Ptr = (VOID*)(UINTN) PcdGet64 (PcdEmuVariableNvStoreReserved); DEBUG (( EFI_D_INFO, "EMU Variable FVB: Using pre-reserved block at %p\n", Ptr )); Status = ValidateFvHeader (Ptr); if (!EFI_ERROR (Status)) { DEBUG ((EFI_D_INFO, "EMU Variable FVB: Found valid pre-existing FV\n")); Initialize = FALSE; } } else { Ptr = AllocateAlignedRuntimePages ( EFI_SIZE_TO_PAGES (EMU_FVB_SIZE), SIZE_64KB ); } mEmuVarsFvb.BufferPtr = Ptr; // // Initialize the main FV header and variable store header // if (Initialize) { SetMem (Ptr, EMU_FVB_SIZE, ERASED_UINT8); InitializeFvAndVariableStoreHeaders (Ptr); } PcdStatus = PcdSet64S (PcdFlashNvStorageVariableBase64, (UINT32)(UINTN) Ptr); ASSERT_RETURN_ERROR (PcdStatus); // // Initialize the Fault Tolerant Write data area // SubPtr = (VOID*) ((UINT8*) Ptr + PcdGet32 (PcdVariableStoreSize)); PcdStatus = PcdSet32S (PcdFlashNvStorageFtwWorkingBase, (UINT32)(UINTN) SubPtr); ASSERT_RETURN_ERROR (PcdStatus); // // Initialize the Fault Tolerant Write spare block // SubPtr = (VOID*) ((UINT8*) Ptr + EMU_FVB_BLOCK_SIZE); PcdStatus = PcdSet32S (PcdFlashNvStorageFtwSpareBase, (UINT32)(UINTN) SubPtr); ASSERT_RETURN_ERROR (PcdStatus); // // Setup FVB device path // Address = (EFI_PHYSICAL_ADDRESS)(UINTN) Ptr; mEmuVarsFvb.DevicePath.MemMapDevPath.StartingAddress = Address; mEmuVarsFvb.DevicePath.MemMapDevPath.EndingAddress = Address + EMU_FVB_SIZE - 1; // // Install the protocols // DEBUG ((EFI_D_INFO, "Installing FVB for EMU Variable support\n")); Handle = 0; Status = gBS->InstallMultipleProtocolInterfaces ( &Handle, &gEfiFirmwareVolumeBlock2ProtocolGuid, &mEmuVarsFvb.FwVolBlockInstance, &gEfiDevicePathProtocolGuid, &mEmuVarsFvb.DevicePath, NULL ); ASSERT_EFI_ERROR (Status); // // Register for the virtual address change event // Status = gBS->CreateEventEx ( EVT_NOTIFY_SIGNAL, TPL_NOTIFY, FvbVirtualAddressChangeEvent, NULL, &gEfiEventVirtualAddressChangeGuid, &mEmuVarsFvbAddrChangeEvent ); ASSERT_EFI_ERROR (Status); return EFI_SUCCESS; }
EFI_STATUS EFIAPI FvbInitialize ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) /*++ Routine Description: This function does common initialization for FVB services Arguments: Returns: **/ { EFI_STATUS Status; EFI_FW_VOL_INSTANCE *FwhInstance = NULL; EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; EFI_DXE_SERVICES *DxeServices; EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor; UINT32 BufferSize; EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry; EFI_HANDLE FwbHandle; EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *OldFwbInterface; EFI_DEVICE_PATH_PROTOCOL *TempFwbDevicePath; FV_DEVICE_PATH TempFvbDevicePathData; UINT32 MaxLbaSize; EFI_PHYSICAL_ADDRESS BaseAddress; UINT64 Length; UINTN NumOfBlocks; EFI_PEI_HOB_POINTERS FvHob; // // Get the DXE services table // DxeServices = gDS; // // Allocate runtime services data for global variable, which contains // the private data of all firmware volume block instances // Status = gBS->AllocatePool ( EfiRuntimeServicesData, sizeof (ESAL_FWB_GLOBAL), (VOID**) &mFvbModuleGlobal ); ASSERT_EFI_ERROR (Status); // // Calculate the total size for all firmware volume block instances // BufferSize = 0; FvHob.Raw = GetHobList (); while ((FvHob.Raw = GetNextHob (EFI_HOB_TYPE_FV, FvHob.Raw)) != NULL) { BaseAddress = FvHob.FirmwareVolume->BaseAddress; Length = FvHob.FirmwareVolume->Length; // // Check if it is a "real" flash // Status = DxeServices->GetMemorySpaceDescriptor ( BaseAddress, &Descriptor ); if (EFI_ERROR (Status)) { break; } if (Descriptor.GcdMemoryType != EfiGcdMemoryTypeMemoryMappedIo) { FvHob.Raw = GET_NEXT_HOB (FvHob); continue; } FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) BaseAddress; Status = ValidateFvHeader (FwVolHeader); if (EFI_ERROR (Status)) { // // Get FvbInfo // Status = GetFvbInfo (Length, &FwVolHeader); if (EFI_ERROR (Status)) { FvHob.Raw = GET_NEXT_HOB (FvHob); continue; } } BufferSize += (sizeof (EFI_FW_VOL_INSTANCE) + FwVolHeader->HeaderLength - sizeof (EFI_FIRMWARE_VOLUME_HEADER)); FvHob.Raw = GET_NEXT_HOB (FvHob); } // // Only need to allocate once. There is only one copy of physical memory for // the private data of each FV instance. But in virtual mode or in physical // mode, the address of the the physical memory may be different. // Status = gBS->AllocatePool ( EfiRuntimeServicesData, BufferSize, (VOID**) &mFvbModuleGlobal->FvInstance[FVB_PHYSICAL] ); ASSERT_EFI_ERROR (Status); // // Make a virtual copy of the FvInstance pointer. // FwhInstance = mFvbModuleGlobal->FvInstance[FVB_PHYSICAL]; mFvbModuleGlobal->FvInstance[FVB_VIRTUAL] = FwhInstance; mFvbModuleGlobal->NumFv = 0; MaxLbaSize = 0; FvHob.Raw = GetHobList (); while (NULL != (FvHob.Raw = GetNextHob (EFI_HOB_TYPE_FV, FvHob.Raw))) { BaseAddress = FvHob.FirmwareVolume->BaseAddress; Length = FvHob.FirmwareVolume->Length; // // Check if it is a "real" flash // Status = DxeServices->GetMemorySpaceDescriptor ( BaseAddress, &Descriptor ); if (EFI_ERROR (Status)) { break; } if (Descriptor.GcdMemoryType != EfiGcdMemoryTypeMemoryMappedIo) { FvHob.Raw = GET_NEXT_HOB (FvHob); continue; } FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) BaseAddress; Status = ValidateFvHeader (FwVolHeader); if (EFI_ERROR (Status)) { // // Get FvbInfo to provide in FwhInstance. // Status = GetFvbInfo (Length, &FwVolHeader); if (EFI_ERROR (Status)) { FvHob.Raw = GET_NEXT_HOB (FvHob); continue; } // // Write healthy FV header back. // CopyMem ( (VOID *) (UINTN) BaseAddress, (VOID *) FwVolHeader, FwVolHeader->HeaderLength ); } FwhInstance->FvBase[FVB_PHYSICAL] = (UINTN) BaseAddress; FwhInstance->FvBase[FVB_VIRTUAL] = (UINTN) BaseAddress; CopyMem ((UINTN *) &(FwhInstance->VolumeHeader), (UINTN *) FwVolHeader, FwVolHeader->HeaderLength); FwVolHeader = &(FwhInstance->VolumeHeader); EfiInitializeLock (&(FwhInstance->FvbDevLock), TPL_HIGH_LEVEL); NumOfBlocks = 0; for (PtrBlockMapEntry = FwVolHeader->BlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) { // // Get the maximum size of a block. The size will be used to allocate // buffer for Scratch space, the intermediate buffer for FVB extension // protocol // if (MaxLbaSize < PtrBlockMapEntry->Length) { MaxLbaSize = PtrBlockMapEntry->Length; } NumOfBlocks = NumOfBlocks + PtrBlockMapEntry->NumBlocks; } // // The total number of blocks in the FV. // FwhInstance->NumOfBlocks = NumOfBlocks; // // Add a FVB Protocol Instance // Status = gBS->AllocatePool ( EfiRuntimeServicesData, sizeof (EFI_FW_VOL_BLOCK_DEVICE), (VOID**) &FvbDevice ); ASSERT_EFI_ERROR (Status); CopyMem (FvbDevice, &mFvbDeviceTemplate, sizeof (EFI_FW_VOL_BLOCK_DEVICE)); FvbDevice->Instance = mFvbModuleGlobal->NumFv; mFvbModuleGlobal->NumFv++; // // Set up the devicepath // FvbDevice->DevicePath.MemMapDevPath.StartingAddress = BaseAddress; FvbDevice->DevicePath.MemMapDevPath.EndingAddress = BaseAddress + (FwVolHeader->FvLength - 1); // // Find a handle with a matching device path that has supports FW Block protocol // TempFwbDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) &TempFvbDevicePathData; CopyMem (TempFwbDevicePath, &FvbDevice->DevicePath, sizeof (FV_DEVICE_PATH)); Status = gBS->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid, &TempFwbDevicePath, &FwbHandle); if (EFI_ERROR (Status)) { // // LocateDevicePath fails so install a new interface and device path // FwbHandle = NULL; Status = gBS->InstallMultipleProtocolInterfaces ( &FwbHandle, &gEfiFirmwareVolumeBlockProtocolGuid, &FvbDevice->FwVolBlockInstance, &gEfiDevicePathProtocolGuid, &FvbDevice->DevicePath, NULL ); ASSERT_EFI_ERROR (Status); } else if (IsDevicePathEnd (TempFwbDevicePath)) { // // Device allready exists, so reinstall the FVB protocol // Status = gBS->HandleProtocol ( FwbHandle, &gEfiFirmwareVolumeBlockProtocolGuid, (VOID**)&OldFwbInterface ); ASSERT_EFI_ERROR (Status); Status = gBS->ReinstallProtocolInterface ( FwbHandle, &gEfiFirmwareVolumeBlockProtocolGuid, OldFwbInterface, &FvbDevice->FwVolBlockInstance ); ASSERT_EFI_ERROR (Status); } else { // // There was a FVB protocol on an End Device Path node // ASSERT (FALSE); } FwhInstance = (EFI_FW_VOL_INSTANCE *) ( (UINTN) ((UINT8 *) FwhInstance) + FwVolHeader->HeaderLength + (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER)) ); FvHob.Raw = GET_NEXT_HOB (FvHob); } return EFI_SUCCESS; }
EFI_STATUS EFIAPI NorFlashFvbInitialize ( IN NOR_FLASH_INSTANCE* Instance ) { EFI_STATUS Status; UINT32 FvbNumLba; EFI_BOOT_MODE BootMode; UINTN RuntimeMmioRegionSize; DEBUG((DEBUG_BLKIO,"NorFlashFvbInitialize\n")); ASSERT((Instance != NULL)); // // Declare the Non-Volatile storage as EFI_MEMORY_RUNTIME // // Note: all the NOR Flash region needs to be reserved into the UEFI Runtime memory; // even if we only use the small block region at the top of the NOR Flash. // The reason is when the NOR Flash memory is set into program mode, the command // is written as the base of the flash region (ie: Instance->DeviceBaseAddress) RuntimeMmioRegionSize = (Instance->RegionBaseAddress - Instance->DeviceBaseAddress) + Instance->Size; Status = gDS->AddMemorySpace ( EfiGcdMemoryTypeMemoryMappedIo, Instance->DeviceBaseAddress, RuntimeMmioRegionSize, EFI_MEMORY_UC | EFI_MEMORY_RUNTIME ); ASSERT_EFI_ERROR (Status); Status = gDS->SetMemorySpaceAttributes ( Instance->DeviceBaseAddress, RuntimeMmioRegionSize, EFI_MEMORY_UC | EFI_MEMORY_RUNTIME); ASSERT_EFI_ERROR (Status); mFlashNvStorageVariableBase = FixedPcdGet32 (PcdFlashNvStorageVariableBase); // Set the index of the first LBA for the FVB Instance->StartLba = (PcdGet32 (PcdFlashNvStorageVariableBase) - Instance->RegionBaseAddress) / Instance->Media.BlockSize; BootMode = GetBootModeHob (); if (BootMode == BOOT_WITH_DEFAULT_SETTINGS) { Status = EFI_INVALID_PARAMETER; } else { // Determine if there is a valid header at the beginning of the NorFlash Status = ValidateFvHeader (Instance); } // Install the Default FVB header if required if (EFI_ERROR(Status)) { // There is no valid header, so time to install one. DEBUG ((EFI_D_INFO, "%a: The FVB Header is not valid.\n", __FUNCTION__)); DEBUG ((EFI_D_INFO, "%a: Installing a correct one for this volume.\n", __FUNCTION__)); // Erase all the NorFlash that is reserved for variable storage FvbNumLba = (PcdGet32(PcdFlashNvStorageVariableSize) + PcdGet32(PcdFlashNvStorageFtwWorkingSize) + PcdGet32(PcdFlashNvStorageFtwSpareSize)) / Instance->Media.BlockSize; Status = FvbEraseBlocks (&Instance->FvbProtocol, (EFI_LBA)0, FvbNumLba, EFI_LBA_LIST_TERMINATOR); if (EFI_ERROR(Status)) { return Status; } // Install all appropriate headers Status = InitializeFvAndVariableStoreHeaders (Instance); if (EFI_ERROR(Status)) { return Status; } } // // The driver implementing the variable read service can now be dispatched; // the varstore headers are in place. // Status = gBS->InstallProtocolInterface ( &gImageHandle, &gEdkiiNvVarStoreFormattedGuid, EFI_NATIVE_INTERFACE, NULL ); ASSERT_EFI_ERROR (Status); // // Register for the virtual address change event // Status = gBS->CreateEventEx ( EVT_NOTIFY_SIGNAL, TPL_NOTIFY, FvbVirtualNotifyEvent, NULL, &gEfiEventVirtualAddressChangeGuid, &mFvbVirtualAddrChangeEvent ); ASSERT_EFI_ERROR (Status); return Status; }