1169689Skan/*	$NetBSD: sread.c,v 1.2 2021/10/23 15:20:26 jmcneill Exp $	*/
2169689Skan
3132718Skan/*++
4132718Skan
5132718SkanCopyright (c) 1998  Intel Corporation
6132718Skan
7132718SkanModule Name:
8132718Skan
9132718Skan    sread.c
10132718Skan
11132718SkanAbstract:
12132718Skan
13132718Skan    Simple read file access
14132718Skan
15132718Skan
16132718Skan
17132718SkanRevision History
18132718Skan
19169689Skan--*/
20169689Skan
21132718Skan#include "lib.h"
22169689Skan
23169689Skan#define SIMPLE_READ_SIGNATURE       EFI_SIGNATURE_32('s','r','d','r')
24169689Skantypedef struct _SIMPLE_READ_FILE {
25169689Skan    UINTN               Signature;
26169689Skan    BOOLEAN             FreeBuffer;
27169689Skan    VOID                *Source;
28169689Skan    UINTN               SourceSize;
29169689Skan    EFI_FILE_HANDLE     FileHandle;
30169689Skan} SIMPLE_READ_HANDLE;
31169689Skan
32169689Skan
33169689Skan
34169689SkanEFI_STATUS
35169689SkanOpenSimpleReadFile (
36169689Skan    IN BOOLEAN                  BootPolicy,
37169689Skan    IN VOID                     *SourceBuffer   OPTIONAL,
38169689Skan    IN UINTN                    SourceSize,
39169689Skan    IN OUT EFI_DEVICE_PATH      **FilePath,
40169689Skan    OUT EFI_HANDLE              *DeviceHandle,
41169689Skan    OUT SIMPLE_READ_FILE        *SimpleReadHandle
42169689Skan    )
43169689Skan/*++
44169689Skan
45169689SkanRoutine Description:
46169689Skan
47169689Skan    Opens a file for (simple) reading.  The simple read abstraction
48169689Skan    will access the file either from a memory copy, from a file
49169689Skan    system interface, or from the load file interface.
50169689Skan
51169689SkanArguments:
52169689Skan
53169689SkanReturns:
54169689Skan
55169689Skan    A handle to access the file
56169689Skan
57169689Skan--*/
58169689Skan{
59169689Skan    SIMPLE_READ_HANDLE          *FHand;
60169689Skan    EFI_DEVICE_PATH             *UserFilePath;
61169689Skan    EFI_DEVICE_PATH             *TempFilePath;
62169689Skan    EFI_DEVICE_PATH             *TempFilePathPtr;
63169689Skan    FILEPATH_DEVICE_PATH        *FilePathNode;
64169689Skan    EFI_DEVICE_PATH_PROTOCOL    *AlignedFilePath;
65169689Skan    EFI_FILE_HANDLE             FileHandle, LastHandle;
66169689Skan    EFI_STATUS                  Status;
67169689Skan    EFI_LOAD_FILE_INTERFACE     *LoadFile;
68169689Skan
69169689Skan    FHand = NULL;
70169689Skan    AlignedFilePath = NULL;
71169689Skan    UserFilePath = *FilePath;
72169689Skan
73169689Skan    //
74169689Skan    // Allocate a new simple read handle structure
75169689Skan    //
76169689Skan
77169689Skan    FHand = AllocateZeroPool (sizeof(SIMPLE_READ_HANDLE));
78169689Skan    if (!FHand) {
79169689Skan        Status = EFI_OUT_OF_RESOURCES;
80169689Skan        goto Done;
81169689Skan    }
82169689Skan
83169689Skan    *SimpleReadHandle = (SIMPLE_READ_FILE) FHand;
84169689Skan    FHand->Signature = SIMPLE_READ_SIGNATURE;
85169689Skan
86169689Skan    //
87169689Skan    // If the caller passed a copy of the file, then just use it
88169689Skan    //
89169689Skan
90169689Skan    if (SourceBuffer) {
91169689Skan        FHand->Source = SourceBuffer;
92169689Skan        FHand->SourceSize = SourceSize;
93169689Skan        *DeviceHandle = NULL;
94169689Skan        Status = EFI_SUCCESS;
95169689Skan        goto Done;
96169689Skan    }
97169689Skan
98169689Skan    //
99169689Skan    // Attempt to access the file via a file system interface
100169689Skan    //
101169689Skan
102169689Skan    FileHandle = NULL;
103169689Skan    Status = uefi_call_wrapper(BS->LocateDevicePath, 3, &FileSystemProtocol, FilePath, DeviceHandle);
104169689Skan    if (!EFI_ERROR(Status)) {
105169689Skan        FileHandle = LibOpenRoot (*DeviceHandle);
106169689Skan    }
107169689Skan
108169689Skan    Status = FileHandle ? EFI_SUCCESS : EFI_UNSUPPORTED;
109169689Skan
110169689Skan    //
111169689Skan    // Duplicate FilePath to make sure it is aligned so that
112169689Skan    // FilePathNode->PathName below is 16-bit aligned.
113169689Skan    //
114169689Skan    AlignedFilePath = DuplicateDevicePath(*FilePath);
115169689Skan    if (AlignedFilePath == NULL) {
116169689Skan        if (FileHandle != NULL) {
117169689Skan            uefi_call_wrapper(FileHandle->Close, 1, FileHandle);
118169689Skan        }
119169689Skan        return EFI_OUT_OF_RESOURCES;
120169689Skan    }
121169689Skan
122169689Skan    //
123169689Skan    // To access as a filesystem, the filepath should only
124169689Skan    // contain filepath components.  Follow the filepath nodes
125169689Skan    // and find the target file
126169689Skan    //
127169689Skan
128169689Skan    FilePathNode = (FILEPATH_DEVICE_PATH *)AlignedFilePath;
129169689Skan    while (!IsDevicePathEnd(&FilePathNode->Header)) {
130169689Skan
131169689Skan        //
132169689Skan        // For filesystem access each node should be a filepath component
133169689Skan        //
134169689Skan
135169689Skan        if (DevicePathType(&FilePathNode->Header) != MEDIA_DEVICE_PATH ||
136169689Skan            DevicePathSubType(&FilePathNode->Header) != MEDIA_FILEPATH_DP) {
137169689Skan            Status = EFI_UNSUPPORTED;
138169689Skan        }
139169689Skan
140169689Skan        //
141169689Skan        // If there's been an error, stop
142132718Skan        //
143132718Skan
144132718Skan        if (EFI_ERROR(Status)) {
145132718Skan            break;
146132718Skan        }
147169689Skan
148169689Skan        //
149132718Skan        // Open this file path node
150132718Skan        //
151169689Skan
152132718Skan        LastHandle = FileHandle;
153132718Skan        FileHandle = NULL;
154132718Skan
155132718Skan        Status = uefi_call_wrapper(
156132718Skan			LastHandle->Open,
157132718Skan			5,
158132718Skan                        LastHandle,
159132718Skan                        &FileHandle,
160132718Skan                        FilePathNode->PathName,
161132718Skan                        EFI_FILE_MODE_READ,
162132718Skan                        0
163132718Skan                        );
164132718Skan
165169689Skan        //
166169689Skan        // Close the last node
167169689Skan        //
168169689Skan
169132718Skan        uefi_call_wrapper(LastHandle->Close, 1, LastHandle);
170132718Skan
171132718Skan        //
172132718Skan        // Get the next node
173169689Skan        //
174169689Skan
175169689Skan        FilePathNode = (FILEPATH_DEVICE_PATH *) NextDevicePathNode(&FilePathNode->Header);
176132718Skan    }
177169689Skan
178169689Skan    //
179132718Skan    // If success, return the FHand
180169689Skan    //
181132718Skan
182132718Skan    if (!EFI_ERROR(Status)) {
183169689Skan        ASSERT(FileHandle);
184169689Skan        FHand->FileHandle = FileHandle;
185132718Skan        goto Done;
186169689Skan    }
187169689Skan
188132718Skan    //
189132718Skan    // Cleanup from filesystem access
190132718Skan    //
191132718Skan
192132718Skan    if (FileHandle) {
193132718Skan        uefi_call_wrapper(FileHandle->Close, 1, FileHandle);
194132718Skan        FileHandle = NULL;
195132718Skan        *FilePath = UserFilePath;
196169689Skan    }
197169689Skan
198169689Skan    //
199169689Skan    // If the error is something other then unsupported, return it
200169689Skan    //
201169689Skan
202169689Skan    if (Status != EFI_UNSUPPORTED) {
203169689Skan        goto Done;
204169689Skan    }
205169689Skan
206169689Skan    //
207169689Skan    // Attempt to access the file via the load file protocol
208169689Skan    //
209169689Skan
210169689Skan    Status = LibDevicePathToInterface (&LoadFileProtocol, *FilePath, (VOID*)&LoadFile);
211169689Skan    if (!EFI_ERROR(Status)) {
212169689Skan
213169689Skan        TempFilePath = DuplicateDevicePath (*FilePath);
214169689Skan
215169689Skan        TempFilePathPtr = TempFilePath;
216169689Skan
217169689Skan        Status = uefi_call_wrapper(BS->LocateDevicePath, 3, &LoadFileProtocol, &TempFilePath, DeviceHandle);
218132718Skan
219132718Skan        FreePool (TempFilePathPtr);
220132718Skan
221132718Skan        //
222132718Skan        // Determine the size of buffer needed to hold the file
223132718Skan        //
224132718Skan
225169689Skan        SourceSize = 0;
226169689Skan        Status = uefi_call_wrapper(
227169689Skan		    LoadFile->LoadFile,
228169689Skan			5,
229169689Skan                    LoadFile,
230169689Skan                    *FilePath,
231169689Skan                    BootPolicy,
232169689Skan                    &SourceSize,
233169689Skan                    NULL
234169689Skan                    );
235169689Skan
236169689Skan        //
237169689Skan        // We expect a buffer too small error to inform us
238132718Skan        // of the buffer size needed
239132718Skan        //
240132718Skan
241132718Skan        if (Status == EFI_BUFFER_TOO_SMALL) {
242132718Skan            SourceBuffer = AllocatePool (SourceSize);
243132718Skan
244132718Skan            if (SourceBuffer) {
245132718Skan                FHand->FreeBuffer = TRUE;
246132718Skan                FHand->Source = SourceBuffer;
247132718Skan                FHand->SourceSize = SourceSize;
248132718Skan
249132718Skan                Status = uefi_call_wrapper(
250132718Skan			    LoadFile->LoadFile,
251132718Skan				5,
252132718Skan                            LoadFile,
253132718Skan                            *FilePath,
254169689Skan                            BootPolicy,
255169689Skan                            &SourceSize,
256169689Skan                            SourceBuffer
257169689Skan                            );
258169689Skan            }
259169689Skan        }
260132718Skan
261132718Skan        //
262132718Skan        // If success, return FHand
263132718Skan        //
264132718Skan
265132718Skan        if (!EFI_ERROR(Status) || Status == EFI_ALREADY_STARTED) {
266132718Skan            goto Done;
267169689Skan        }
268169689Skan    }
269132718Skan
270132718Skan    //
271132718Skan    // Nothing else to try
272132718Skan    //
273132718Skan
274169689Skan    DEBUG ((D_LOAD|D_WARN, "OpenSimpleReadFile: Device did not support a known load protocol\n"));
275169689Skan    Status = EFI_UNSUPPORTED;
276169689Skan
277169689SkanDone:
278169689Skan
279169689Skan    if (AlignedFilePath) {
280169689Skan        FreePool (AlignedFilePath);
281169689Skan    }
282169689Skan
283169689Skan    //
284169689Skan    // If the file was not accessed, clean up
285169689Skan    //
286169689Skan    if (EFI_ERROR(Status) && (Status != EFI_ALREADY_STARTED)) {
287169689Skan        if (FHand) {
288169689Skan            if (FHand->FreeBuffer) {
289169689Skan                FreePool (FHand->Source);
290169689Skan            }
291169689Skan
292169689Skan            FreePool (FHand);
293169689Skan        }
294169689Skan    }
295169689Skan
296169689Skan    return Status;
297169689Skan}
298169689Skan
299169689SkanEFI_STATUS
300169689SkanReadSimpleReadFile (
301169689Skan    IN SIMPLE_READ_FILE     UserHandle,
302169689Skan    IN UINTN                Offset,
303169689Skan    IN OUT UINTN            *ReadSize,
304169689Skan    OUT VOID                *Buffer
305169689Skan    )
306169689Skan{
307169689Skan    UINTN                   EndPos;
308169689Skan    SIMPLE_READ_HANDLE      *FHand;
309169689Skan    EFI_STATUS              Status;
310169689Skan
311169689Skan    FHand = UserHandle;
312169689Skan    ASSERT (FHand->Signature == SIMPLE_READ_SIGNATURE);
313169689Skan    if (FHand->Source) {
314169689Skan
315169689Skan        //
316169689Skan        // Move data from our local copy of the file
317169689Skan        //
318169689Skan
319169689Skan        EndPos = Offset + *ReadSize;
320169689Skan        if (EndPos > FHand->SourceSize) {
321169689Skan            *ReadSize = FHand->SourceSize - Offset;
322169689Skan            if (Offset >= FHand->SourceSize) {
323169689Skan                *ReadSize = 0;
324169689Skan            }
325169689Skan        }
326169689Skan
327169689Skan        CopyMem (Buffer, (CHAR8 *) FHand->Source + Offset, *ReadSize);
328169689Skan        Status = EFI_SUCCESS;
329169689Skan
330169689Skan    } else {
331169689Skan
332169689Skan        //
333169689Skan        // Read data from the file
334169689Skan        //
335169689Skan
336169689Skan        Status = uefi_call_wrapper(FHand->FileHandle->SetPosition, 2, FHand->FileHandle, Offset);
337169689Skan
338169689Skan        if (!EFI_ERROR(Status)) {
339169689Skan            Status = uefi_call_wrapper(FHand->FileHandle->Read, 3, FHand->FileHandle, ReadSize, Buffer);
340169689Skan        }
341169689Skan    }
342169689Skan
343169689Skan    return Status;
344169689Skan}
345169689Skan
346169689Skan
347169689SkanVOID
348169689SkanCloseSimpleReadFile (
349169689Skan    IN SIMPLE_READ_FILE     UserHandle
350169689Skan    )
351132718Skan{
352132718Skan    SIMPLE_READ_HANDLE      *FHand;
353132718Skan
354132718Skan    FHand = UserHandle;
355132718Skan    ASSERT (FHand->Signature == SIMPLE_READ_SIGNATURE);
356132718Skan
357132718Skan    //
358132718Skan    // Free any file handle we opened
359132718Skan    //
360132718Skan
361132718Skan    if (FHand->FileHandle) {
362169689Skan        uefi_call_wrapper(FHand->FileHandle->Close, 1, FHand->FileHandle);
363169689Skan    }
364132718Skan
365132718Skan    //
366132718Skan    // If we allocated the Source buffer, free it
367132718Skan    //
368132718Skan
369169689Skan    if (FHand->FreeBuffer) {
370169689Skan        FreePool (FHand->Source);
371169689Skan    }
372169689Skan
373132718Skan    //
374132718Skan    // Done with this simple read file handle
375132718Skan    //
376132718Skan
377132718Skan    FreePool (FHand);
378132718Skan}
379169689Skan