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