Exemple #1
0
/**
  Check if an FV is consistent and allocate cache for it.

  @param  FvDevice              A pointer to the FvDevice to be checked.

  @retval EFI_OUT_OF_RESOURCES  No enough buffer could be allocated.
  @retval EFI_SUCCESS           FV is consistent and cache is allocated.
  @retval EFI_VOLUME_CORRUPTED  File system is corrupted.

**/
EFI_STATUS
FvCheck (
  IN OUT FV_DEVICE  *FvDevice
  )
{
  EFI_STATUS                            Status;
  EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL    *Fvb;
  EFI_FIRMWARE_VOLUME_HEADER            *FwVolHeader;
  EFI_FIRMWARE_VOLUME_EXT_HEADER        *FwVolExtHeader;
  EFI_FVB_ATTRIBUTES_2                  FvbAttributes;
  EFI_FV_BLOCK_MAP_ENTRY                *BlockMap;
  FFS_FILE_LIST_ENTRY                   *FfsFileEntry;
  EFI_FFS_FILE_HEADER                   *FfsHeader;
  UINT8                                 *CacheLocation;
  UINTN                                 LbaOffset;
  UINTN                                 HeaderSize;
  UINTN                                 Index;
  EFI_LBA                               LbaIndex;
  UINTN                                 Size;
  EFI_FFS_FILE_STATE                    FileState;
  UINT8                                 *TopFvAddress;
  UINTN                                 TestLength;
  EFI_PHYSICAL_ADDRESS                  PhysicalAddress;
  BOOLEAN                               FileCached;
  UINTN                                 WholeFileSize;
  EFI_FFS_FILE_HEADER                   *CacheFfsHeader;

  FileCached = FALSE;
  CacheFfsHeader = NULL;

  Fvb = FvDevice->Fvb;
  FwVolHeader = FvDevice->FwVolHeader;

  Status = Fvb->GetAttributes (Fvb, &FvbAttributes);
  if (EFI_ERROR (Status)) {
    return Status;
  }

  //
  // Size is the size of the FV minus the head. We have already allocated
  // the header to check to make sure the volume is valid
  //
  Size = (UINTN)(FwVolHeader->FvLength - FwVolHeader->HeaderLength);
  if ((FvbAttributes & EFI_FVB2_MEMORY_MAPPED) != 0) {
    FvDevice->IsMemoryMapped = TRUE;

    Status = Fvb->GetPhysicalAddress (Fvb, &PhysicalAddress);
    if (EFI_ERROR (Status)) {
      return Status;
    }

    //
    // Don't cache memory mapped FV really.
    //
    FvDevice->CachedFv = (UINT8 *) (UINTN) (PhysicalAddress + FwVolHeader->HeaderLength);
  } else {
    FvDevice->IsMemoryMapped = FALSE;
    FvDevice->CachedFv = AllocatePool (Size);

    if (FvDevice->CachedFv == NULL) {
      return EFI_OUT_OF_RESOURCES;
    }
  }

  //
  // Remember a pointer to the end fo the CachedFv
  //
  FvDevice->EndOfCachedFv = FvDevice->CachedFv + Size;

  if (!FvDevice->IsMemoryMapped) {
    //
    // Copy FV minus header into memory using the block map we have all ready
    // read into memory.
    //
    BlockMap = FwVolHeader->BlockMap;
    CacheLocation = FvDevice->CachedFv;
    LbaIndex = 0;
    LbaOffset = 0;
    HeaderSize = FwVolHeader->HeaderLength;
    while ((BlockMap->NumBlocks != 0) || (BlockMap->Length != 0)) {
      Index = 0;
      Size  = BlockMap->Length;
      if (HeaderSize > 0) {
        //
        // Skip header size
        //
        for (; Index < BlockMap->NumBlocks && HeaderSize >= BlockMap->Length; Index ++) {
          HeaderSize -= BlockMap->Length;
          LbaIndex ++;
        }

        //
        // Check whether FvHeader is crossing the multi block range.
        //
        if (Index >= BlockMap->NumBlocks) {
          BlockMap++;
          continue;
        } else if (HeaderSize > 0) {
          LbaOffset = HeaderSize;
          Size = BlockMap->Length - HeaderSize;
          HeaderSize = 0;
        }
      }
    
      //
      // read the FV data  
      //
      for (; Index < BlockMap->NumBlocks; Index ++) {
        Status = Fvb->Read (Fvb,
                        LbaIndex,
                        LbaOffset,
                        &Size,
                        CacheLocation
                        );

        //
        // Not check EFI_BAD_BUFFER_SIZE, for Size = BlockMap->Length
        //
        if (EFI_ERROR (Status)) {
          goto Done;
        }

        LbaIndex++;
        CacheLocation += Size;

        //
        // After we skip Fv Header always read from start of block
        //
        LbaOffset = 0;
        Size  = BlockMap->Length;
      }

      BlockMap++;
    }
  }

  //
  // Scan to check the free space & File list
  //
  if ((FvbAttributes & EFI_FVB2_ERASE_POLARITY) != 0) {
    FvDevice->ErasePolarity = 1;
  } else {
    FvDevice->ErasePolarity = 0;
  }


  //
  // go through the whole FV cache, check the consistence of the FV.
  // Make a linked list of all the Ffs file headers
  //
  Status = EFI_SUCCESS;
  InitializeListHead (&FvDevice->FfsFileListHeader);

  //
  // Build FFS list
  //
  if (FwVolHeader->ExtHeaderOffset != 0) {
    //
    // Searching for files starts on an 8 byte aligned boundary after the end of the Extended Header if it exists.
    //
    FwVolExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *) (FvDevice->CachedFv + (FwVolHeader->ExtHeaderOffset - FwVolHeader->HeaderLength));
    FfsHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FwVolExtHeader + FwVolExtHeader->ExtHeaderSize);
    FfsHeader = (EFI_FFS_FILE_HEADER *) ALIGN_POINTER (FfsHeader, 8);
  } else {
    FfsHeader = (EFI_FFS_FILE_HEADER *) (FvDevice->CachedFv);
  }
  TopFvAddress = FvDevice->EndOfCachedFv;
  while (((UINTN) FfsHeader >= (UINTN) FvDevice->CachedFv) && ((UINTN) FfsHeader <= (UINTN) ((UINTN) TopFvAddress - sizeof (EFI_FFS_FILE_HEADER)))) {

    if (FileCached) {
      CoreFreePool (CacheFfsHeader);
      FileCached = FALSE;
    }

    TestLength = TopFvAddress - ((UINT8 *) FfsHeader);
    if (TestLength > sizeof (EFI_FFS_FILE_HEADER)) {
      TestLength = sizeof (EFI_FFS_FILE_HEADER);
    }

    if (IsBufferErased (FvDevice->ErasePolarity, FfsHeader, TestLength)) {
      //
      // We have found the free space so we are done!
      //
      goto Done;
    }

    if (!IsValidFfsHeader (FvDevice->ErasePolarity, FfsHeader, &FileState)) {
      if ((FileState == EFI_FILE_HEADER_INVALID) ||
          (FileState == EFI_FILE_HEADER_CONSTRUCTION)) {
        if (IS_FFS_FILE2 (FfsHeader)) {
          if (!FvDevice->IsFfs3Fv) {
            DEBUG ((EFI_D_ERROR, "Found a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &FfsHeader->Name));
          }
          FfsHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsHeader + sizeof (EFI_FFS_FILE_HEADER2));
        } else {
          FfsHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsHeader + sizeof (EFI_FFS_FILE_HEADER));
        }
        continue;
      } else {
        //
        // File system is corrputed
        //
        Status = EFI_VOLUME_CORRUPTED;
        goto Done;
      }
    }

    CacheFfsHeader = FfsHeader;
    if ((CacheFfsHeader->Attributes & FFS_ATTRIB_CHECKSUM) == FFS_ATTRIB_CHECKSUM) {
      if (FvDevice->IsMemoryMapped) {
        //
        // Memory mapped FV has not been cached.
        // Here is to cache FFS file to memory buffer for following checksum calculating.
        // And then, the cached file buffer can be also used for FvReadFile.
        //
        WholeFileSize = IS_FFS_FILE2 (CacheFfsHeader) ? FFS_FILE2_SIZE (CacheFfsHeader): FFS_FILE_SIZE (CacheFfsHeader);
        CacheFfsHeader = AllocateCopyPool (WholeFileSize, CacheFfsHeader);
        if (CacheFfsHeader == NULL) {
          Status = EFI_OUT_OF_RESOURCES;
          goto Done;
        }
        FileCached = TRUE;
      }
    }

    if (!IsValidFfsFile (FvDevice->ErasePolarity, CacheFfsHeader)) {
      //
      // File system is corrupted
      //
      Status = EFI_VOLUME_CORRUPTED;
      goto Done;
    }

    if (IS_FFS_FILE2 (CacheFfsHeader)) {
      ASSERT (FFS_FILE2_SIZE (CacheFfsHeader) > 0x00FFFFFF);
      if (!FvDevice->IsFfs3Fv) {
        DEBUG ((EFI_D_ERROR, "Found a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &CacheFfsHeader->Name));
        FfsHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsHeader + FFS_FILE2_SIZE (CacheFfsHeader));
        //
        // Adjust pointer to the next 8-byte aligned boundry.
        //
        FfsHeader = (EFI_FFS_FILE_HEADER *) (((UINTN) FfsHeader + 7) & ~0x07);
        continue;
      }
    }

    FileState = GetFileState (FvDevice->ErasePolarity, CacheFfsHeader);

    //
    // check for non-deleted file
    //
    if (FileState != EFI_FILE_DELETED) {
      //
      // Create a FFS list entry for each non-deleted file
      //
      FfsFileEntry = AllocateZeroPool (sizeof (FFS_FILE_LIST_ENTRY));
      if (FfsFileEntry == NULL) {
        Status = EFI_OUT_OF_RESOURCES;
        goto Done;
      }

      FfsFileEntry->FfsHeader = CacheFfsHeader;
      FfsFileEntry->FileCached = FileCached;
      FileCached = FALSE;
      InsertTailList (&FvDevice->FfsFileListHeader, &FfsFileEntry->Link);
    }

    if (IS_FFS_FILE2 (CacheFfsHeader)) {
      FfsHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsHeader + FFS_FILE2_SIZE (CacheFfsHeader));
    } else {
      FfsHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsHeader + FFS_FILE_SIZE (CacheFfsHeader));
    }

    //
    // Adjust pointer to the next 8-byte aligned boundry.
    //
    FfsHeader = (EFI_FFS_FILE_HEADER *)(((UINTN)FfsHeader + 7) & ~0x07);

  }

Done:
  if (EFI_ERROR (Status)) {
    if (FileCached) {
      CoreFreePool (CacheFfsHeader);
      FileCached = FALSE;
    }
    FreeFvDeviceResource (FvDevice);
  }

  return Status;
}
Exemple #2
0
/**
  Check if an FV is consistent and allocate cache for it.

  @param  FvDevice              A pointer to the FvDevice to be checked.

  @retval EFI_OUT_OF_RESOURCES  No enough buffer could be allocated.
  @retval EFI_VOLUME_CORRUPTED  File system is corrupted.
  @retval EFI_SUCCESS           FV is consistent and cache is allocated.

**/
EFI_STATUS
FvCheck (
  IN FV_DEVICE  *FvDevice
  )
{
  EFI_STATUS                          Status;
  EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *Fvb;
  EFI_FVB_ATTRIBUTES_2                FvbAttributes;
  EFI_FV_BLOCK_MAP_ENTRY              *BlockMap;
  EFI_FIRMWARE_VOLUME_HEADER          *FwVolHeader;
  EFI_FIRMWARE_VOLUME_EXT_HEADER      *FwVolExtHeader;
  UINT8                               *FwCache;
  LBA_ENTRY                           *LbaEntry;
  FREE_SPACE_ENTRY                    *FreeSpaceEntry;
  FFS_FILE_LIST_ENTRY                 *FfsFileEntry;
  UINT8                               *LbaStart;
  UINTN                               Index;
  EFI_LBA                             LbaIndex;
  UINT8                               *Ptr;
  UINTN                               Size;
  UINT8                               *FreeStart;
  UINTN                               FreeSize;
  UINT8                               ErasePolarity;
  EFI_FFS_FILE_STATE                  FileState;
  UINT8                               *TopFvAddress;
  UINTN                               TestLength;
  EFI_PHYSICAL_ADDRESS                BaseAddress;

  Fvb     = FvDevice->Fvb;

  Status  = Fvb->GetAttributes (Fvb, &FvbAttributes);
  if (EFI_ERROR (Status)) {
    return Status;
  }

  InitializeListHead (&FvDevice->LbaHeader);
  InitializeListHead (&FvDevice->FreeSpaceHeader);
  InitializeListHead (&FvDevice->FfsFileListHeader);

  FwVolHeader = NULL;
  Status = GetFwVolHeader (Fvb, &FwVolHeader);
  if (EFI_ERROR (Status)) {
    return Status;
  }
  ASSERT (FwVolHeader != NULL);

  FvDevice->IsFfs3Fv = CompareGuid (&FwVolHeader->FileSystemGuid, &gEfiFirmwareFileSystem3Guid);

  //
  // Double Check firmware volume header here
  //
  if (!VerifyFvHeaderChecksum (FwVolHeader)) {
    FreePool (FwVolHeader);
    return EFI_VOLUME_CORRUPTED;
  }

  BlockMap = FwVolHeader->BlockMap;

  //
  // FwVolHeader->FvLength is the whole FV length including FV header
  //
  FwCache = AllocateZeroPool ((UINTN) FwVolHeader->FvLength);
  if (FwCache == NULL) {
    FreePool (FwVolHeader);
    return EFI_OUT_OF_RESOURCES;
  }

  FvDevice->CachedFv = (EFI_PHYSICAL_ADDRESS) (UINTN) FwCache;

  //
  // Copy to memory
  //
  LbaStart  = FwCache;
  LbaIndex  = 0;
  Ptr       = NULL;

  if ((FvbAttributes & EFI_FVB2_MEMORY_MAPPED) != 0) {
    //
    // Get volume base address
    //
    Status = Fvb->GetPhysicalAddress (Fvb, &BaseAddress);
    if (EFI_ERROR (Status)) {
      FreePool (FwVolHeader);
      return Status;
    }

    Ptr = (UINT8 *) ((UINTN) BaseAddress);

    DEBUG((EFI_D_INFO, "Fv Base Address is 0x%LX\n", BaseAddress));
  }
  //
  // Copy whole FV into the memory
  //
  while ((BlockMap->NumBlocks != 0) || (BlockMap->Length != 0)) {

    for (Index = 0; Index < BlockMap->NumBlocks; Index++) {
      LbaEntry = AllocatePool (sizeof (LBA_ENTRY));
      if (LbaEntry == NULL) {
        FreePool (FwVolHeader);
        FreeFvDeviceResource (FvDevice);
        return EFI_OUT_OF_RESOURCES;
      }

      LbaEntry->LbaIndex        = LbaIndex;
      LbaEntry->StartingAddress = LbaStart;
      LbaEntry->BlockLength     = BlockMap->Length;

      //
      // Copy each LBA into memory
      //
      if ((FvbAttributes & EFI_FVB2_MEMORY_MAPPED) != 0) {

        CopyMem (LbaStart, Ptr, BlockMap->Length);
        Ptr += BlockMap->Length;

      } else {

        Size = BlockMap->Length;
        Status = Fvb->Read (
                        Fvb,
                        LbaIndex,
                        0,
                        &Size,
                        LbaStart
                        );
        //
        // Not check EFI_BAD_BUFFER_SIZE, for Size = BlockMap->Length
        //
        if (EFI_ERROR (Status)) {
          FreePool (FwVolHeader);
          FreeFvDeviceResource (FvDevice);
          return Status;
        }

      }

      LbaIndex++;
      LbaStart += BlockMap->Length;

      InsertTailList (&FvDevice->LbaHeader, &LbaEntry->Link);
    }

    BlockMap++;
  }

  FvDevice->FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) FwCache;

  //
  // it is not used any more, so free FwVolHeader
  //
  FreePool (FwVolHeader);

  //
  // Scan to check the free space & File list
  //
  if ((FvbAttributes & EFI_FVB2_ERASE_POLARITY) != 0) {
    ErasePolarity = 1;
  } else {
    ErasePolarity = 0;
  }

  FvDevice->ErasePolarity = ErasePolarity;

  //
  // go through the whole FV cache, check the consistence of the FV
  //
  if (FvDevice->FwVolHeader->ExtHeaderOffset != 0) {
    //
    // Searching for files starts on an 8 byte aligned boundary after the end of the Extended Header if it exists.
    //
    FwVolExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *) (UINTN) (FvDevice->CachedFv + FvDevice->FwVolHeader->ExtHeaderOffset);
    Ptr = (UINT8 *) FwVolExtHeader + FwVolExtHeader->ExtHeaderSize;
    Ptr = (UINT8 *) ALIGN_POINTER (Ptr, 8);
  } else {
    Ptr = (UINT8 *) (UINTN) (FvDevice->CachedFv + FvDevice->FwVolHeader->HeaderLength);
  }
  TopFvAddress = (UINT8 *) (UINTN) (FvDevice->CachedFv + FvDevice->FwVolHeader->FvLength);

  //
  // Build FFS list & Free Space List here
  //
  while (Ptr < TopFvAddress) {
    TestLength = TopFvAddress - Ptr;

    if (TestLength > sizeof (EFI_FFS_FILE_HEADER)) {
      TestLength = sizeof (EFI_FFS_FILE_HEADER);
    }

    if (IsBufferErased (ErasePolarity, Ptr, TestLength)) {
      //
      // We found free space
      //
      FreeStart = Ptr;
      FreeSize  = 0;

      do {
        TestLength = TopFvAddress - Ptr;

        if (TestLength > sizeof (EFI_FFS_FILE_HEADER)) {
          TestLength = sizeof (EFI_FFS_FILE_HEADER);
        }

        if (!IsBufferErased (ErasePolarity, Ptr, TestLength)) {
          break;
        }

        FreeSize += TestLength;
        Ptr += TestLength;
      } while (Ptr < TopFvAddress);

      FreeSpaceEntry = AllocateZeroPool (sizeof (FREE_SPACE_ENTRY));
      if (FreeSpaceEntry == NULL) {
        FreeFvDeviceResource (FvDevice);
        return EFI_OUT_OF_RESOURCES;
      }
      //
      // Create a Free space entry
      //
      FreeSpaceEntry->StartingAddress = FreeStart;
      FreeSpaceEntry->Length          = FreeSize;
      InsertTailList (&FvDevice->FreeSpaceHeader, &FreeSpaceEntry->Link);
      continue;
    }
    //
    // double check boundry
    //
    if (TestLength < sizeof (EFI_FFS_FILE_HEADER)) {
      break;
    }

    if (!IsValidFFSHeader (
          FvDevice->ErasePolarity,
          (EFI_FFS_FILE_HEADER *) Ptr
          )) {
      FileState = GetFileState (
                    FvDevice->ErasePolarity,
                    (EFI_FFS_FILE_HEADER *) Ptr
                    );
      if ((FileState == EFI_FILE_HEADER_INVALID) || (FileState == EFI_FILE_HEADER_CONSTRUCTION)) {
        if (IS_FFS_FILE2 (Ptr)) {
          if (!FvDevice->IsFfs3Fv) {
            DEBUG ((EFI_D_ERROR, "Found a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &((EFI_FFS_FILE_HEADER *) Ptr)->Name));
          }
          Ptr = Ptr + sizeof (EFI_FFS_FILE_HEADER2);
        } else {
          Ptr = Ptr + sizeof (EFI_FFS_FILE_HEADER);
        }

        continue;

      } else {
        //
        // File system is corrputed, return
        //
        FreeFvDeviceResource (FvDevice);
        return EFI_VOLUME_CORRUPTED;
      }
    }

    if (IS_FFS_FILE2 (Ptr)) {
      ASSERT (FFS_FILE2_SIZE (Ptr) > 0x00FFFFFF);
      if (!FvDevice->IsFfs3Fv) {
        DEBUG ((EFI_D_ERROR, "Found a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &((EFI_FFS_FILE_HEADER *) Ptr)->Name));
        Ptr = Ptr + FFS_FILE2_SIZE (Ptr);
        //
        // Adjust Ptr to the next 8-byte aligned boundry.
        //
        while (((UINTN) Ptr & 0x07) != 0) {
          Ptr++;
        }
        continue;
      }
    }

    if (IsValidFFSFile (FvDevice, (EFI_FFS_FILE_HEADER *) Ptr)) {
      FileState = GetFileState (
                    FvDevice->ErasePolarity,
                    (EFI_FFS_FILE_HEADER *) Ptr
                    );

      //
      // check for non-deleted file
      //
      if (FileState != EFI_FILE_DELETED) {
        //
        // Create a FFS list entry for each non-deleted file
        //
        FfsFileEntry = AllocateZeroPool (sizeof (FFS_FILE_LIST_ENTRY));
        if (FfsFileEntry == NULL) {
          FreeFvDeviceResource (FvDevice);
          return EFI_OUT_OF_RESOURCES;
        }

        FfsFileEntry->FfsHeader = Ptr;
        InsertTailList (&FvDevice->FfsFileListHeader, &FfsFileEntry->Link);
      }

      if (IS_FFS_FILE2 (Ptr)) {
        Ptr = Ptr + FFS_FILE2_SIZE (Ptr);
      } else {
        Ptr = Ptr + FFS_FILE_SIZE (Ptr);
      }

      //
      // Adjust Ptr to the next 8-byte aligned boundry.
      //
      while (((UINTN) Ptr & 0x07) != 0) {
        Ptr++;
      }
    } else {
      //
      // File system is corrupted, return
      //
      FreeFvDeviceResource (FvDevice);
      return EFI_VOLUME_CORRUPTED;
    }
  }

  FvDevice->CurrentFfsFile = NULL;

  return EFI_SUCCESS;
}
Exemple #3
0
/**
  Create a PAD File in the Free Space.

  @param FvDevice        Firmware Volume Device.
  @param FreeSpaceEntry  Indicating in which Free Space(Cache) the Pad file will be inserted.
  @param Size            Pad file Size, not include the header.
  @param PadFileEntry    The Ffs File Entry that points to this Pad File.

  @retval EFI_SUCCESS            Successfully create a PAD file.
  @retval EFI_OUT_OF_RESOURCES   No enough free space to create a PAD file.
  @retval EFI_INVALID_PARAMETER  Size is not 8 byte alignment.
  @retval EFI_DEVICE_ERROR       Free space is not erased.
**/
EFI_STATUS
FvCreatePadFileInFreeSpace (
  IN  FV_DEVICE           *FvDevice,
  IN  FREE_SPACE_ENTRY    *FreeSpaceEntry,
  IN  UINTN               Size,
  OUT FFS_FILE_LIST_ENTRY **PadFileEntry
  )
{
  EFI_STATUS                          Status;
  EFI_FFS_FILE_HEADER                 *PadFileHeader;
  UINTN                               Offset;
  UINTN                               NumBytesWritten;
  UINTN                               StateOffset;
  UINT8                               *StartPos;
  FFS_FILE_LIST_ENTRY                 *FfsFileEntry;
  UINTN                               HeaderSize;
  UINTN                               FileSize;

  HeaderSize = sizeof (EFI_FFS_FILE_HEADER);
  FileSize = Size + HeaderSize;
  if (FileSize > 0x00FFFFFF) {
    HeaderSize = sizeof (EFI_FFS_FILE_HEADER2);
    FileSize = Size + HeaderSize;
  }

  if (FreeSpaceEntry->Length < FileSize) {
    return EFI_OUT_OF_RESOURCES;
  }

  if ((Size & 0x07) != 0) {
    return EFI_INVALID_PARAMETER;
  }

  StartPos = FreeSpaceEntry->StartingAddress;

  //
  // First double check the space
  //
  if (!IsBufferErased (
        FvDevice->ErasePolarity,
        StartPos,
        FileSize
        )) {
    return EFI_DEVICE_ERROR;
  }

  PadFileHeader = (EFI_FFS_FILE_HEADER *) StartPos;

  //
  // Create File Step 1
  //
  SetFileState (EFI_FILE_HEADER_CONSTRUCTION, PadFileHeader);

  Offset          = (UINTN) (StartPos - FvDevice->CachedFv);
  StateOffset     = Offset + (UINT8 *) &PadFileHeader->State - (UINT8 *) PadFileHeader;

  NumBytesWritten = sizeof (EFI_FFS_FILE_STATE);
  Status = FvcWrite (
            FvDevice,
            StateOffset,
            &NumBytesWritten,
            &PadFileHeader->State
            );
  if (EFI_ERROR (Status)) {
    SetFileState (EFI_FILE_HEADER_CONSTRUCTION, PadFileHeader);
    return Status;
  }
  //
  // Update Free Space Entry, since header is allocated
  //
  FreeSpaceEntry->Length -= HeaderSize;
  FreeSpaceEntry->StartingAddress += HeaderSize;

  //
  // Fill File Name Guid, here we assign a NULL-GUID to Pad files
  //
  ZeroMem (&PadFileHeader->Name, sizeof (EFI_GUID));

  //
  // Fill File Type, checksum(0), Attributes(0), Size
  //
  PadFileHeader->Type       = EFI_FV_FILETYPE_FFS_PAD;
  PadFileHeader->Attributes = 0;
  if ((FileSize) > 0x00FFFFFF) {
    ((EFI_FFS_FILE_HEADER2 *) PadFileHeader)->ExtendedSize = (UINT32) FileSize;
    *(UINT32 *) PadFileHeader->Size &= 0xFF000000;
    PadFileHeader->Attributes |= FFS_ATTRIB_LARGE_FILE;
  } else {
    *(UINT32 *) PadFileHeader->Size &= 0xFF000000;
    *(UINT32 *) PadFileHeader->Size |= FileSize;
  }

  SetHeaderChecksum (PadFileHeader);
  SetPadFileChecksum (PadFileHeader);

  Offset          = (UINTN) (StartPos - FvDevice->CachedFv);

  NumBytesWritten = HeaderSize;
  Status = FvcWrite (
            FvDevice,
            Offset,
            &NumBytesWritten,
            (UINT8 *) PadFileHeader
            );
  if (EFI_ERROR (Status)) {
    return Status;
  }

  //
  // Step 2, then Mark header valid, since no data write,
  // mark the data valid at the same time.
  //
  SetFileState (EFI_FILE_HEADER_VALID, PadFileHeader);
  SetFileState (EFI_FILE_DATA_VALID, PadFileHeader);

  Offset          = (UINTN) (StartPos - FvDevice->CachedFv);
  StateOffset     = Offset + (UINT8 *) &PadFileHeader->State - (UINT8 *) PadFileHeader;

  NumBytesWritten = sizeof (EFI_FFS_FILE_STATE);
  Status = FvcWrite (
            FvDevice,
            StateOffset,
            &NumBytesWritten,
            &PadFileHeader->State
            );
  if (EFI_ERROR (Status)) {
    SetFileState (EFI_FILE_HEADER_VALID, PadFileHeader);
    SetFileState (EFI_FILE_DATA_VALID, PadFileHeader);
    return Status;
  }
  //
  // Update Free Space Entry, since header is allocated
  //
  FreeSpaceEntry->Length -= Size;
  FreeSpaceEntry->StartingAddress += Size;

  //
  // If successfully, insert an FfsFileEntry at the end of ffs file list
  //
  FfsFileEntry = AllocateZeroPool (sizeof (FFS_FILE_LIST_ENTRY));
  ASSERT (FfsFileEntry != NULL);

  FfsFileEntry->FfsHeader = (UINT8 *) (UINTN) StartPos;
  InsertTailList (&FvDevice->FfsFileListHeader, &FfsFileEntry->Link);

  *PadFileEntry             = FfsFileEntry;
  FvDevice->CurrentFfsFile  = FfsFileEntry;

  return EFI_SUCCESS;
}
Exemple #4
0
/**
  Get FFS buffer pointer by FileName GUID and FileType.

  @param[in]   FdStart          The System Firmware FD image
  @param[in]   FdSize           The size of System Firmware FD image
  @param[in]   FileName         The FileName GUID of FFS to be found
  @param[in]   Type             The FileType of FFS to be found
  @param[out]  OutFfsBuffer     The FFS buffer found, including FFS_FILE_HEADER
  @param[out]  OutFfsBufferSize The size of FFS buffer found, including FFS_FILE_HEADER

  @retval TRUE  The FFS buffer is found.
  @retval FALSE The FFS buffer is not found.
**/
BOOLEAN
GetFfsByName (
  IN VOID                  *FdStart,
  IN UINTN                 FdSize,
  IN EFI_GUID              *FileName,
  IN EFI_FV_FILETYPE       Type,
  OUT VOID                 **OutFfsBuffer,
  OUT UINTN                *OutFfsBufferSize
  )
{
  UINTN                                     FvSize;
  EFI_FIRMWARE_VOLUME_HEADER                *FvHeader;
  EFI_FIRMWARE_VOLUME_EXT_HEADER            *FvExtHeader;
  EFI_FFS_FILE_HEADER                       *FfsHeader;
  UINT32                                    FfsSize;
  UINTN                                     TestLength;
  BOOLEAN                                   FvFound;

  DEBUG ((DEBUG_INFO, "GetFfsByName - FV: 0x%08x - 0x%08x\n", (UINTN)FdStart, (UINTN)FdSize));

  FvFound = FALSE;
  FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)FdStart;
  while ((UINTN)FvHeader < (UINTN)FdStart + FdSize - 1) {
    FvSize = (UINTN)FdStart + FdSize - (UINTN)FvHeader;

    if (FvHeader->Signature != EFI_FVH_SIGNATURE) {
      FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)((UINTN)FvHeader + SIZE_4KB);
      continue;
    }
    DEBUG((DEBUG_ERROR, "checking FV....0x%08x - 0x%x\n", FvHeader, FvHeader->FvLength));
    FvFound = TRUE;
    if (FvHeader->FvLength > FvSize) {
      DEBUG((DEBUG_ERROR, "GetFfsByName - FvSize: 0x%08x, MaxSize - 0x%08x\n", (UINTN)FvHeader->FvLength, (UINTN)FvSize));
      return FALSE;
    }
    FvSize = (UINTN)FvHeader->FvLength;

    //
    // Find FFS
    //
    if (FvHeader->ExtHeaderOffset != 0) {
      FvExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *)((UINT8 *)FvHeader + FvHeader->ExtHeaderOffset);
      FfsHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FvExtHeader + FvExtHeader->ExtHeaderSize);
    } else {
      FfsHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FvHeader + FvHeader->HeaderLength);
    }
    FfsHeader = (EFI_FFS_FILE_HEADER *)((UINTN)FvHeader + ALIGN_VALUE((UINTN)FfsHeader - (UINTN)FvHeader, 8));

    while ((UINTN)FfsHeader < (UINTN)FvHeader + FvSize - 1) {
      DEBUG((DEBUG_INFO, "GetFfsByName - FFS: 0x%08x\n", FfsHeader));
      TestLength = (UINTN)((UINTN)FvHeader + FvSize - (UINTN)FfsHeader);
      if (TestLength > sizeof(EFI_FFS_FILE_HEADER)) {
        TestLength = sizeof(EFI_FFS_FILE_HEADER);
      }
      if (IsBufferErased(1, FfsHeader, TestLength)) {
        break;
      }

      if (IS_FFS_FILE2(FfsHeader)) {
        FfsSize = FFS_FILE2_SIZE(FfsHeader);
      } else {
        FfsSize = FFS_FILE_SIZE(FfsHeader);
      }

      if (CompareGuid(FileName, &FfsHeader->Name) &&
          ((Type == EFI_FV_FILETYPE_ALL) || (FfsHeader->Type == Type))) {
        //
        // Check section
        //
        *OutFfsBuffer = FfsHeader;
        *OutFfsBufferSize = FfsSize;
        return TRUE;
      } else {
        //
        // Any other type is not allowed
        //
        DEBUG((DEBUG_INFO, "GetFfsByName - other FFS type 0x%x, name %g\n", FfsHeader->Type, &FfsHeader->Name));
      }

      //
      // Next File
      //
      FfsHeader = (EFI_FFS_FILE_HEADER *)((UINTN)FfsHeader + ALIGN_VALUE(FfsSize, 8));
    }

    //
    // Next FV
    //
    FvHeader = (VOID *)(UINTN)((UINTN)FvHeader + FvHeader->FvLength);
    DEBUG((DEBUG_ERROR, "Next FV....0x%08x - 0x%x\n", FvHeader, FvHeader->FvLength));
  }

  if (!FvFound) {
    DEBUG((DEBUG_ERROR, "GetFfsByName - NO FV Found\n"));
  }
  return FALSE;
}