Home | History | Annotate | Line # | Download | only in lib
      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
     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
    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
    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