/** Check the integrity of firmware volume header @param[in] FwVolHeader A pointer to a firmware volume header @retval TRUE The firmware volume is consistent @retval FALSE The firmware volume has corrupted. **/ STATIC BOOLEAN IsFvHeaderValid ( IN EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader ) { UINT16 Checksum; // Skip nv storage fv if (CompareMem (&FwVolHeader->FileSystemGuid, &gEfiFirmwareFileSystem2Guid, sizeof(EFI_GUID)) != 0 ) { return FALSE; } if ( (FwVolHeader->Revision != EFI_FVH_REVISION) || (FwVolHeader->Signature != EFI_FVH_SIGNATURE) || (FwVolHeader->FvLength == ((UINTN) -1)) || ((FwVolHeader->HeaderLength & 0x01 ) !=0) ) { return FALSE; } Checksum = CalculateCheckSum16 ((UINT16 *) FwVolHeader, FwVolHeader->HeaderLength); if (Checksum != 0) { DEBUG (( DEBUG_ERROR, "ERROR - Invalid Firmware Volume Header Checksum, change 0x%04x to 0x%04x\r\n", FwVolHeader->Checksum, (UINT16)( Checksum + FwVolHeader->Checksum ))); return FALSE; } return TRUE; }
EFI_STATUS GetFvbInfo ( IN UINT64 FvLength, OUT EFI_FIRMWARE_VOLUME_HEADER **FvbInfo ) { STATIC BOOLEAN Checksummed = FALSE; UINTN Index; if (!Checksummed) { for (Index = 0; Index < sizeof (mPlatformFvbMediaInfo) / sizeof (EFI_FVB_MEDIA_INFO); Index += 1) { UINT16 Checksum; mPlatformFvbMediaInfo[Index].FvbInfo.Checksum = 0; Checksum = CalculateCheckSum16 ( (UINT16*) &mPlatformFvbMediaInfo[Index].FvbInfo, mPlatformFvbMediaInfo[Index].FvbInfo.HeaderLength ); mPlatformFvbMediaInfo[Index].FvbInfo.Checksum = Checksum; } Checksummed = TRUE; } for (Index = 0; Index < sizeof (mPlatformFvbMediaInfo) / sizeof (EFI_FVB_MEDIA_INFO); Index += 1) { if (mPlatformFvbMediaInfo[Index].FvLength == FvLength) { *FvbInfo = &mPlatformFvbMediaInfo[Index].FvbInfo; return EFI_SUCCESS; } } return EFI_NOT_FOUND; }
EFI_STATUS ValidateFvHeader ( EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader ) /*++ Routine Description: Check the integrity of firmware volume header Arguments: FwVolHeader - A pointer to a firmware volume header Returns: EFI_SUCCESS - The firmware volume is consistent EFI_NOT_FOUND - The firmware volume has corrupted. So it is not an FV --*/ { // // Verify the header revision, header signature, length // Length of FvBlock cannot be 2**64-1 // HeaderLength cannot be an odd number // if ((FwVolHeader->Revision != EFI_FVH_REVISION) || (FwVolHeader->Signature != EFI_FVH_SIGNATURE) || (FwVolHeader->FvLength == ((UINTN) -1)) || ((FwVolHeader->HeaderLength & 0x01) != 0) ) { return EFI_NOT_FOUND; } // // Verify the header checksum // if (CalculateCheckSum16 ((UINT16 *) FwVolHeader, FwVolHeader->HeaderLength) != 0) { return EFI_NOT_FOUND; } return EFI_SUCCESS; }
/** Check the integrity of firmware volume header @param[in] FwVolHeader A pointer to a firmware volume header @retval TRUE The firmware volume is consistent @retval FALSE The firmware volume has corrupted. **/ STATIC BOOLEAN IsFvHeaderValid ( IN EFI_PHYSICAL_ADDRESS FvBase, IN CONST EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader ) { UINT16 Checksum; if (FvBase == PcdGet32(PcdFlashNvStorageVariableBase)) { if (CompareMem (&FwVolHeader->FileSystemGuid, &gEfiSystemNvDataFvGuid, sizeof(EFI_GUID)) != 0 ) { return FALSE; } } else { if (CompareMem (&FwVolHeader->FileSystemGuid, &gEfiFirmwareFileSystem2Guid, sizeof(EFI_GUID)) != 0 ) { return FALSE; } } if ((FwVolHeader->Revision != EFI_FVH_REVISION) || (FwVolHeader->Signature != EFI_FVH_SIGNATURE) || (FwVolHeader->FvLength == ((UINTN) -1)) || ((FwVolHeader->HeaderLength & 0x01 ) !=0)) { return FALSE; } Checksum = CalculateCheckSum16 ((UINT16 *) FwVolHeader, FwVolHeader->HeaderLength); if (Checksum != 0) { DEBUG (( DEBUG_ERROR, "ERROR - Invalid Firmware Volume Header Checksum, change 0x%04x to 0x%04x\r\n", FwVolHeader->Checksum, (UINT16)( Checksum + FwVolHeader->Checksum ))); return FALSE; } return TRUE; }
/** Initializes the FV Header and Variable Store Header to support variable operations. @param[in] Ptr - Location to initialize the headers **/ VOID InitializeFvAndVariableStoreHeaders ( IN VOID *Ptr ) { // // Templates for standard (non-authenticated) variable FV header // STATIC FVB_FV_HDR_AND_VARS_TEMPLATE FvAndVarTemplate = { { // EFI_FIRMWARE_VOLUME_HEADER FvHdr; // UINT8 ZeroVector[16]; { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // EFI_GUID FileSystemGuid; EFI_SYSTEM_NV_DATA_FV_GUID, // UINT64 FvLength; EMU_FVB_SIZE, // UINT32 Signature; EFI_FVH_SIGNATURE, // EFI_FVB_ATTRIBUTES_2 Attributes; 0x4feff, // UINT16 HeaderLength; EMU_FV_HEADER_LENGTH, // UINT16 Checksum; 0, // UINT16 ExtHeaderOffset; 0, // UINT8 Reserved[1]; {0}, // UINT8 Revision; EFI_FVH_REVISION, // EFI_FV_BLOCK_MAP_ENTRY BlockMap[1]; { { 2, // UINT32 NumBlocks; EMU_FVB_BLOCK_SIZE // UINT32 Length; } } }, // EFI_FV_BLOCK_MAP_ENTRY EndBlockMap; { 0, 0 }, // End of block map { // VARIABLE_STORE_HEADER VarHdr; // EFI_GUID Signature; EFI_VARIABLE_GUID, // UINT32 Size; ( FixedPcdGet32 (PcdVariableStoreSize) - OFFSET_OF (FVB_FV_HDR_AND_VARS_TEMPLATE, VarHdr) ), // UINT8 Format; VARIABLE_STORE_FORMATTED, // UINT8 State; VARIABLE_STORE_HEALTHY, // UINT16 Reserved; 0, // UINT32 Reserved1; 0 } }; // // Templates for authenticated variable FV header // STATIC FVB_FV_HDR_AND_VARS_TEMPLATE FvAndAuthenticatedVarTemplate = { { // EFI_FIRMWARE_VOLUME_HEADER FvHdr; // UINT8 ZeroVector[16]; { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // EFI_GUID FileSystemGuid; EFI_SYSTEM_NV_DATA_FV_GUID, // UINT64 FvLength; EMU_FVB_SIZE, // UINT32 Signature; EFI_FVH_SIGNATURE, // EFI_FVB_ATTRIBUTES_2 Attributes; 0x4feff, // UINT16 HeaderLength; EMU_FV_HEADER_LENGTH, // UINT16 Checksum; 0, // UINT16 ExtHeaderOffset; 0, // UINT8 Reserved[1]; {0}, // UINT8 Revision; EFI_FVH_REVISION, // EFI_FV_BLOCK_MAP_ENTRY BlockMap[1]; { { 2, // UINT32 NumBlocks; EMU_FVB_BLOCK_SIZE // UINT32 Length; } } }, // EFI_FV_BLOCK_MAP_ENTRY EndBlockMap; { 0, 0 }, // End of block map { // VARIABLE_STORE_HEADER VarHdr; // EFI_GUID Signature; // need authenticated variables for secure boot EFI_AUTHENTICATED_VARIABLE_GUID, // UINT32 Size; ( FixedPcdGet32 (PcdVariableStoreSize) - OFFSET_OF (FVB_FV_HDR_AND_VARS_TEMPLATE, VarHdr) ), // UINT8 Format; VARIABLE_STORE_FORMATTED, // UINT8 State; VARIABLE_STORE_HEALTHY, // UINT16 Reserved; 0, // UINT32 Reserved1; 0 } }; EFI_FIRMWARE_VOLUME_HEADER *Fv; // // Copy the template structure into the location // if (FeaturePcdGet (PcdSecureBootEnable) == FALSE) { CopyMem (Ptr, (VOID*)&FvAndVarTemplate, sizeof (FvAndVarTemplate)); } else { CopyMem (Ptr, (VOID*)&FvAndAuthenticatedVarTemplate, sizeof (FvAndAuthenticatedVarTemplate)); } // // Update the checksum for the FV header // Fv = (EFI_FIRMWARE_VOLUME_HEADER*) Ptr; Fv->Checksum = CalculateCheckSum16 (Ptr, Fv->HeaderLength); }
/** Initialises the FV Header and Variable Store Header to support variable operations. @param[in] Ptr - Location to initialise the headers **/ EFI_STATUS InitializeFvAndVariableStoreHeaders ( IN NOR_FLASH_INSTANCE *Instance ) { EFI_STATUS Status; VOID* Headers; UINTN HeadersLength; EFI_FIRMWARE_VOLUME_HEADER *FirmwareVolumeHeader; VARIABLE_STORE_HEADER *VariableStoreHeader; if (!Instance->Initialized && Instance->Initialize) { Instance->Initialize (Instance); } HeadersLength = sizeof(EFI_FIRMWARE_VOLUME_HEADER) + sizeof(EFI_FV_BLOCK_MAP_ENTRY) + sizeof(VARIABLE_STORE_HEADER); Headers = AllocateZeroPool(HeadersLength); // FirmwareVolumeHeader->FvLength is declared to have the Variable area AND the FTW working area AND the FTW Spare contiguous. ASSERT(PcdGet32(PcdFlashNvStorageVariableBase) + PcdGet32(PcdFlashNvStorageVariableSize) == PcdGet32(PcdFlashNvStorageFtwWorkingBase)); ASSERT(PcdGet32(PcdFlashNvStorageFtwWorkingBase) + PcdGet32(PcdFlashNvStorageFtwWorkingSize) == PcdGet32(PcdFlashNvStorageFtwSpareBase)); // Check if the size of the area is at least one block size ASSERT((PcdGet32(PcdFlashNvStorageVariableSize) > 0) && (PcdGet32(PcdFlashNvStorageVariableSize) / Instance->Media.BlockSize > 0)); ASSERT((PcdGet32(PcdFlashNvStorageFtwWorkingSize) > 0) && (PcdGet32(PcdFlashNvStorageFtwWorkingSize) / Instance->Media.BlockSize > 0)); ASSERT((PcdGet32(PcdFlashNvStorageFtwSpareSize) > 0) && (PcdGet32(PcdFlashNvStorageFtwSpareSize) / Instance->Media.BlockSize > 0)); // Ensure the Variable area Base Addresses are aligned on a block size boundaries ASSERT(PcdGet32(PcdFlashNvStorageVariableBase) % Instance->Media.BlockSize == 0); ASSERT(PcdGet32(PcdFlashNvStorageFtwWorkingBase) % Instance->Media.BlockSize == 0); ASSERT(PcdGet32(PcdFlashNvStorageFtwSpareBase) % Instance->Media.BlockSize == 0); // // EFI_FIRMWARE_VOLUME_HEADER // FirmwareVolumeHeader = (EFI_FIRMWARE_VOLUME_HEADER*)Headers; CopyGuid (&FirmwareVolumeHeader->FileSystemGuid, &gEfiSystemNvDataFvGuid); FirmwareVolumeHeader->FvLength = PcdGet32(PcdFlashNvStorageVariableSize) + PcdGet32(PcdFlashNvStorageFtwWorkingSize) + PcdGet32(PcdFlashNvStorageFtwSpareSize); FirmwareVolumeHeader->Signature = EFI_FVH_SIGNATURE; FirmwareVolumeHeader->Attributes = (EFI_FVB_ATTRIBUTES_2) ( EFI_FVB2_READ_ENABLED_CAP | // Reads may be enabled EFI_FVB2_READ_STATUS | // Reads are currently enabled EFI_FVB2_STICKY_WRITE | // A block erase is required to flip bits into EFI_FVB2_ERASE_POLARITY EFI_FVB2_MEMORY_MAPPED | // It is memory mapped EFI_FVB2_ERASE_POLARITY | // After erasure all bits take this value (i.e. '1') EFI_FVB2_WRITE_STATUS | // Writes are currently enabled EFI_FVB2_WRITE_ENABLED_CAP // Writes may be enabled ); FirmwareVolumeHeader->HeaderLength = sizeof(EFI_FIRMWARE_VOLUME_HEADER) + sizeof(EFI_FV_BLOCK_MAP_ENTRY); FirmwareVolumeHeader->Revision = EFI_FVH_REVISION; FirmwareVolumeHeader->BlockMap[0].NumBlocks = Instance->Media.LastBlock + 1; FirmwareVolumeHeader->BlockMap[0].Length = Instance->Media.BlockSize; FirmwareVolumeHeader->BlockMap[1].NumBlocks = 0; FirmwareVolumeHeader->BlockMap[1].Length = 0; FirmwareVolumeHeader->Checksum = CalculateCheckSum16 ((UINT16*)FirmwareVolumeHeader,FirmwareVolumeHeader->HeaderLength); // // VARIABLE_STORE_HEADER // VariableStoreHeader = (VARIABLE_STORE_HEADER*)((UINTN)Headers + FirmwareVolumeHeader->HeaderLength); CopyGuid (&VariableStoreHeader->Signature, &gEfiVariableGuid); VariableStoreHeader->Size = PcdGet32(PcdFlashNvStorageVariableSize) - FirmwareVolumeHeader->HeaderLength; VariableStoreHeader->Format = VARIABLE_STORE_FORMATTED; VariableStoreHeader->State = VARIABLE_STORE_HEALTHY; // Install the combined super-header in the NorFlash Status = FvbWrite (&Instance->FvbProtocol, 0, 0, &HeadersLength, Headers); FreePool (Headers); return Status; }