1/* $NetBSD: sread.c,v 1.2 2021/10/23 15:20:26 jmcneill Exp $ */ 2 3/*++ 4 5Copyright (c) 1998 Intel Corporation 6 7Module Name: 8 9 sread.c 10 11Abstract: 12 13 Simple read file access 14 15 16 17Revision History 18 19--*/ 20 21#include "lib.h" 22 23#define SIMPLE_READ_SIGNATURE EFI_SIGNATURE_32('s','r','d','r') 24typedef 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 34EFI_STATUS 35OpenSimpleReadFile ( 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 45Routine 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 51Arguments: 52 53Returns: 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 277Done: 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 299EFI_STATUS 300ReadSimpleReadFile ( 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 347VOID 348CloseSimpleReadFile ( 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