Home | History | Annotate | Download | only in BootMonFs
      1 /** @file
      2 *
      3 *  Copyright (c) 2012-2014, ARM Limited. All rights reserved.
      4 *
      5 *  This program and the accompanying materials
      6 *  are licensed and made available under the terms and conditions of the BSD License
      7 *  which accompanies this distribution.  The full text of the license may be found at
      8 *  http://opensource.org/licenses/bsd-license.php
      9 *
     10 *  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11 *  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 *
     13 **/
     14 
     15 #include <Protocol/SimpleFileSystem.h>
     16 #include <Library/UefiLib.h>
     17 #include <Library/BaseMemoryLib.h>
     18 #include <Library/MemoryAllocationLib.h>
     19 #include <Library/DebugLib.h>
     20 
     21 #include "BootMonFsInternal.h"
     22 
     23 /**
     24   Read data from an open file.
     25 
     26   @param[in]      This        A pointer to the EFI_FILE_PROTOCOL instance that
     27                               is the file handle to read data from.
     28   @param[in out]  BufferSize  On input, the size of the Buffer. On output, the
     29                               amount of data returned in Buffer. In both cases,
     30                               the size is measured in bytes.
     31   @param[out]     Buffer      The buffer into which the data is read.
     32 
     33   @retval  EFI_SUCCESS            The data was read.
     34   @retval  EFI_DEVICE_ERROR       On entry, the current file position is
     35                                   beyond the end of the file, or the device
     36                                   reported an error while performing the read
     37                                   operation.
     38   @retval  EFI_INVALID_PARAMETER  At least one of the parameters is invalid.
     39 
     40 **/
     41 EFIAPI
     42 EFI_STATUS
     43 BootMonFsReadFile (
     44   IN EFI_FILE_PROTOCOL  *This,
     45   IN OUT UINTN          *BufferSize,
     46   OUT VOID              *Buffer
     47   )
     48 {
     49   BOOTMON_FS_INSTANCE   *Instance;
     50   BOOTMON_FS_FILE       *File;
     51   EFI_DISK_IO_PROTOCOL  *DiskIo;
     52   EFI_BLOCK_IO_MEDIA    *Media;
     53   UINT64                FileStart;
     54   EFI_STATUS            Status;
     55   UINTN                 RemainingFileSize;
     56 
     57   if ((This == NULL)       ||
     58       (BufferSize == NULL) ||
     59       (Buffer == NULL)        ) {
     60     return EFI_INVALID_PARAMETER;
     61   }
     62   File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);
     63   if (File->Info == NULL) {
     64     return EFI_INVALID_PARAMETER;
     65   }
     66 
     67   // Ensure the file has been written in Flash before reading it.
     68   // This keeps the code simple and avoids having to manage a non-flushed file.
     69   BootMonFsFlushFile (This);
     70 
     71   Instance  = File->Instance;
     72   DiskIo    = Instance->DiskIo;
     73   Media     = Instance->Media;
     74   FileStart = (Media->LowestAlignedLba + File->HwDescription.BlockStart) * Media->BlockSize;
     75 
     76   if (File->Position >= File->Info->FileSize) {
     77     // The entire file has been read or the position has been
     78     // set past the end of the file.
     79     *BufferSize = 0;
     80     if (File->Position > File->Info->FileSize) {
     81       return EFI_DEVICE_ERROR;
     82     } else {
     83       return EFI_SUCCESS;
     84     }
     85   }
     86 
     87   // This driver assumes that the entire file is in region 0.
     88   RemainingFileSize = File->Info->FileSize - File->Position;
     89 
     90   // If read would go past end of file, truncate the read
     91   if (*BufferSize > RemainingFileSize) {
     92     *BufferSize = RemainingFileSize;
     93   }
     94 
     95   Status = DiskIo->ReadDisk (
     96                     DiskIo,
     97                     Media->MediaId,
     98                     FileStart + File->Position,
     99                     *BufferSize,
    100                     Buffer
    101                     );
    102   if (EFI_ERROR (Status)) {
    103     *BufferSize = 0;
    104   }
    105 
    106   File->Position += *BufferSize;
    107 
    108   return Status;
    109 }
    110 
    111 /**
    112   Write data to an open file.
    113 
    114   The data is not written to the flash yet. It will be written when the file
    115   will be either read, closed or flushed.
    116 
    117   @param[in]      This        A pointer to the EFI_FILE_PROTOCOL instance that
    118                               is the file handle to write data to.
    119   @param[in out]  BufferSize  On input, the size of the Buffer. On output, the
    120                               size of the data actually written. In both cases,
    121                               the size is measured in bytes.
    122   @param[in]      Buffer      The buffer of data to write.
    123 
    124   @retval  EFI_SUCCESS            The data was written.
    125   @retval  EFI_ACCESS_DENIED      The file was opened read only.
    126   @retval  EFI_OUT_OF_RESOURCES   Unable to allocate the buffer to store the
    127                                   data to write.
    128   @retval  EFI_INVALID_PARAMETER  At least one of the parameters is invalid.
    129 
    130 **/
    131 EFIAPI
    132 EFI_STATUS
    133 BootMonFsWriteFile (
    134   IN EFI_FILE_PROTOCOL  *This,
    135   IN OUT UINTN          *BufferSize,
    136   IN VOID               *Buffer
    137   )
    138 {
    139   BOOTMON_FS_FILE         *File;
    140   BOOTMON_FS_FILE_REGION  *Region;
    141 
    142   if (This == NULL) {
    143     return EFI_INVALID_PARAMETER;
    144   }
    145   File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);
    146   if (File->Info == NULL) {
    147     return EFI_INVALID_PARAMETER;
    148   }
    149 
    150   if (File->OpenMode == EFI_FILE_MODE_READ) {
    151     return EFI_ACCESS_DENIED;
    152   }
    153 
    154   // Allocate and initialize the memory region
    155   Region = (BOOTMON_FS_FILE_REGION*)AllocateZeroPool (sizeof (BOOTMON_FS_FILE_REGION));
    156   if (Region == NULL) {
    157     *BufferSize = 0;
    158     return EFI_OUT_OF_RESOURCES;
    159   }
    160 
    161   Region->Buffer = AllocateCopyPool (*BufferSize, Buffer);
    162   if (Region->Buffer == NULL) {
    163     *BufferSize = 0;
    164     FreePool (Region);
    165     return EFI_OUT_OF_RESOURCES;
    166   }
    167 
    168   Region->Size   = *BufferSize;
    169   Region->Offset = File->Position;
    170 
    171   InsertTailList (&File->RegionToFlushLink, &Region->Link);
    172 
    173   File->Position += *BufferSize;
    174 
    175   if (File->Position > File->Info->FileSize) {
    176     File->Info->FileSize = File->Position;
    177   }
    178 
    179   return EFI_SUCCESS;
    180 }
    181 
    182 /**
    183   Set a file's current position.
    184 
    185   @param[in]  This      A pointer to the EFI_FILE_PROTOCOL instance that is
    186                         the file handle to set the requested position on.
    187   @param[in]  Position  The byte position from the start of the file to set.
    188 
    189   @retval  EFI_SUCCESS            The position was set.
    190   @retval  EFI_INVALID_PARAMETER  At least one of the parameters is invalid.
    191 
    192 **/
    193 EFIAPI
    194 EFI_STATUS
    195 BootMonFsSetPosition (
    196   IN EFI_FILE_PROTOCOL  *This,
    197   IN UINT64             Position
    198   )
    199 {
    200   BOOTMON_FS_FILE  *File;
    201 
    202   if (This == NULL) {
    203     return EFI_INVALID_PARAMETER;
    204   }
    205   File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);
    206   if (File->Info == NULL) {
    207     return EFI_INVALID_PARAMETER;
    208   }
    209 
    210   //
    211   // UEFI Spec section 12.5:
    212   // "Seeking to position 0xFFFFFFFFFFFFFFFF causes the current position to
    213   // be set to the end of the file."
    214   //
    215   if (Position == 0xFFFFFFFFFFFFFFFF) {
    216     Position = File->Info->FileSize;
    217   }
    218 
    219   File->Position = Position;
    220 
    221   return EFI_SUCCESS;
    222 }
    223 
    224 /**
    225   Return a file's current position.
    226 
    227   @param[in]   This      A pointer to the EFI_FILE_PROTOCOL instance that is
    228                          the file handle to get the current position on.
    229   @param[out]  Position  The address to return the file's current position value.
    230 
    231   @retval  EFI_SUCCESS            The position was returned.
    232   @retval  EFI_INVALID_PARAMETER  At least one of the parameters is invalid.
    233 
    234 **/
    235 EFIAPI
    236 EFI_STATUS
    237 BootMonFsGetPosition (
    238   IN  EFI_FILE_PROTOCOL *This,
    239   OUT UINT64            *Position
    240   )
    241 {
    242   BOOTMON_FS_FILE         *File;
    243 
    244   if (This == NULL) {
    245     return EFI_INVALID_PARAMETER;
    246   }
    247   File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);
    248   if (File->Info == NULL) {
    249     return EFI_INVALID_PARAMETER;
    250   }
    251 
    252   if (Position == NULL) {
    253     return EFI_INVALID_PARAMETER;
    254   }
    255 
    256   *Position = File->Position;
    257 
    258   return EFI_SUCCESS;
    259 }
    260