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