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