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
BootMonFsReadFile(IN EFI_FILE_PROTOCOL * This,IN OUT UINTN * BufferSize,OUT VOID * Buffer)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
BootMonFsWriteFile(IN EFI_FILE_PROTOCOL * This,IN OUT UINTN * BufferSize,IN VOID * Buffer)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
BootMonFsSetPosition(IN EFI_FILE_PROTOCOL * This,IN UINT64 Position)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
BootMonFsGetPosition(IN EFI_FILE_PROTOCOL * This,OUT UINT64 * Position)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