xref: /netbsd-src/sys/external/bsd/gnu-efi/dist/lib/sread.c (revision b7b7574d3bf8eeb51a1fa3977b59142ec6434a55)
1 /*	$NetBSD: sread.c,v 1.1.1.1 2014/04/01 16:16:07 jakllsch Exp $	*/
2 
3 /*++
4 
5 Copyright (c) 1998  Intel Corporation
6 
7 Module Name:
8 
9     sread.c
10 
11 Abstract:
12 
13     Simple read file access
14 
15 
16 
17 Revision History
18 
19 --*/
20 
21 #include "lib.h"
22 
23 #define SIMPLE_READ_SIGNATURE       EFI_SIGNATURE_32('s','r','d','r')
24 typedef struct _SIMPLE_READ_FILE {
25     UINTN               Signature;
26     BOOLEAN             FreeBuffer;
27     VOID                *Source;
28     UINTN               SourceSize;
29     EFI_FILE_HANDLE     FileHandle;
30 } SIMPLE_READ_HANDLE;
31 
32 
33 
34 EFI_STATUS
35 OpenSimpleReadFile (
36     IN BOOLEAN                  BootPolicy,
37     IN VOID                     *SourceBuffer   OPTIONAL,
38     IN UINTN                    SourceSize,
39     IN OUT EFI_DEVICE_PATH      **FilePath,
40     OUT EFI_HANDLE              *DeviceHandle,
41     OUT SIMPLE_READ_FILE        *SimpleReadHandle
42     )
43 /*++
44 
45 Routine Description:
46 
47     Opens a file for (simple) reading.  The simple read abstraction
48     will access the file either from a memory copy, from a file
49     system interface, or from the load file interface.
50 
51 Arguments:
52 
53 Returns:
54 
55     A handle to access the file
56 
57 --*/
58 {
59     SIMPLE_READ_HANDLE          *FHand;
60     EFI_DEVICE_PATH             *UserFilePath;
61     EFI_DEVICE_PATH             *TempFilePath;
62     EFI_DEVICE_PATH             *TempFilePathPtr;
63     FILEPATH_DEVICE_PATH        *FilePathNode;
64     EFI_FILE_HANDLE             FileHandle, LastHandle;
65     EFI_STATUS                  Status;
66     EFI_LOAD_FILE_INTERFACE     *LoadFile;
67 
68     FHand = NULL;
69     UserFilePath = *FilePath;
70 
71     //
72     // Allocate a new simple read handle structure
73     //
74 
75     FHand = AllocateZeroPool (sizeof(SIMPLE_READ_HANDLE));
76     if (!FHand) {
77         Status = EFI_OUT_OF_RESOURCES;
78         goto Done;
79     }
80 
81     *SimpleReadHandle = (SIMPLE_READ_FILE) FHand;
82     FHand->Signature = SIMPLE_READ_SIGNATURE;
83 
84     //
85     // If the caller passed a copy of the file, then just use it
86     //
87 
88     if (SourceBuffer) {
89         FHand->Source = SourceBuffer;
90         FHand->SourceSize = SourceSize;
91         *DeviceHandle = NULL;
92         Status = EFI_SUCCESS;
93         goto Done;
94     }
95 
96     //
97     // Attempt to access the file via a file system interface
98     //
99 
100     FileHandle = NULL;
101     Status = uefi_call_wrapper(BS->LocateDevicePath, 3, &FileSystemProtocol, FilePath, DeviceHandle);
102     if (!EFI_ERROR(Status)) {
103         FileHandle = LibOpenRoot (*DeviceHandle);
104     }
105 
106     Status = FileHandle ? EFI_SUCCESS : EFI_UNSUPPORTED;
107 
108     //
109     // To access as a filesystem, the filepath should only
110     // contain filepath components.  Follow the filepath nodes
111     // and find the target file
112     //
113 
114     FilePathNode = (FILEPATH_DEVICE_PATH *) *FilePath;
115     while (!IsDevicePathEnd(&FilePathNode->Header)) {
116 
117         //
118         // For filesystem access each node should be a filepath component
119         //
120 
121         if (DevicePathType(&FilePathNode->Header) != MEDIA_DEVICE_PATH ||
122             DevicePathSubType(&FilePathNode->Header) != MEDIA_FILEPATH_DP) {
123             Status = EFI_UNSUPPORTED;
124         }
125 
126         //
127         // If there's been an error, stop
128         //
129 
130         if (EFI_ERROR(Status)) {
131             break;
132         }
133 
134         //
135         // Open this file path node
136         //
137 
138         LastHandle = FileHandle;
139         FileHandle = NULL;
140 
141         Status = uefi_call_wrapper(
142 			LastHandle->Open,
143 			5,
144                         LastHandle,
145                         &FileHandle,
146                         FilePathNode->PathName,
147                         EFI_FILE_MODE_READ,
148                         0
149                         );
150 
151         //
152         // Close the last node
153         //
154 
155         uefi_call_wrapper(LastHandle->Close, 1, LastHandle);
156 
157         //
158         // Get the next node
159         //
160 
161         FilePathNode = (FILEPATH_DEVICE_PATH *) NextDevicePathNode(&FilePathNode->Header);
162     }
163 
164     //
165     // If success, return the FHand
166     //
167 
168     if (!EFI_ERROR(Status)) {
169         ASSERT(FileHandle);
170         FHand->FileHandle = FileHandle;
171         goto Done;
172     }
173 
174     //
175     // Cleanup from filesystem access
176     //
177 
178     if (FileHandle) {
179         uefi_call_wrapper(FileHandle->Close, 1, FileHandle);
180         FileHandle = NULL;
181         *FilePath = UserFilePath;
182     }
183 
184     //
185     // If the error is something other then unsupported, return it
186     //
187 
188     if (Status != EFI_UNSUPPORTED) {
189         goto Done;
190     }
191 
192     //
193     // Attempt to access the file via the load file protocol
194     //
195 
196     Status = LibDevicePathToInterface (&LoadFileProtocol, *FilePath, (VOID*)&LoadFile);
197     if (!EFI_ERROR(Status)) {
198 
199         TempFilePath = DuplicateDevicePath (*FilePath);
200 
201         TempFilePathPtr = TempFilePath;
202 
203         Status = uefi_call_wrapper(BS->LocateDevicePath, 3, &LoadFileProtocol, &TempFilePath, DeviceHandle);
204 
205         FreePool (TempFilePathPtr);
206 
207         //
208         // Determine the size of buffer needed to hold the file
209         //
210 
211         SourceSize = 0;
212         Status = uefi_call_wrapper(
213 		    LoadFile->LoadFile,
214 			5,
215                     LoadFile,
216                     *FilePath,
217                     BootPolicy,
218                     &SourceSize,
219                     NULL
220                     );
221 
222         //
223         // We expect a buffer too small error to inform us
224         // of the buffer size needed
225         //
226 
227         if (Status == EFI_BUFFER_TOO_SMALL) {
228             SourceBuffer = AllocatePool (SourceSize);
229 
230             if (SourceBuffer) {
231                 FHand->FreeBuffer = TRUE;
232                 FHand->Source = SourceBuffer;
233                 FHand->SourceSize = SourceSize;
234 
235                 Status = uefi_call_wrapper(
236 			    LoadFile->LoadFile,
237 				5,
238                             LoadFile,
239                             *FilePath,
240                             BootPolicy,
241                             &SourceSize,
242                             SourceBuffer
243                             );
244             }
245         }
246 
247         //
248         // If success, return FHand
249         //
250 
251         if (!EFI_ERROR(Status) || Status == EFI_ALREADY_STARTED) {
252             goto Done;
253         }
254     }
255 
256     //
257     // Nothing else to try
258     //
259 
260     DEBUG ((D_LOAD|D_WARN, "OpenSimpleReadFile: Device did not support a known load protocol\n"));
261     Status = EFI_UNSUPPORTED;
262 
263 Done:
264 
265     //
266     // If the file was not accessed, clean up
267     //
268     if (EFI_ERROR(Status) && (Status != EFI_ALREADY_STARTED)) {
269         if (FHand) {
270             if (FHand->FreeBuffer) {
271                 FreePool (FHand->Source);
272             }
273 
274             FreePool (FHand);
275         }
276     }
277 
278     return Status;
279 }
280 
281 EFI_STATUS
282 ReadSimpleReadFile (
283     IN SIMPLE_READ_FILE     UserHandle,
284     IN UINTN                Offset,
285     IN OUT UINTN            *ReadSize,
286     OUT VOID                *Buffer
287     )
288 {
289     UINTN                   EndPos;
290     SIMPLE_READ_HANDLE      *FHand;
291     EFI_STATUS              Status;
292 
293     FHand = UserHandle;
294     ASSERT (FHand->Signature == SIMPLE_READ_SIGNATURE);
295     if (FHand->Source) {
296 
297         //
298         // Move data from our local copy of the file
299         //
300 
301         EndPos = Offset + *ReadSize;
302         if (EndPos > FHand->SourceSize) {
303             *ReadSize = FHand->SourceSize - Offset;
304             if (Offset >= FHand->SourceSize) {
305                 *ReadSize = 0;
306             }
307         }
308 
309         CopyMem (Buffer, (CHAR8 *) FHand->Source + Offset, *ReadSize);
310         Status = EFI_SUCCESS;
311 
312     } else {
313 
314         //
315         // Read data from the file
316         //
317 
318         Status = uefi_call_wrapper(FHand->FileHandle->SetPosition, 2, FHand->FileHandle, Offset);
319 
320         if (!EFI_ERROR(Status)) {
321             Status = uefi_call_wrapper(FHand->FileHandle->Read, 3, FHand->FileHandle, ReadSize, Buffer);
322         }
323     }
324 
325     return Status;
326 }
327 
328 
329 VOID
330 CloseSimpleReadFile (
331     IN SIMPLE_READ_FILE     UserHandle
332     )
333 {
334     SIMPLE_READ_HANDLE      *FHand;
335 
336     FHand = UserHandle;
337     ASSERT (FHand->Signature == SIMPLE_READ_SIGNATURE);
338 
339     //
340     // Free any file handle we opened
341     //
342 
343     if (FHand->FileHandle) {
344         uefi_call_wrapper(FHand->FileHandle->Close, 1, FHand->FileHandle);
345     }
346 
347     //
348     // If we allocated the Source buffer, free it
349     //
350 
351     if (FHand->FreeBuffer) {
352         FreePool (FHand->Source);
353     }
354 
355     //
356     // Done with this simple read file handle
357     //
358 
359     FreePool (FHand);
360 }
361