コード例 #1
0
ファイル: BootMonFsDir.c プロジェクト: EvanLloyd/tianocore
/**
  Set information about a file or a volume.

  @param[in]  This             A pointer to the EFI_FILE_PROTOCOL instance that
                               is the file handle the information is for.
  @param[in]  InformationType  The type identifier for the information being set :
                               EFI_FILE_INFO_ID or EFI_FILE_SYSTEM_INFO_ID or
                               EFI_FILE_SYSTEM_VOLUME_LABEL_ID
  @param[in]  BufferSize       The size, in bytes, of Buffer.
  @param[in]  Buffer           A pointer to the data buffer to write. The type of the
                               data inside the buffer is indicated by InformationType.

  @retval  EFI_SUCCESS            The information was set.
  @retval  EFI_UNSUPPORTED        The InformationType is not known.
  @retval  EFI_DEVICE_ERROR       The last issued semi-hosting operation failed.
  @retval  EFI_ACCESS_DENIED      An attempt is made to change the name of a file
                                  to a file that is already present.
  @retval  EFI_ACCESS_DENIED      An attempt is being made to change the
                                  EFI_FILE_DIRECTORY Attribute.
  @retval  EFI_ACCESS_DENIED      InformationType is EFI_FILE_INFO_ID and
                                  the file was opened in read-only mode and an
                                  attempt is being made to modify a field other
                                  than Attribute.
  @retval  EFI_WRITE_PROTECTED    An attempt is being made to modify a read-only
                                  attribute.
  @retval  EFI_BAD_BUFFER_SIZE    The size of the buffer is lower than that indicated by
                                  the data inside the buffer.
  @retval  EFI_OUT_OF_RESOURCES   A allocation needed to process the request failed.
  @retval  EFI_INVALID_PARAMETER  At least one of the parameters is invalid.

**/
EFIAPI
EFI_STATUS
BootMonFsSetInfo (
  IN EFI_FILE_PROTOCOL  *This,
  IN EFI_GUID           *InformationType,
  IN UINTN              BufferSize,
  IN VOID               *Buffer
  )
{
  BOOTMON_FS_FILE       *File;
  EFI_FILE_INFO         *Info;
  EFI_FILE_SYSTEM_INFO  *SystemInfo;

  if ((This == NULL)            ||
      (InformationType == NULL) ||
      (Buffer == NULL)             ) {
    return EFI_INVALID_PARAMETER;
  }

  File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);
  if (File->Info == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  if (CompareGuid (InformationType, &gEfiFileInfoGuid)) {
    Info = Buffer;
    if (Info->Size < (SIZE_OF_EFI_FILE_INFO + StrSize (Info->FileName))) {
      return EFI_INVALID_PARAMETER;
    }
    if (BufferSize < Info->Size) {
      return EFI_BAD_BUFFER_SIZE;
    }
    return (SetFileInfo (File->Instance, File, Info));
  }

  //
  // The only writable field in the other two information types
  // (i.e. EFI_FILE_SYSTEM_INFO and EFI_FILE_SYSTEM_VOLUME_LABEL) is the
  // filesystem volume label. This can be retrieved with GetInfo, but it is
  // hard-coded into this driver, not stored on media.
  //

  if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) {
    SystemInfo = Buffer;
    if (SystemInfo->Size <
        (SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (SystemInfo->VolumeLabel))) {
      return EFI_INVALID_PARAMETER;
    }
    if (BufferSize < SystemInfo->Size) {
      return EFI_BAD_BUFFER_SIZE;
    }
    return EFI_WRITE_PROTECTED;
  }

  if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) {
    return EFI_WRITE_PROTECTED;
  }

  return EFI_UNSUPPORTED;
}
コード例 #2
0
ファイル: BootMonFsOpenClose.c プロジェクト: Michell-Lee/edk2
EFIAPI
EFI_STATUS
BootMonFsDelete (
  IN EFI_FILE_PROTOCOL *This
  )
{
  EFI_STATUS               Status;
  BOOTMON_FS_FILE         *File;
  LIST_ENTRY              *RegionToFlushLink;
  BOOTMON_FS_FILE_REGION  *Region;
  HW_IMAGE_DESCRIPTION    *Description;
  EFI_BLOCK_IO_PROTOCOL   *BlockIo;
  UINT8                   *EmptyBuffer;

  File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);
  if (File == NULL) {
    return EFI_DEVICE_ERROR;
  }

  Status = EFI_SUCCESS;

  if (BootMonFsFileNeedFlush (File)) {
    // Free the entries from the Buffer List
    RegionToFlushLink = GetFirstNode (&File->RegionToFlushLink);
    do {
      Region = (BOOTMON_FS_FILE_REGION*)RegionToFlushLink;

      // Get Next entry
      RegionToFlushLink = RemoveEntryList (RegionToFlushLink);

      // Free the buffers
      FreePool (Region->Buffer);
      FreePool (Region);
    } while (!IsListEmpty (&File->RegionToFlushLink));
  }

  // If (RegionCount is greater than 0) then the file already exists
  if (File->HwDescription.RegionCount > 0) {
    Description = &File->HwDescription;
    BlockIo = File->Instance->BlockIo;

    // Create an empty buffer
    EmptyBuffer = AllocateZeroPool (BlockIo->Media->BlockSize);
    if (EmptyBuffer == NULL) {
      FreePool (File);
      return EFI_OUT_OF_RESOURCES;
    }

    // Invalidate the last Block
    Status = BlockIo->WriteBlocks (BlockIo, BlockIo->Media->MediaId, Description->BlockEnd, BlockIo->Media->BlockSize, EmptyBuffer);
    ASSERT_EFI_ERROR (Status);

    FreePool (EmptyBuffer);
  }

  // Remove the entry from the list
  RemoveEntryList (&File->Link);
  FreePool (File);
  return Status;
}
コード例 #3
0
ファイル: BootMonFsDir.c プロジェクト: jian-tian/UEFI
EFIAPI
EFI_STATUS
BootMonFsSetInfo (
  IN EFI_FILE_PROTOCOL  *This,
  IN EFI_GUID           *InformationType,
  IN UINTN              BufferSize,
  IN VOID               *Buffer
  )
{
  EFI_STATUS           Status;
  BOOTMON_FS_FILE     *File;
  BOOTMON_FS_INSTANCE *Instance;

  File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);
  if (File == NULL) {
    return EFI_DEVICE_ERROR;
  }

  Instance = File->Instance;

  if (CompareGuid (InformationType, &gEfiFileInfoGuid) != 0) {
    Status = SetFileInfo (Instance, File, BufferSize, (EFI_FILE_INFO *) Buffer);
  } else {
    // The only writable field in the other two information types
    // (i.e. EFI_FILE_SYSTEM_INFO and EFI_FILE_SYSTEM_VOLUME_LABEL) is the
    // filesystem volume label. This can be retrieved with GetInfo, but it is
    // hard-coded into this driver, not stored on media.
    Status = EFI_UNSUPPORTED;
  }

  return Status;
}
コード例 #4
0
ファイル: BootMonFsDir.c プロジェクト: EvanLloyd/tianocore
EFIAPI
EFI_STATUS
BootMonFsReadDirectory (
  IN EFI_FILE_PROTOCOL    *This,
  IN OUT UINTN            *BufferSize,
  OUT VOID                *Buffer
  )
{
  BOOTMON_FS_INSTANCE *Instance;
  BOOTMON_FS_FILE     *RootFile;
  BOOTMON_FS_FILE     *File;
  EFI_FILE_INFO       *Info;
  UINTN               NameSize;
  UINTN               ResultSize;
  EFI_STATUS          Status;
  UINTN               Index;

  RootFile = BOOTMON_FS_FILE_FROM_FILE_THIS (This);
  if (RootFile == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  Instance = RootFile->Instance;
  Status = BootMonGetFileFromPosition (Instance, RootFile->Position, &File);
  if (EFI_ERROR (Status)) {
    // No more file
    *BufferSize = 0;
    return EFI_SUCCESS;
  }

  NameSize   = AsciiStrLen (File->HwDescription.Footer.Filename) + 1;
  ResultSize = SIZE_OF_EFI_FILE_INFO + (NameSize * sizeof (CHAR16));
  if (*BufferSize < ResultSize) {
    *BufferSize = ResultSize;
    return EFI_BUFFER_TOO_SMALL;
  }

  // Zero out the structure
  Info = Buffer;
  ZeroMem (Info, ResultSize);

  // Fill in the structure
  Info->Size         = ResultSize;
  Info->FileSize     = BootMonFsGetImageLength (File);
  Info->PhysicalSize = BootMonFsGetPhysicalSize (File);
  for (Index = 0; Index < NameSize; Index++) {
    Info->FileName[Index] = File->HwDescription.Footer.Filename[Index];
  }

  *BufferSize = ResultSize;
  RootFile->Position++;

  return EFI_SUCCESS;
}
コード例 #5
0
ファイル: BootMonFsDir.c プロジェクト: EvanLloyd/tianocore
EFIAPI
EFI_STATUS
BootMonFsGetInfo (
  IN EFI_FILE_PROTOCOL  *This,
  IN EFI_GUID           *InformationType,
  IN OUT UINTN          *BufferSize,
  OUT VOID              *Buffer
  )
{
  EFI_STATUS           Status;
  BOOTMON_FS_FILE     *File;
  BOOTMON_FS_INSTANCE *Instance;

  if ((This == NULL)                         ||
      (InformationType == NULL)              ||
      (BufferSize == NULL)                   ||
      ((Buffer == NULL) && (*BufferSize > 0))  ) {
    return EFI_INVALID_PARAMETER;
  }

  File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);
  if (File->Info == NULL) {
    return EFI_INVALID_PARAMETER;
  }
  Instance = File->Instance;

  // If the instance has not been initialized yet then do it ...
  if (!Instance->Initialized) {
    Status = BootMonFsInitialize (Instance);
  } else {
    Status = EFI_SUCCESS;
  }

  if (!EFI_ERROR (Status)) {
    if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)
        != 0) {
      Status = GetFileSystemVolumeLabelInfo (Instance, BufferSize, Buffer);
    } else if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid) != 0) {
      Status = GetFilesystemInfo (Instance, BufferSize, Buffer);
    } else if (CompareGuid (InformationType, &gEfiFileInfoGuid) != 0) {
      Status = GetFileInfo (Instance, File, BufferSize, Buffer);
    } else if (CompareGuid (InformationType, &gArmBootMonFsFileInfoGuid) != 0) {
      Status = GetBootMonFsFileInfo (Instance, File, BufferSize, Buffer);
    } else {
      Status = EFI_UNSUPPORTED;
    }
  }

  return Status;
}
コード例 #6
0
ファイル: BootMonFsDir.c プロジェクト: EvanLloyd/tianocore
EFIAPI
EFI_STATUS
BootMonFsFlushDirectory (
  IN EFI_FILE_PROTOCOL  *This
  )
{
  BOOTMON_FS_FILE *RootFile;
  LIST_ENTRY      *ListFiles;
  LIST_ENTRY      *Link;
  BOOTMON_FS_FILE *File;

  RootFile = BOOTMON_FS_FILE_FROM_FILE_THIS (This);
  if (RootFile == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  ListFiles = &RootFile->Link;

  if (IsListEmpty (ListFiles)) {
    return EFI_SUCCESS;
  }

  //
  // Flush all the files that need to be flushed
  //

  // Go through all the list of files to flush them
  for (Link = GetFirstNode (ListFiles);
       !IsNull (ListFiles, Link);
       Link = GetNextNode (ListFiles, Link)
       )
  {
    File = BOOTMON_FS_FILE_FROM_LINK_THIS (Link);
    File->File.Flush (&File->File);
  }

  return EFI_SUCCESS;
}
コード例 #7
0
ファイル: BootMonFsDir.c プロジェクト: EvanLloyd/tianocore
EFIAPI
EFI_STATUS
BootMonFsSetDirPosition (
  IN EFI_FILE_PROTOCOL  *This,
  IN UINT64             Position
  )
{
  BOOTMON_FS_FILE       *File;

  File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);
  if (File == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  // UEFI Spec section 12.5:
  // "The seek request for nonzero is not valid on open directories."
  if (Position != 0) {
    return EFI_UNSUPPORTED;
  }
  File->Position = Position;

  return EFI_SUCCESS;
}
コード例 #8
0
ファイル: BootMonFsOpenClose.c プロジェクト: Michell-Lee/edk2
/**
  Opens a file on the Nor Flash FS volume

  Calls BootMonFsGetFileFromAsciiFilename to search the list of tracked files.

  @param  This  The EFI_FILE_PROTOCOL parent handle.
  @param  NewHandle Double-pointer to the newly created protocol.
  @param  FileName The name of the image/metadata on flash
  @param  OpenMode Read,write,append etc
  @param  Attributes ?

  @return EFI_STATUS
  OUT_OF_RESOURCES
    Run out of space to keep track of the allocated structures
  DEVICE_ERROR
    Unable to locate the volume associated with the parent file handle
  NOT_FOUND
    Filename wasn't found on flash
  SUCCESS

**/
EFIAPI
EFI_STATUS
BootMonFsOpenFile (
  IN EFI_FILE_PROTOCOL  *This,
  OUT EFI_FILE_PROTOCOL **NewHandle,
  IN CHAR16             *FileName,
  IN UINT64             OpenMode,
  IN UINT64             Attributes
  )
{
  BOOTMON_FS_FILE     *Directory;
  BOOTMON_FS_FILE     *File;
  BOOTMON_FS_INSTANCE *Instance;
  CHAR8*               AsciiFileName;
  EFI_STATUS           Status;

  if ((FileName == NULL) || (NewHandle == NULL)) {
    return EFI_INVALID_PARAMETER;
  }

  // The only valid modes are read, read/write, and read/write/create
  if (!(OpenMode & EFI_FILE_MODE_READ) || ((OpenMode & EFI_FILE_MODE_CREATE)  && !(OpenMode & EFI_FILE_MODE_WRITE))) {
    return EFI_INVALID_PARAMETER;
  }

  Directory = BOOTMON_FS_FILE_FROM_FILE_THIS (This);
  if (Directory == NULL) {
    return EFI_DEVICE_ERROR;
  }

  Instance = Directory->Instance;

  // If the instance has not been initialized it yet then do it ...
  if (!Instance->Initialized) {
    Status = BootMonFsInitialize (Instance);
    if (EFI_ERROR (Status)) {
      return Status;
    }
  }

  // BootMonFs interface requires ASCII filenames
  AsciiFileName = AllocatePool ((StrLen (FileName) + 1) * sizeof (CHAR8));
  if (AsciiFileName == NULL) {
    return EFI_OUT_OF_RESOURCES;
  }
  UnicodeStrToAsciiStr (FileName, AsciiFileName);

  if ((AsciiStrCmp (AsciiFileName, "\\") == 0) ||
      (AsciiStrCmp (AsciiFileName, "/")  == 0) ||
      (AsciiStrCmp (AsciiFileName, "")   == 0) ||
      (AsciiStrCmp (AsciiFileName, ".")  == 0))
  {
    //
    // Opening '/', '\', '.', or the NULL pathname is trying to open the root directory
    //

    *NewHandle = &Instance->RootFile->File;
    Instance->RootFile->Position = 0;
    Status = EFI_SUCCESS;
  } else {
    //
    // Open or Create a regular file
    //

    // Check if the file already exists
    Status = BootMonGetFileFromAsciiFileName (Instance, AsciiFileName, &File);
    if (Status == EFI_NOT_FOUND) {
      // The file doesn't exist.
      if (OpenMode & EFI_FILE_MODE_CREATE) {
        // If the file does not exist but is required then create it.
        if (Attributes & EFI_FILE_DIRECTORY) {
          // BootMonFS doesn't support subdirectories
          Status = EFI_UNSUPPORTED;
        } else {
          // Create a new file
          Status = CreateNewFile (Instance, AsciiFileName, &File);
          if (!EFI_ERROR (Status)) {
            File->OpenMode = OpenMode;
            *NewHandle = &File->File;
            File->Position = 0;
          }
        }
      }
    } else if (Status == EFI_SUCCESS) {
      // The file exists
      File->OpenMode = OpenMode;
      *NewHandle = &File->File;
      File->Position = 0;
    }
  }

  FreePool (AsciiFileName);

  return Status;
}
コード例 #9
0
ファイル: BootMonFsOpenClose.c プロジェクト: Michell-Lee/edk2
EFIAPI
EFI_STATUS
BootMonFsFlushFile (
  IN EFI_FILE_PROTOCOL  *This
  )
{
  EFI_STATUS               Status;
  BOOTMON_FS_INSTANCE     *Instance;
  LIST_ENTRY              *RegionToFlushLink;
  BOOTMON_FS_FILE         *File;
  BOOTMON_FS_FILE         *NextFile;
  BOOTMON_FS_FILE_REGION  *Region;
  LIST_ENTRY              *FileLink;
  UINTN                    CurrentPhysicalSize;
  UINTN                    BlockSize;
  UINT64                   FileStart;
  UINT64                   FileEnd;
  UINT64                   RegionStart;
  UINT64                   RegionEnd;
  UINT64                   NewFileSize;
  UINT64                   EndOfAppendSpace;
  BOOLEAN                  HasSpace;
  EFI_DISK_IO_PROTOCOL    *DiskIo;
  EFI_BLOCK_IO_PROTOCOL   *BlockIo;

  Status      = EFI_SUCCESS;
  FileStart   = 0;

  File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);
  if (File == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  // Check if the file needs to be flushed
  if (!BootMonFsFileNeedFlush (File)) {
    return Status;
  }

  Instance = File->Instance;
  BlockIo = Instance->BlockIo;
  DiskIo = Instance->DiskIo;
  BlockSize = BlockIo->Media->BlockSize;

  // If the file doesn't exist then find a space for it
  if (File->HwDescription.RegionCount == 0) {
    Status = BootMonFsFindSpaceForNewFile (File, &FileStart);
    // FileStart has changed so we need to recompute RegionEnd
    if (EFI_ERROR (Status)) {
      return Status;
    }
  } else {
    FileStart = File->HwDescription.BlockStart * BlockSize;
  }

  // FileEnd is the NOR address of the end of the file's data
  FileEnd = FileStart + BootMonFsGetImageLength (File);

  for (RegionToFlushLink = GetFirstNode (&File->RegionToFlushLink);
       !IsNull (&File->RegionToFlushLink, RegionToFlushLink);
       RegionToFlushLink = GetNextNode (&File->RegionToFlushLink, RegionToFlushLink)
       )
  {
    Region = (BOOTMON_FS_FILE_REGION*)RegionToFlushLink;

    // RegionStart and RegionEnd are the the intended NOR address of the
    // start and end of the region
    RegionStart = FileStart + Region->Offset;
    RegionEnd = RegionStart + Region->Size;

    if (RegionEnd < FileEnd) {
      // Handle regions representing edits to existing portions of the file
      // Write the region data straight into the file
      Status = DiskIo->WriteDisk (DiskIo,
                        BlockIo->Media->MediaId,
                        RegionStart,
                        Region->Size,
                        Region->Buffer
                        );
      if (EFI_ERROR (Status)) {
        return Status;
      }
    } else {
      // Handle regions representing appends to the file
      //
      // Note: Since seeking past the end of the file with SetPosition() is
      //  valid, it's possible there will be a gap between the current end of
      //  the file and the beginning of the new region. Since the UEFI spec
      //  says nothing about this case (except "a subsequent write would grow
      //  the file"), we just leave garbage in the gap.

      // Check if there is space to append the new region
      HasSpace = FALSE;
      NewFileSize = (RegionEnd - FileStart) + sizeof (HW_IMAGE_DESCRIPTION);
      CurrentPhysicalSize = BootMonFsGetPhysicalSize (File);
      if (NewFileSize <= CurrentPhysicalSize) {
        HasSpace = TRUE;
      } else {
        // Get the File Description for the next file
        FileLink = GetNextNode (&Instance->RootFile->Link, &File->Link);
        if (!IsNull (&Instance->RootFile->Link, FileLink)) {
          NextFile = BOOTMON_FS_FILE_FROM_LINK_THIS (FileLink);

          // If there is space between the beginning of the current file and the
          // beginning of the next file then use it
          EndOfAppendSpace = NextFile->HwDescription.BlockStart * BlockSize;
        } else {
          // We are flushing the last file.
          EndOfAppendSpace = (BlockIo->Media->LastBlock + 1) * BlockSize;
        }
        if (EndOfAppendSpace - FileStart >= NewFileSize) {
          HasSpace = TRUE;
        }
      }

      if (HasSpace == TRUE) {
        Status = FlushAppendRegion (File, Region, NewFileSize, FileStart);
        if (EFI_ERROR (Status)) {
          return Status;
        }
      } else {
        // There isn't a space for the file.
        // Options here are to move the file or fragment it. However as files
        // may represent boot images at fixed positions, these options will
        // break booting if the bootloader doesn't use BootMonFs to find the
        // image.

        return EFI_VOLUME_FULL;
      }
    }
  }

  FreeFileRegions (File);

  // Flush DiskIo Buffers (see UEFI Spec 12.7 - DiskIo buffers are flushed by
  // calling FlushBlocks on the same device's BlockIo).
  BlockIo->FlushBlocks (BlockIo);

  return Status;
}