1 /* $NetBSD: sread.c,v 1.1.1.1 2014/04/01 16:16:07 jakllsch 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_FILE_HANDLE FileHandle, LastHandle; 65 EFI_STATUS Status; 66 EFI_LOAD_FILE_INTERFACE *LoadFile; 67 68 FHand = NULL; 69 UserFilePath = *FilePath; 70 71 // 72 // Allocate a new simple read handle structure 73 // 74 75 FHand = AllocateZeroPool (sizeof(SIMPLE_READ_HANDLE)); 76 if (!FHand) { 77 Status = EFI_OUT_OF_RESOURCES; 78 goto Done; 79 } 80 81 *SimpleReadHandle = (SIMPLE_READ_FILE) FHand; 82 FHand->Signature = SIMPLE_READ_SIGNATURE; 83 84 // 85 // If the caller passed a copy of the file, then just use it 86 // 87 88 if (SourceBuffer) { 89 FHand->Source = SourceBuffer; 90 FHand->SourceSize = SourceSize; 91 *DeviceHandle = NULL; 92 Status = EFI_SUCCESS; 93 goto Done; 94 } 95 96 // 97 // Attempt to access the file via a file system interface 98 // 99 100 FileHandle = NULL; 101 Status = uefi_call_wrapper(BS->LocateDevicePath, 3, &FileSystemProtocol, FilePath, DeviceHandle); 102 if (!EFI_ERROR(Status)) { 103 FileHandle = LibOpenRoot (*DeviceHandle); 104 } 105 106 Status = FileHandle ? EFI_SUCCESS : EFI_UNSUPPORTED; 107 108 // 109 // To access as a filesystem, the filepath should only 110 // contain filepath components. Follow the filepath nodes 111 // and find the target file 112 // 113 114 FilePathNode = (FILEPATH_DEVICE_PATH *) *FilePath; 115 while (!IsDevicePathEnd(&FilePathNode->Header)) { 116 117 // 118 // For filesystem access each node should be a filepath component 119 // 120 121 if (DevicePathType(&FilePathNode->Header) != MEDIA_DEVICE_PATH || 122 DevicePathSubType(&FilePathNode->Header) != MEDIA_FILEPATH_DP) { 123 Status = EFI_UNSUPPORTED; 124 } 125 126 // 127 // If there's been an error, stop 128 // 129 130 if (EFI_ERROR(Status)) { 131 break; 132 } 133 134 // 135 // Open this file path node 136 // 137 138 LastHandle = FileHandle; 139 FileHandle = NULL; 140 141 Status = uefi_call_wrapper( 142 LastHandle->Open, 143 5, 144 LastHandle, 145 &FileHandle, 146 FilePathNode->PathName, 147 EFI_FILE_MODE_READ, 148 0 149 ); 150 151 // 152 // Close the last node 153 // 154 155 uefi_call_wrapper(LastHandle->Close, 1, LastHandle); 156 157 // 158 // Get the next node 159 // 160 161 FilePathNode = (FILEPATH_DEVICE_PATH *) NextDevicePathNode(&FilePathNode->Header); 162 } 163 164 // 165 // If success, return the FHand 166 // 167 168 if (!EFI_ERROR(Status)) { 169 ASSERT(FileHandle); 170 FHand->FileHandle = FileHandle; 171 goto Done; 172 } 173 174 // 175 // Cleanup from filesystem access 176 // 177 178 if (FileHandle) { 179 uefi_call_wrapper(FileHandle->Close, 1, FileHandle); 180 FileHandle = NULL; 181 *FilePath = UserFilePath; 182 } 183 184 // 185 // If the error is something other then unsupported, return it 186 // 187 188 if (Status != EFI_UNSUPPORTED) { 189 goto Done; 190 } 191 192 // 193 // Attempt to access the file via the load file protocol 194 // 195 196 Status = LibDevicePathToInterface (&LoadFileProtocol, *FilePath, (VOID*)&LoadFile); 197 if (!EFI_ERROR(Status)) { 198 199 TempFilePath = DuplicateDevicePath (*FilePath); 200 201 TempFilePathPtr = TempFilePath; 202 203 Status = uefi_call_wrapper(BS->LocateDevicePath, 3, &LoadFileProtocol, &TempFilePath, DeviceHandle); 204 205 FreePool (TempFilePathPtr); 206 207 // 208 // Determine the size of buffer needed to hold the file 209 // 210 211 SourceSize = 0; 212 Status = uefi_call_wrapper( 213 LoadFile->LoadFile, 214 5, 215 LoadFile, 216 *FilePath, 217 BootPolicy, 218 &SourceSize, 219 NULL 220 ); 221 222 // 223 // We expect a buffer too small error to inform us 224 // of the buffer size needed 225 // 226 227 if (Status == EFI_BUFFER_TOO_SMALL) { 228 SourceBuffer = AllocatePool (SourceSize); 229 230 if (SourceBuffer) { 231 FHand->FreeBuffer = TRUE; 232 FHand->Source = SourceBuffer; 233 FHand->SourceSize = SourceSize; 234 235 Status = uefi_call_wrapper( 236 LoadFile->LoadFile, 237 5, 238 LoadFile, 239 *FilePath, 240 BootPolicy, 241 &SourceSize, 242 SourceBuffer 243 ); 244 } 245 } 246 247 // 248 // If success, return FHand 249 // 250 251 if (!EFI_ERROR(Status) || Status == EFI_ALREADY_STARTED) { 252 goto Done; 253 } 254 } 255 256 // 257 // Nothing else to try 258 // 259 260 DEBUG ((D_LOAD|D_WARN, "OpenSimpleReadFile: Device did not support a known load protocol\n")); 261 Status = EFI_UNSUPPORTED; 262 263 Done: 264 265 // 266 // If the file was not accessed, clean up 267 // 268 if (EFI_ERROR(Status) && (Status != EFI_ALREADY_STARTED)) { 269 if (FHand) { 270 if (FHand->FreeBuffer) { 271 FreePool (FHand->Source); 272 } 273 274 FreePool (FHand); 275 } 276 } 277 278 return Status; 279 } 280 281 EFI_STATUS 282 ReadSimpleReadFile ( 283 IN SIMPLE_READ_FILE UserHandle, 284 IN UINTN Offset, 285 IN OUT UINTN *ReadSize, 286 OUT VOID *Buffer 287 ) 288 { 289 UINTN EndPos; 290 SIMPLE_READ_HANDLE *FHand; 291 EFI_STATUS Status; 292 293 FHand = UserHandle; 294 ASSERT (FHand->Signature == SIMPLE_READ_SIGNATURE); 295 if (FHand->Source) { 296 297 // 298 // Move data from our local copy of the file 299 // 300 301 EndPos = Offset + *ReadSize; 302 if (EndPos > FHand->SourceSize) { 303 *ReadSize = FHand->SourceSize - Offset; 304 if (Offset >= FHand->SourceSize) { 305 *ReadSize = 0; 306 } 307 } 308 309 CopyMem (Buffer, (CHAR8 *) FHand->Source + Offset, *ReadSize); 310 Status = EFI_SUCCESS; 311 312 } else { 313 314 // 315 // Read data from the file 316 // 317 318 Status = uefi_call_wrapper(FHand->FileHandle->SetPosition, 2, FHand->FileHandle, Offset); 319 320 if (!EFI_ERROR(Status)) { 321 Status = uefi_call_wrapper(FHand->FileHandle->Read, 3, FHand->FileHandle, ReadSize, Buffer); 322 } 323 } 324 325 return Status; 326 } 327 328 329 VOID 330 CloseSimpleReadFile ( 331 IN SIMPLE_READ_FILE UserHandle 332 ) 333 { 334 SIMPLE_READ_HANDLE *FHand; 335 336 FHand = UserHandle; 337 ASSERT (FHand->Signature == SIMPLE_READ_SIGNATURE); 338 339 // 340 // Free any file handle we opened 341 // 342 343 if (FHand->FileHandle) { 344 uefi_call_wrapper(FHand->FileHandle->Close, 1, FHand->FileHandle); 345 } 346 347 // 348 // If we allocated the Source buffer, free it 349 // 350 351 if (FHand->FreeBuffer) { 352 FreePool (FHand->Source); 353 } 354 355 // 356 // Done with this simple read file handle 357 // 358 359 FreePool (FHand); 360 } 361