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