1 /** @file 2 * 3 * Copyright (c) 2012-2014, ARM Limited. All rights reserved. 4 * 5 * This program and the accompanying materials 6 * are licensed and made available under the terms and conditions of the BSD License 7 * which accompanies this distribution. The full text of the license may be found at 8 * http://opensource.org/licenses/bsd-license.php 9 * 10 * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 12 * 13 **/ 14 15 #include <Library/BaseMemoryLib.h> 16 #include <Library/DevicePathLib.h> 17 #include <Library/MemoryAllocationLib.h> 18 #include <Library/PrintLib.h> 19 #include <Library/UefiBootServicesTableLib.h> 20 21 #include <Protocol/DevicePathFromText.h> 22 #include <Protocol/DriverBinding.h> 23 24 #include "BootMonFsInternal.h" 25 26 EFI_DEVICE_PATH* mBootMonFsSupportedDevicePaths; 27 LIST_ENTRY mInstances; 28 29 EFI_FILE_PROTOCOL mBootMonFsRootTemplate = { 30 EFI_FILE_PROTOCOL_REVISION, 31 BootMonFsOpenFile, 32 BootMonFsCloseFile, 33 BootMonFsDeleteFail, 34 BootMonFsReadDirectory, 35 BootMonFsWriteFile, 36 BootMonFsGetPositionUnsupported, // UEFI Spec: GetPosition not valid on dirs 37 BootMonFsSetDirPosition, 38 BootMonFsGetInfo, 39 BootMonFsSetInfo, 40 BootMonFsFlushDirectory 41 }; 42 43 EFI_FILE_PROTOCOL mBootMonFsFileTemplate = { 44 EFI_FILE_PROTOCOL_REVISION, 45 BootMonFsOpenFile, 46 BootMonFsCloseFile, 47 BootMonFsDelete, 48 BootMonFsReadFile, 49 BootMonFsWriteFile, 50 BootMonFsGetPosition, 51 BootMonFsSetPosition, 52 BootMonFsGetInfo, 53 BootMonFsSetInfo, 54 BootMonFsFlushFile 55 }; 56 57 /** 58 Search for a file given its name coded in Ascii. 59 60 When searching through the files of the volume, if a file is currently not 61 open, its name was written on the media and is kept in RAM in the 62 "HwDescription.Footer.Filename[]" field of the file's description. 63 64 If a file is currently open, its name might not have been written on the 65 media yet, and as the "HwDescription" is a mirror in RAM of what is on the 66 media the "HwDescription.Footer.Filename[]" might be outdated. In that case, 67 the up to date name of the file is stored in the "Info" field of the file's 68 description. 69 70 @param[in] Instance Pointer to the description of the volume in which 71 the file has to be search for. 72 @param[in] AsciiFileName Name of the file. 73 74 @param[out] File Pointer to the description of the file if the 75 file was found. 76 77 @retval EFI_SUCCESS The file was found. 78 @retval EFI_NOT_FOUND The file was not found. 79 80 **/ 81 EFI_STATUS 82 BootMonGetFileFromAsciiFileName ( 83 IN BOOTMON_FS_INSTANCE *Instance, 84 IN CHAR8* AsciiFileName, 85 OUT BOOTMON_FS_FILE **File 86 ) 87 { 88 LIST_ENTRY *Entry; 89 BOOTMON_FS_FILE *FileEntry; 90 CHAR8 OpenFileAsciiFileName[MAX_NAME_LENGTH]; 91 CHAR8 *AsciiFileNameToCompare; 92 93 // Go through all the files in the list and return the file handle 94 for (Entry = GetFirstNode (&Instance->RootFile->Link); 95 !IsNull (&Instance->RootFile->Link, Entry); 96 Entry = GetNextNode (&Instance->RootFile->Link, Entry) 97 ) 98 { 99 FileEntry = BOOTMON_FS_FILE_FROM_LINK_THIS (Entry); 100 if (FileEntry->Info != NULL) { 101 UnicodeStrToAsciiStr (FileEntry->Info->FileName, OpenFileAsciiFileName); 102 AsciiFileNameToCompare = OpenFileAsciiFileName; 103 } else { 104 AsciiFileNameToCompare = FileEntry->HwDescription.Footer.Filename; 105 } 106 107 if (AsciiStrCmp (AsciiFileNameToCompare, AsciiFileName) == 0) { 108 *File = FileEntry; 109 return EFI_SUCCESS; 110 } 111 } 112 return EFI_NOT_FOUND; 113 } 114 115 EFI_STATUS 116 BootMonGetFileFromPosition ( 117 IN BOOTMON_FS_INSTANCE *Instance, 118 IN UINTN Position, 119 OUT BOOTMON_FS_FILE **File 120 ) 121 { 122 LIST_ENTRY *Entry; 123 BOOTMON_FS_FILE *FileEntry; 124 125 // Go through all the files in the list and return the file handle 126 for (Entry = GetFirstNode (&Instance->RootFile->Link); 127 !IsNull (&Instance->RootFile->Link, Entry) && (&Instance->RootFile->Link != Entry); 128 Entry = GetNextNode (&Instance->RootFile->Link, Entry) 129 ) 130 { 131 if (Position == 0) { 132 FileEntry = BOOTMON_FS_FILE_FROM_LINK_THIS (Entry); 133 *File = FileEntry; 134 return EFI_SUCCESS; 135 } 136 Position--; 137 } 138 return EFI_NOT_FOUND; 139 } 140 141 EFI_STATUS 142 BootMonFsCreateFile ( 143 IN BOOTMON_FS_INSTANCE *Instance, 144 OUT BOOTMON_FS_FILE **File 145 ) 146 { 147 BOOTMON_FS_FILE *NewFile; 148 149 NewFile = (BOOTMON_FS_FILE*)AllocateZeroPool (sizeof (BOOTMON_FS_FILE)); 150 if (NewFile == NULL) { 151 return EFI_OUT_OF_RESOURCES; 152 } 153 154 NewFile->Signature = BOOTMON_FS_FILE_SIGNATURE; 155 InitializeListHead (&NewFile->Link); 156 InitializeListHead (&NewFile->RegionToFlushLink); 157 NewFile->Instance = Instance; 158 159 // If the created file is the root file then create a directory EFI_FILE_PROTOCOL 160 if (Instance->RootFile == *File) { 161 CopyMem (&NewFile->File, &mBootMonFsRootTemplate, sizeof (mBootMonFsRootTemplate)); 162 } else { 163 CopyMem (&NewFile->File, &mBootMonFsFileTemplate, sizeof (mBootMonFsFileTemplate)); 164 } 165 *File = NewFile; 166 return EFI_SUCCESS; 167 } 168 169 STATIC 170 EFI_STATUS 171 SupportedDevicePathsInit ( 172 VOID 173 ) 174 { 175 EFI_STATUS Status; 176 CHAR16* DevicePathListStr; 177 CHAR16* DevicePathStr; 178 CHAR16* NextDevicePathStr; 179 EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *EfiDevicePathFromTextProtocol; 180 EFI_DEVICE_PATH_PROTOCOL *Instance; 181 182 Status = gBS->LocateProtocol (&gEfiDevicePathFromTextProtocolGuid, NULL, (VOID **)&EfiDevicePathFromTextProtocol); 183 ASSERT_EFI_ERROR (Status); 184 185 // Initialize Variable 186 DevicePathListStr = (CHAR16*)PcdGetPtr (PcdBootMonFsSupportedDevicePaths); 187 mBootMonFsSupportedDevicePaths = NULL; 188 189 // Extract the Device Path instances from the multi-device path string 190 while ((DevicePathListStr != NULL) && (DevicePathListStr[0] != L'\0')) { 191 NextDevicePathStr = StrStr (DevicePathListStr, L";"); 192 if (NextDevicePathStr == NULL) { 193 DevicePathStr = DevicePathListStr; 194 DevicePathListStr = NULL; 195 } else { 196 DevicePathStr = (CHAR16*)AllocateCopyPool ((NextDevicePathStr - DevicePathListStr + 1) * sizeof (CHAR16), DevicePathListStr); 197 if (DevicePathStr == NULL) { 198 return EFI_OUT_OF_RESOURCES; 199 } 200 *(DevicePathStr + (NextDevicePathStr - DevicePathListStr)) = L'\0'; 201 DevicePathListStr = NextDevicePathStr; 202 if (DevicePathListStr[0] == L';') { 203 DevicePathListStr++; 204 } 205 } 206 207 Instance = EfiDevicePathFromTextProtocol->ConvertTextToDevicePath (DevicePathStr); 208 ASSERT (Instance != NULL); 209 mBootMonFsSupportedDevicePaths = AppendDevicePathInstance (mBootMonFsSupportedDevicePaths, Instance); 210 211 if (NextDevicePathStr != NULL) { 212 FreePool (DevicePathStr); 213 } 214 FreePool (Instance); 215 } 216 217 if (mBootMonFsSupportedDevicePaths == NULL) { 218 return EFI_UNSUPPORTED; 219 } else { 220 return EFI_SUCCESS; 221 } 222 } 223 224 EFI_STATUS 225 EFIAPI 226 BootMonFsDriverSupported ( 227 IN EFI_DRIVER_BINDING_PROTOCOL *DriverBinding, 228 IN EFI_HANDLE ControllerHandle, 229 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath OPTIONAL 230 ) 231 { 232 EFI_DISK_IO_PROTOCOL *DiskIo; 233 EFI_DEVICE_PATH_PROTOCOL *DevicePathProtocol; 234 EFI_DEVICE_PATH_PROTOCOL *SupportedDevicePath; 235 EFI_DEVICE_PATH_PROTOCOL *SupportedDevicePaths; 236 EFI_STATUS Status; 237 UINTN Size1; 238 UINTN Size2; 239 240 // 241 // Open the IO Abstraction(s) needed to perform the supported test 242 // 243 Status = gBS->OpenProtocol ( 244 ControllerHandle, 245 &gEfiDiskIoProtocolGuid, 246 (VOID **) &DiskIo, 247 gImageHandle, 248 ControllerHandle, 249 EFI_OPEN_PROTOCOL_BY_DRIVER 250 ); 251 252 if (EFI_ERROR (Status)) { 253 return Status; 254 } 255 // 256 // Close the I/O Abstraction(s) used to perform the supported test 257 // 258 gBS->CloseProtocol ( 259 ControllerHandle, 260 &gEfiDiskIoProtocolGuid, 261 gImageHandle, 262 ControllerHandle 263 ); 264 265 // Check that BlockIo protocol instance exists 266 Status = gBS->OpenProtocol ( 267 ControllerHandle, 268 &gEfiBlockIoProtocolGuid, 269 NULL, 270 gImageHandle, 271 ControllerHandle, 272 EFI_OPEN_PROTOCOL_TEST_PROTOCOL 273 ); 274 if (EFI_ERROR (Status)) { 275 return Status; 276 } 277 278 // Check if a DevicePath is attached to the handle 279 Status = gBS->OpenProtocol ( 280 ControllerHandle, 281 &gEfiDevicePathProtocolGuid, 282 (VOID **)&DevicePathProtocol, 283 gImageHandle, 284 ControllerHandle, 285 EFI_OPEN_PROTOCOL_BY_DRIVER 286 ); 287 if (EFI_ERROR (Status)) { 288 return Status; 289 } 290 291 // Check if the Device Path is the one which contains the Boot Monitor File System 292 Size1 = GetDevicePathSize (DevicePathProtocol); 293 294 // Go through the list of Device Path Instances 295 Status = EFI_UNSUPPORTED; 296 SupportedDevicePaths = mBootMonFsSupportedDevicePaths; 297 while (SupportedDevicePaths != NULL) { 298 SupportedDevicePath = GetNextDevicePathInstance (&SupportedDevicePaths, &Size2); 299 300 if ((Size1 == Size2) && (CompareMem (DevicePathProtocol, SupportedDevicePath, Size1) == 0)) { 301 // The Device Path is supported 302 Status = EFI_SUCCESS; 303 break; 304 } 305 } 306 307 gBS->CloseProtocol (ControllerHandle, &gEfiDevicePathProtocolGuid, gImageHandle, ControllerHandle); 308 return Status; 309 } 310 311 EFI_STATUS 312 EFIAPI 313 BootMonFsDriverStart ( 314 IN EFI_DRIVER_BINDING_PROTOCOL *DriverBinding, 315 IN EFI_HANDLE ControllerHandle, 316 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath OPTIONAL 317 ) 318 { 319 BOOTMON_FS_INSTANCE *Instance; 320 EFI_STATUS Status; 321 UINTN VolumeNameSize; 322 EFI_FILE_INFO *Info; 323 324 Instance = AllocateZeroPool (sizeof (BOOTMON_FS_INSTANCE)); 325 if (Instance == NULL) { 326 return EFI_OUT_OF_RESOURCES; 327 } 328 329 // Initialize the BlockIo of the Instance 330 Status = gBS->OpenProtocol ( 331 ControllerHandle, 332 &gEfiBlockIoProtocolGuid, 333 (VOID **)&(Instance->BlockIo), 334 gImageHandle, 335 ControllerHandle, 336 EFI_OPEN_PROTOCOL_GET_PROTOCOL 337 ); 338 if (EFI_ERROR (Status)) { 339 goto Error; 340 } 341 342 Status = gBS->OpenProtocol ( 343 ControllerHandle, 344 &gEfiDiskIoProtocolGuid, 345 (VOID **)&(Instance->DiskIo), 346 gImageHandle, 347 ControllerHandle, 348 EFI_OPEN_PROTOCOL_BY_DRIVER 349 ); 350 if (EFI_ERROR (Status)) { 351 goto Error; 352 } 353 354 // 355 // Initialize the attributes of the Instance 356 // 357 Instance->Signature = BOOTMON_FS_SIGNATURE; 358 Instance->ControllerHandle = ControllerHandle; 359 Instance->Media = Instance->BlockIo->Media; 360 Instance->Binding = DriverBinding; 361 362 // Initialize the Simple File System Protocol 363 Instance->Fs.Revision = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION; 364 Instance->Fs.OpenVolume = OpenBootMonFsOpenVolume; 365 366 // Volume name + L' ' + '2' digit number 367 VolumeNameSize = StrSize (BOOTMON_FS_VOLUME_LABEL) + (3 * sizeof (CHAR16)); 368 369 // Initialize FileSystem Information 370 Instance->FsInfo.Size = SIZE_OF_EFI_FILE_SYSTEM_INFO + VolumeNameSize; 371 Instance->FsInfo.BlockSize = Instance->Media->BlockSize; 372 Instance->FsInfo.ReadOnly = FALSE; 373 Instance->FsInfo.VolumeSize = 374 Instance->Media->BlockSize * (Instance->Media->LastBlock - Instance->Media->LowestAlignedLba); 375 CopyMem (Instance->FsInfo.VolumeLabel, BOOTMON_FS_VOLUME_LABEL, StrSize (BOOTMON_FS_VOLUME_LABEL)); 376 377 // Initialize the root file 378 Status = BootMonFsCreateFile (Instance, &Instance->RootFile); 379 if (EFI_ERROR (Status)) { 380 goto Error; 381 } 382 383 Info = AllocateZeroPool (sizeof (EFI_FILE_INFO)); 384 if (Info == NULL) { 385 Status = EFI_OUT_OF_RESOURCES; 386 goto Error; 387 } 388 Instance->RootFile->Info = Info; 389 390 // Initialize the DevicePath of the Instance 391 Status = gBS->OpenProtocol ( 392 ControllerHandle, 393 &gEfiDevicePathProtocolGuid, 394 (VOID **)&(Instance->DevicePath), 395 gImageHandle, 396 ControllerHandle, 397 EFI_OPEN_PROTOCOL_GET_PROTOCOL 398 ); 399 if (EFI_ERROR (Status)) { 400 goto Error; 401 } 402 403 // 404 // Install the Simple File System Protocol 405 // 406 Status = gBS->InstallMultipleProtocolInterfaces ( 407 &ControllerHandle, 408 &gEfiSimpleFileSystemProtocolGuid, &Instance->Fs, 409 NULL 410 ); 411 if (EFI_ERROR (Status)) { 412 goto Error; 413 } 414 415 InsertTailList (&mInstances, &Instance->Link); 416 417 return EFI_SUCCESS; 418 419 Error: 420 421 if (Instance->RootFile != NULL) { 422 if (Instance->RootFile->Info != NULL) { 423 FreePool (Instance->RootFile->Info); 424 } 425 FreePool (Instance->RootFile); 426 } 427 FreePool (Instance); 428 429 return Status; 430 } 431 432 433 EFI_STATUS 434 EFIAPI 435 BootMonFsDriverStop ( 436 IN EFI_DRIVER_BINDING_PROTOCOL *DriverBinding, 437 IN EFI_HANDLE ControllerHandle, 438 IN UINTN NumberOfChildren, 439 IN EFI_HANDLE *ChildHandleBuffer OPTIONAL 440 ) 441 { 442 BOOTMON_FS_INSTANCE *Instance; 443 LIST_ENTRY *Link; 444 EFI_STATUS Status; 445 BOOLEAN InstanceFound; 446 447 // Find instance from ControllerHandle. 448 Instance = NULL; 449 InstanceFound = FALSE; 450 // For each instance in mInstances: 451 for (Link = GetFirstNode (&mInstances); !IsNull (&mInstances, Link); Link = GetNextNode (&mInstances, Link)) { 452 Instance = BOOTMON_FS_FROM_LINK (Link); 453 454 if (Instance->ControllerHandle == ControllerHandle) { 455 InstanceFound = TRUE; 456 break; 457 } 458 } 459 ASSERT (InstanceFound == TRUE); 460 461 gBS->CloseProtocol ( 462 ControllerHandle, 463 &gEfiDevicePathProtocolGuid, 464 DriverBinding->ImageHandle, 465 ControllerHandle); 466 467 gBS->CloseProtocol ( 468 ControllerHandle, 469 &gEfiDiskIoProtocolGuid, 470 DriverBinding->ImageHandle, 471 ControllerHandle); 472 473 gBS->CloseProtocol ( 474 ControllerHandle, 475 &gEfiBlockIoProtocolGuid, 476 DriverBinding->ImageHandle, 477 ControllerHandle); 478 479 Status = gBS->UninstallMultipleProtocolInterfaces ( 480 &ControllerHandle, 481 &gEfiSimpleFileSystemProtocolGuid, &Instance->Fs, 482 NULL); 483 484 FreePool (Instance->RootFile->Info); 485 FreePool (Instance->RootFile); 486 FreePool (Instance); 487 488 return Status; 489 } 490 491 // 492 // Simple Network Protocol Driver Global Variables 493 // 494 EFI_DRIVER_BINDING_PROTOCOL mBootMonFsDriverBinding = { 495 BootMonFsDriverSupported, 496 BootMonFsDriverStart, 497 BootMonFsDriverStop, 498 0xa, 499 NULL, 500 NULL 501 }; 502 503 EFI_STATUS 504 EFIAPI 505 BootMonFsEntryPoint ( 506 IN EFI_HANDLE ImageHandle, 507 IN EFI_SYSTEM_TABLE *SystemTable 508 ) 509 { 510 EFI_STATUS Status; 511 512 InitializeListHead (&mInstances); 513 514 // Initialize the list of Device Paths that could support BootMonFs 515 Status = SupportedDevicePathsInit (); 516 if (!EFI_ERROR (Status)) { 517 Status = gBS->InstallMultipleProtocolInterfaces ( 518 &ImageHandle, 519 &gEfiDriverBindingProtocolGuid, &mBootMonFsDriverBinding, 520 NULL 521 ); 522 ASSERT_EFI_ERROR (Status); 523 } else { 524 DEBUG((EFI_D_ERROR,"Warning: No Device Paths supporting BootMonFs have been defined in the PCD.\n")); 525 } 526 527 return Status; 528 } 529