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