1 /** @file 2 EBL commands for EFI and PI Devices 3 4 Copyright (c) 2007, Intel Corporation. All rights reserved.<BR> 5 Portions copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR> 6 (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR> 7 8 This program and the accompanying materials 9 are licensed and made available under the terms and conditions of the BSD License 10 which accompanies this distribution. The full text of the license may be found at 11 http://opensource.org/licenses/bsd-license.php 12 13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 15 16 **/ 17 18 #include "Ebl.h" 19 20 21 EFI_DXE_SERVICES *gDS = NULL; 22 23 24 /** 25 Print information about the File System device. 26 27 @param File Open File for the device 28 29 **/ 30 VOID 31 EblPrintFsInfo ( 32 IN EFI_OPEN_FILE *File 33 ) 34 { 35 CHAR16 *Str; 36 37 if (File == NULL) { 38 return; 39 } 40 41 AsciiPrint (" %a: ", File->DeviceName); 42 if (File->FsInfo != NULL) { 43 for (Str = File->FsInfo->VolumeLabel; *Str != '\0'; Str++) { 44 if (*Str == ' ') { 45 // UI makes you enter _ for space, so make the printout match that 46 *Str = '_'; 47 } 48 AsciiPrint ("%c", *Str); 49 } 50 AsciiPrint (":"); 51 if (File->FsInfo->ReadOnly) { 52 AsciiPrint ("ReadOnly"); 53 } 54 } 55 56 AsciiPrint ("\n"); 57 EfiClose (File); 58 } 59 60 61 /** 62 Print information about the FV devices. 63 64 @param File Open File for the device 65 66 **/ 67 VOID 68 EblPrintFvbInfo ( 69 IN EFI_OPEN_FILE *File 70 ) 71 { 72 if (File == NULL) { 73 return; 74 } 75 76 AsciiPrint (" %a: 0x%08lx - 0x%08lx : 0x%08x\n", File->DeviceName, File->FvStart, File->FvStart + File->FvSize - 1, File->FvSize); 77 EfiClose (File); 78 } 79 80 81 /** 82 Print information about the Blk IO devices. 83 If the device supports PXE dump out extra information 84 85 @param File Open File for the device 86 87 **/ 88 VOID 89 EblPrintBlkIoInfo ( 90 IN EFI_OPEN_FILE *File 91 ) 92 { 93 UINT64 DeviceSize; 94 UINTN Index; 95 UINTN Max; 96 EFI_OPEN_FILE *FsFile; 97 98 if (File == NULL) { 99 return; 100 } 101 102 AsciiPrint (" %a: ", File->DeviceName); 103 104 // print out name of file system, if any, on this block device 105 Max = EfiGetDeviceCounts (EfiOpenFileSystem); 106 if (Max != 0) { 107 for (Index = 0; Index < Max; Index++) { 108 FsFile = EfiDeviceOpenByType (EfiOpenFileSystem, Index); 109 if (FsFile != NULL) { 110 if (FsFile->EfiHandle == File->EfiHandle) { 111 AsciiPrint ("fs%d: ", Index); 112 EfiClose (FsFile); 113 break; 114 } 115 EfiClose (FsFile); 116 } 117 } 118 } 119 120 // Print out useful Block IO media properties 121 if (File->FsBlockIoMedia->RemovableMedia) { 122 AsciiPrint ("Removable "); 123 } 124 if (!File->FsBlockIoMedia->MediaPresent) { 125 AsciiPrint ("No Media\n"); 126 } else { 127 if (File->FsBlockIoMedia->LogicalPartition) { 128 AsciiPrint ("Partition "); 129 } 130 DeviceSize = MultU64x32 (File->FsBlockIoMedia->LastBlock + 1, File->FsBlockIoMedia->BlockSize); 131 AsciiPrint ("Size = 0x%lX\n", DeviceSize); 132 } 133 EfiClose (File); 134 } 135 136 /** 137 Print information about the Load File devices. 138 If the device supports PXE dump out extra information 139 140 @param File Open File for the device 141 142 **/ 143 VOID 144 EblPrintLoadFileInfo ( 145 IN EFI_OPEN_FILE *File 146 ) 147 { 148 EFI_DEVICE_PATH_PROTOCOL *DevicePathNode; 149 MAC_ADDR_DEVICE_PATH *MacAddr; 150 UINTN HwAddressSize; 151 UINTN Index; 152 153 if (File == NULL) { 154 return; 155 } 156 157 AsciiPrint (" %a: %a ", File->DeviceName, EblLoadFileBootTypeString (File->EfiHandle)); 158 159 if (File->DevicePath != NULL) { 160 // Try to print out the MAC address 161 for (DevicePathNode = File->DevicePath; 162 !IsDevicePathEnd (DevicePathNode); 163 DevicePathNode = NextDevicePathNode (DevicePathNode)) { 164 165 if ((DevicePathType (DevicePathNode) == MESSAGING_DEVICE_PATH) && (DevicePathSubType (DevicePathNode) == MSG_MAC_ADDR_DP)) { 166 MacAddr = (MAC_ADDR_DEVICE_PATH *)DevicePathNode; 167 168 HwAddressSize = sizeof (EFI_MAC_ADDRESS); 169 if (MacAddr->IfType == 0x01 || MacAddr->IfType == 0x00) { 170 HwAddressSize = 6; 171 } 172 173 AsciiPrint ("MAC "); 174 for (Index = 0; Index < HwAddressSize; Index++) { 175 AsciiPrint ("%02x", MacAddr->MacAddress.Addr[Index] & 0xff); 176 } 177 } 178 } 179 } 180 181 AsciiPrint ("\n"); 182 EfiClose (File); 183 return; 184 } 185 186 187 188 /** 189 Dump information about devices in the system. 190 191 fv: PI Firmware Volume 192 fs: EFI Simple File System 193 blk: EFI Block IO 194 LoadFile: EFI Load File Protocol (commonly PXE network boot) 195 196 Argv[0] - "device" 197 198 @param Argc Number of command arguments in Argv 199 @param Argv Array of strings that represent the parsed command line. 200 Argv[0] is the command name 201 202 @return EFI_SUCCESS 203 204 **/ 205 EFI_STATUS 206 EFIAPI 207 EblDeviceCmd ( 208 IN UINTN Argc, 209 IN CHAR8 **Argv 210 ) 211 { 212 UINTN Index; 213 UINTN CurrentRow; 214 UINTN Max; 215 216 CurrentRow = 0; 217 218 // Need to call here to make sure Device Counts are valid 219 EblUpdateDeviceLists (); 220 221 // Now we can print out the info... 222 Max = EfiGetDeviceCounts (EfiOpenFirmwareVolume); 223 if (Max != 0) { 224 AsciiPrint ("Firmware Volume Devices:\n"); 225 for (Index = 0; Index < Max; Index++) { 226 EblPrintFvbInfo (EfiDeviceOpenByType (EfiOpenFirmwareVolume, Index)); 227 if (EblAnyKeyToContinueQtoQuit (&CurrentRow, TRUE)) { 228 break; 229 } 230 } 231 } 232 233 Max = EfiGetDeviceCounts (EfiOpenFileSystem); 234 if (Max != 0) { 235 AsciiPrint ("File System Devices:\n"); 236 for (Index = 0; Index < Max; Index++) { 237 EblPrintFsInfo (EfiDeviceOpenByType (EfiOpenFileSystem, Index)); 238 if (EblAnyKeyToContinueQtoQuit (&CurrentRow, TRUE)) { 239 break; 240 } 241 } 242 } 243 244 Max = EfiGetDeviceCounts (EfiOpenBlockIo); 245 if (Max != 0) { 246 AsciiPrint ("Block IO Devices:\n"); 247 for (Index = 0; Index < Max; Index++) { 248 EblPrintBlkIoInfo (EfiDeviceOpenByType (EfiOpenBlockIo, Index)); 249 if (EblAnyKeyToContinueQtoQuit (&CurrentRow, TRUE)) { 250 break; 251 } 252 } 253 } 254 255 Max = EfiGetDeviceCounts (EfiOpenLoadFile); 256 if (Max != 0) { 257 AsciiPrint ("LoadFile Devices: (usually network)\n"); 258 for (Index = 0; Index < Max; Index++) { 259 EblPrintLoadFileInfo (EfiDeviceOpenByType (EfiOpenLoadFile, Index)); 260 if (EblAnyKeyToContinueQtoQuit (&CurrentRow, TRUE)) { 261 break; 262 } 263 } 264 } 265 266 return EFI_SUCCESS; 267 } 268 269 270 /** 271 Start an EFI image (PE32+ with EFI defined entry point). 272 273 Argv[0] - "start" 274 Argv[1] - device name and path 275 Argv[2] - "" string to pass into image being started 276 277 start fs1:\Temp\Fv.Fv "arg to pass" ; load an FV from the disk and pass the 278 ; ascii string arg to pass to the image 279 start fv0:\FV ; load an FV from an FV (not common) 280 start LoadFile0: ; load an FV via a PXE boot 281 282 @param Argc Number of command arguments in Argv 283 @param Argv Array of strings that represent the parsed command line. 284 Argv[0] is the command name 285 286 @return EFI_SUCCESS 287 288 **/ 289 EFI_STATUS 290 EFIAPI 291 EblStartCmd ( 292 IN UINTN Argc, 293 IN CHAR8 **Argv 294 ) 295 { 296 EFI_STATUS Status; 297 EFI_OPEN_FILE *File; 298 EFI_DEVICE_PATH_PROTOCOL *DevicePath; 299 EFI_HANDLE ImageHandle; 300 UINTN ExitDataSize; 301 CHAR16 *ExitData; 302 VOID *Buffer; 303 UINTN BufferSize; 304 EFI_LOADED_IMAGE_PROTOCOL *ImageInfo; 305 306 ImageHandle = NULL; 307 308 if (Argc < 2) { 309 return EFI_INVALID_PARAMETER; 310 } 311 312 File = EfiOpen (Argv[1], EFI_FILE_MODE_READ, 0); 313 if (File == NULL) { 314 return EFI_INVALID_PARAMETER; 315 } 316 317 DevicePath = File->DevicePath; 318 if (DevicePath != NULL) { 319 // check for device path form: blk, fv, fs, and loadfile 320 Status = gBS->LoadImage (FALSE, gImageHandle, DevicePath, NULL, 0, &ImageHandle); 321 } else { 322 // Check for buffer form: A0x12345678:0x1234 syntax. 323 // Means load using buffer starting at 0x12345678 of size 0x1234. 324 325 Status = EfiReadAllocatePool (File, &Buffer, &BufferSize); 326 if (EFI_ERROR (Status)) { 327 EfiClose (File); 328 return Status; 329 } 330 Status = gBS->LoadImage (FALSE, gImageHandle, DevicePath, Buffer, BufferSize, &ImageHandle); 331 332 FreePool (Buffer); 333 } 334 335 EfiClose (File); 336 337 if (!EFI_ERROR (Status)) { 338 if (Argc >= 3) { 339 // Argv[2] is a "" string that we pass directly to the EFI application without the "" 340 // We don't pass Argv[0] to the EFI Application (it's name) just the args 341 Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **)&ImageInfo); 342 ASSERT_EFI_ERROR (Status); 343 344 ImageInfo->LoadOptionsSize = (UINT32)AsciiStrSize (Argv[2]); 345 ImageInfo->LoadOptions = AllocatePool (ImageInfo->LoadOptionsSize); 346 AsciiStrCpyS (ImageInfo->LoadOptions, ImageInfo->LoadOptionsSize, Argv[2]); 347 } 348 349 // Transfer control to the EFI image we loaded with LoadImage() 350 Status = gBS->StartImage (ImageHandle, &ExitDataSize, &ExitData); 351 } 352 353 return Status; 354 } 355 356 357 /** 358 Load a Firmware Volume (FV) into memory from a device. This causes drivers in 359 the FV to be dispatched if the dependencies of the drivers are met. 360 361 Argv[0] - "loadfv" 362 Argv[1] - device name and path 363 364 loadfv fs1:\Temp\Fv.Fv ; load an FV from the disk 365 loadfv fv0:\FV ; load an FV from an FV (not common) 366 loadfv LoadFile0: ; load an FV via a PXE boot 367 368 @param Argc Number of command arguments in Argv 369 @param Argv Array of strings that represent the parsed command line. 370 Argv[0] is the command name 371 372 @return EFI_SUCCESS 373 374 **/ 375 EFI_STATUS 376 EFIAPI 377 EblLoadFvCmd ( 378 IN UINTN Argc, 379 IN CHAR8 **Argv 380 ) 381 { 382 EFI_STATUS Status; 383 EFI_OPEN_FILE *File; 384 VOID *FvStart; 385 UINTN FvSize; 386 EFI_HANDLE FvHandle; 387 388 389 if (Argc < 2) { 390 return EFI_INVALID_PARAMETER; 391 } 392 393 File = EfiOpen (Argv[1], EFI_FILE_MODE_READ, 0); 394 if (File == NULL) { 395 return EFI_INVALID_PARAMETER; 396 } 397 398 if (File->Type == EfiOpenMemoryBuffer) { 399 // If it is a address just use it. 400 Status = gDS->ProcessFirmwareVolume (File->Buffer, File->Size, &FvHandle); 401 } else { 402 // If it is a file read it into memory and use it 403 Status = EfiReadAllocatePool (File, &FvStart, &FvSize); 404 EfiClose (File); 405 if (EFI_ERROR (Status)) { 406 return Status; 407 } 408 409 Status = gDS->ProcessFirmwareVolume (FvStart, FvSize, &FvHandle); 410 if (EFI_ERROR (Status)) { 411 FreePool (FvStart); 412 } 413 } 414 return Status; 415 } 416 417 418 /** 419 Perform an EFI connect to connect devices that follow the EFI driver model. 420 If it is a PI system also call the dispatcher in case a new FV was made 421 available by one of the connect EFI drivers (this is not a common case). 422 423 Argv[0] - "connect" 424 425 @param Argc Number of command arguments in Argv 426 @param Argv Array of strings that represent the parsed command line. 427 Argv[0] is the command name 428 429 @return EFI_SUCCESS 430 431 **/ 432 EFI_STATUS 433 EFIAPI 434 EblConnectCmd ( 435 IN UINTN Argc, 436 IN CHAR8 **Argv 437 ) 438 { 439 EFI_STATUS Status; 440 UINTN HandleCount; 441 EFI_HANDLE *HandleBuffer; 442 UINTN Index; 443 BOOLEAN Dispatch; 444 EFI_OPEN_FILE *File; 445 446 447 if (Argc > 1) { 448 if ((*Argv[1] == 'd') || (*Argv[1] == 'D')) { 449 Status = gBS->LocateHandleBuffer ( 450 AllHandles, 451 NULL, 452 NULL, 453 &HandleCount, 454 &HandleBuffer 455 ); 456 if (EFI_ERROR (Status)) { 457 return Status; 458 } 459 460 for (Index = 0; Index < HandleCount; Index++) { 461 gBS->DisconnectController (HandleBuffer[Index], NULL, NULL); 462 } 463 464 // 465 // Given we disconnect our console we should go and do a connect now 466 // 467 } else { 468 File = EfiOpen (Argv[1], EFI_FILE_MODE_READ, 0); 469 if (File != NULL) { 470 AsciiPrint ("Connecting %a\n", Argv[1]); 471 gBS->ConnectController (File->EfiHandle, NULL, NULL, TRUE); 472 EfiClose (File); 473 return EFI_SUCCESS; 474 } 475 } 476 } 477 478 Dispatch = FALSE; 479 do { 480 Status = gBS->LocateHandleBuffer ( 481 AllHandles, 482 NULL, 483 NULL, 484 &HandleCount, 485 &HandleBuffer 486 ); 487 if (EFI_ERROR (Status)) { 488 return Status; 489 } 490 491 for (Index = 0; Index < HandleCount; Index++) { 492 gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE); 493 } 494 495 FreePool (HandleBuffer); 496 497 // 498 // Check to see if it's possible to dispatch an more DXE drivers. 499 // The BdsLibConnectAllEfi () may have made new DXE drivers show up. 500 // If anything is Dispatched Status == EFI_SUCCESS and we will try 501 // the connect again. 502 // 503 if (gDS == NULL) { 504 Status = EFI_NOT_FOUND; 505 } else { 506 Status = gDS->Dispatch (); 507 if (!EFI_ERROR (Status)) { 508 Dispatch = TRUE; 509 } 510 } 511 512 } while (!EFI_ERROR (Status)); 513 514 if (Dispatch) { 515 AsciiPrint ("Connected and dispatched\n"); 516 } else { 517 AsciiPrint ("Connect\n"); 518 } 519 520 return EFI_SUCCESS; 521 } 522 523 524 525 CHAR8 *gMemMapType[] = { 526 "reserved ", 527 "LoaderCode", 528 "LoaderData", 529 "BS_code ", 530 "BS_data ", 531 "RT_code ", 532 "RT_data ", 533 "available ", 534 "Unusable ", 535 "ACPI_recl ", 536 "ACPI_NVS ", 537 "MemMapIO ", 538 "MemPortIO ", 539 "PAL_code " 540 }; 541 542 543 /** 544 Dump out the EFI memory map 545 546 Argv[0] - "memmap" 547 548 @param Argc Number of command arguments in Argv 549 @param Argv Array of strings that represent the parsed command line. 550 Argv[0] is the command name 551 552 @return EFI_SUCCESS 553 554 **/ 555 EFI_STATUS 556 EFIAPI 557 EblMemMapCmd ( 558 IN UINTN Argc, 559 IN CHAR8 **Argv 560 ) 561 { 562 EFI_STATUS Status; 563 EFI_MEMORY_DESCRIPTOR *MemMap; 564 EFI_MEMORY_DESCRIPTOR *OrigMemMap; 565 UINTN MemMapSize; 566 UINTN MapKey; 567 UINTN DescriptorSize; 568 UINT32 DescriptorVersion; 569 UINT64 PageCount[EfiMaxMemoryType]; 570 UINTN Index; 571 UINT64 EntrySize; 572 UINTN CurrentRow; 573 UINT64 TotalMemory; 574 575 ZeroMem (PageCount, sizeof (PageCount)); 576 577 AsciiPrint ("EFI Memory Map\n"); 578 579 // First call is to figure out how big the buffer needs to be 580 MemMapSize = 0; 581 MemMap = NULL; 582 Status = gBS->GetMemoryMap (&MemMapSize, MemMap, &MapKey, &DescriptorSize, &DescriptorVersion); 583 if (Status == EFI_BUFFER_TOO_SMALL) { 584 // In case the AllocatPool changes the memory map we added in some extra descriptors 585 MemMapSize += (DescriptorSize * 0x100); 586 OrigMemMap = MemMap = AllocatePool (MemMapSize); 587 if (OrigMemMap != NULL) { 588 // 2nd time we get the data 589 Status = gBS->GetMemoryMap (&MemMapSize, MemMap, &MapKey, &DescriptorSize, &DescriptorVersion); 590 if (!EFI_ERROR (Status)) { 591 for (Index = 0, CurrentRow = 0; Index < MemMapSize/DescriptorSize; Index++) { 592 EntrySize = LShiftU64 (MemMap->NumberOfPages, 12); 593 AsciiPrint ("\n%a %016lx - %016lx: # %08lx %016lx", gMemMapType[MemMap->Type % EfiMaxMemoryType], MemMap->PhysicalStart, MemMap->PhysicalStart + EntrySize -1, MemMap->NumberOfPages, MemMap->Attribute); 594 if (EblAnyKeyToContinueQtoQuit (&CurrentRow, TRUE)) { 595 break; 596 } 597 598 PageCount[MemMap->Type % EfiMaxMemoryType] += MemMap->NumberOfPages; 599 MemMap = NEXT_MEMORY_DESCRIPTOR (MemMap, DescriptorSize); 600 } 601 } 602 603 for (Index = 0, TotalMemory = 0; Index < EfiMaxMemoryType; Index++) { 604 if (PageCount[Index] != 0) { 605 AsciiPrint ("\n %a %,7ld Pages (%,14ld)", gMemMapType[Index], PageCount[Index], LShiftU64 (PageCount[Index], 12)); 606 if (Index == EfiLoaderCode || 607 Index == EfiLoaderData || 608 Index == EfiBootServicesCode || 609 Index == EfiBootServicesData || 610 Index == EfiRuntimeServicesCode || 611 Index == EfiRuntimeServicesData || 612 Index == EfiConventionalMemory || 613 Index == EfiACPIReclaimMemory || 614 Index == EfiACPIMemoryNVS || 615 Index == EfiPalCode 616 ) { 617 // Count total memory 618 TotalMemory += PageCount[Index]; 619 } 620 } 621 } 622 623 AsciiPrint ("\nTotal Memory: %,ld MB (%,ld bytes)\n", RShiftU64 (TotalMemory, 8), LShiftU64 (TotalMemory, 12)); 624 625 FreePool (OrigMemMap); 626 627 } 628 } 629 630 return EFI_SUCCESS; 631 } 632 633 634 635 636 /** 637 Load a file into memory and optionally jump to it. A load address can be 638 specified or automatically allocated. A quoted command line can optionally 639 be passed into the image. 640 641 Argv[0] - "go" 642 Argv[1] - Device Name:path for the file to load 643 Argv[2] - Address to load to or '*' if the load address will be allocated 644 Argv[3] - Optional Entry point to the image. Image will be called if present 645 Argv[4] - "" string that will be passed as Argc & Argv to EntryPoint. Needs 646 to include the command name 647 648 go fv1:\EblCmdX 0x10000 0x10010 "EblCmdX Arg2 Arg3 Arg4"; - load EblCmdX 649 from FV1 to location 0x10000 and call the entry point at 0x10010 passing 650 in "EblCmdX Arg2 Arg3 Arg4" as the arguments. 651 652 go fv0:\EblCmdX * 0x10 "EblCmdX Arg2 Arg3 Arg4"; - load EblCmdX from FS0 653 to location allocated by this command and call the entry point at offset 0x10 654 passing in "EblCmdX Arg2 Arg3 Arg4" as the arguments. 655 656 go fv1:\EblCmdX 0x10000; Load EblCmdX to address 0x10000 and return 657 658 @param Argc Number of command arguments in Argv 659 @param Argv Array of strings that represent the parsed command line. 660 Argv[0] is the command name 661 662 @return EFI_SUCCESS 663 664 **/ 665 EFI_STATUS 666 EFIAPI 667 EblGoCmd ( 668 IN UINTN Argc, 669 IN CHAR8 **Argv 670 ) 671 { 672 EFI_STATUS Status; 673 EFI_OPEN_FILE *File; 674 VOID *Address; 675 UINTN Size; 676 EBL_COMMMAND EntryPoint; 677 UINTN EntryPointArgc; 678 CHAR8 *EntryPointArgv[MAX_ARGS]; 679 680 681 if (Argc <= 2) { 682 // device name and laod address are required 683 return EFI_SUCCESS; 684 } 685 686 File = EfiOpen (Argv[1], EFI_FILE_MODE_READ, 0); 687 if (File == NULL) { 688 AsciiPrint (" %a is not a valid path\n", Argv[1]); 689 return EFI_SUCCESS; 690 } 691 692 EntryPoint = (EBL_COMMMAND)((Argc > 3) ? (UINTN)AsciiStrHexToUintn (Argv[3]) : (UINTN)NULL); 693 if (Argv[2][0] == '*') { 694 // * Means allocate the buffer 695 Status = EfiReadAllocatePool (File, &Address, &Size); 696 697 // EntryPoint is relative to the start of the image 698 EntryPoint = (EBL_COMMMAND)((UINTN)EntryPoint + (UINTN)Address); 699 700 } else { 701 Address = (VOID *)AsciiStrHexToUintn (Argv[2]); 702 Size = File->Size; 703 704 // File->Size for LoadFile is lazy so we need to use the tell to figure it out 705 EfiTell (File, NULL); 706 Status = EfiRead (File, Address, &Size); 707 } 708 709 if (!EFI_ERROR (Status)) { 710 AsciiPrint ("Loaded %,d bytes to 0x%08x\n", Size, Address); 711 712 if (Argc > 3) { 713 if (Argc > 4) { 714 ParseArguments (Argv[4], &EntryPointArgc, EntryPointArgv); 715 } else { 716 EntryPointArgc = 1; 717 EntryPointArgv[0] = File->FileName; 718 } 719 720 Status = EntryPoint (EntryPointArgc, EntryPointArgv); 721 } 722 } 723 724 EfiClose (File); 725 return Status; 726 } 727 728 #define FILE_COPY_CHUNK 0x20000 729 730 EFI_STATUS 731 EFIAPI 732 EblFileCopyCmd ( 733 IN UINTN Argc, 734 IN CHAR8 **Argv 735 ) 736 { 737 EFI_OPEN_FILE *Source = NULL; 738 EFI_OPEN_FILE *Destination = NULL; 739 EFI_STATUS Status = EFI_SUCCESS; 740 VOID *Buffer = NULL; 741 UINTN Size; 742 UINTN Offset; 743 UINTN Chunk = FILE_COPY_CHUNK; 744 UINTN FileNameLen, DestFileNameLen; 745 CHAR8* DestFileName; 746 CHAR8* SrcFileName; 747 CHAR8* SrcPtr; 748 749 if (Argc < 3) { 750 return EFI_INVALID_PARAMETER; 751 } 752 753 DestFileName = Argv[2]; 754 FileNameLen = AsciiStrLen (DestFileName); 755 756 // Check if the destination file name looks like a directory 757 if ((DestFileName[FileNameLen-1] == '\\') || (DestFileName[FileNameLen-1] == ':')) { 758 // Set the pointer after the source drive (eg: after fs1:) 759 SrcPtr = AsciiStrStr (Argv[1], ":"); 760 if (SrcPtr == NULL) { 761 SrcPtr = Argv[1]; 762 } else { 763 SrcPtr++; 764 if (*SrcPtr == '\\') { 765 SrcPtr++; 766 } 767 } 768 769 if (*SrcPtr == '\0') { 770 AsciiPrint("Source file incorrect.\n"); 771 } 772 773 // Skip the Source Directories 774 while (1) { 775 SrcFileName = SrcPtr; 776 SrcPtr = AsciiStrStr (SrcPtr,"\\"); 777 if (SrcPtr != NULL) { 778 SrcPtr++; 779 } else { 780 break; 781 } 782 } 783 784 if (*SrcFileName == '\0') { 785 AsciiPrint("Source file incorrect (Error 2).\n"); 786 } 787 788 // Construct the destination filepath 789 DestFileNameLen = FileNameLen + AsciiStrLen (SrcFileName) + 1; 790 DestFileName = (CHAR8*)AllocatePool (DestFileNameLen); 791 AsciiStrCpyS (DestFileName, DestFileNameLen, Argv[2]); 792 AsciiStrCatS (DestFileName, DestFileNameLen, SrcFileName); 793 } 794 795 Source = EfiOpen(Argv[1], EFI_FILE_MODE_READ, 0); 796 if (Source == NULL) { 797 AsciiPrint("Source file open error.\n"); 798 return EFI_NOT_FOUND; 799 } 800 801 Destination = EfiOpen(DestFileName, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE, 0); 802 if (Destination == NULL) { 803 AsciiPrint("Destination file open error.\n"); 804 return EFI_NOT_FOUND; 805 } 806 807 Buffer = AllocatePool(FILE_COPY_CHUNK); 808 if (Buffer == NULL) { 809 goto Exit; 810 } 811 812 Size = EfiTell(Source, NULL); 813 814 for (Offset = 0; Offset + FILE_COPY_CHUNK <= Size; Offset += Chunk) { 815 Chunk = FILE_COPY_CHUNK; 816 817 Status = EfiRead(Source, Buffer, &Chunk); 818 if (EFI_ERROR(Status)) { 819 AsciiPrint("Read file error %r\n", Status); 820 goto Exit; 821 } 822 823 Status = EfiWrite(Destination, Buffer, &Chunk); 824 if (EFI_ERROR(Status)) { 825 AsciiPrint("Write file error %r\n", Status); 826 goto Exit; 827 } 828 } 829 830 // Any left over? 831 if (Offset < Size) { 832 Chunk = Size - Offset; 833 834 Status = EfiRead(Source, Buffer, &Chunk); 835 if (EFI_ERROR(Status)) { 836 AsciiPrint("Read file error %r\n", Status); 837 goto Exit; 838 } 839 840 Status = EfiWrite(Destination, Buffer, &Chunk); 841 if (EFI_ERROR(Status)) { 842 AsciiPrint("Write file error %r\n", Status); 843 goto Exit; 844 } 845 } 846 847 848 Exit: 849 if (Source != NULL) { 850 Status = EfiClose(Source); 851 if (EFI_ERROR(Status)) { 852 AsciiPrint("Source close error %r\n", Status); 853 } 854 } 855 if (Destination != NULL) { 856 Status = EfiClose(Destination); 857 if (EFI_ERROR(Status)) { 858 AsciiPrint("Destination close error %r\n", Status); 859 } 860 861 // Case when we have concated the filename to the destination directory 862 if (DestFileName != Argv[2]) { 863 FreePool (DestFileName); 864 } 865 } 866 867 if (Buffer != NULL) { 868 FreePool(Buffer); 869 } 870 871 return Status; 872 } 873 874 EFI_STATUS 875 EFIAPI 876 EblFileDiffCmd ( 877 IN UINTN Argc, 878 IN CHAR8 **Argv 879 ) 880 { 881 EFI_OPEN_FILE *File1 = NULL; 882 EFI_OPEN_FILE *File2 = NULL; 883 EFI_STATUS Status = EFI_SUCCESS; 884 VOID *Buffer1 = NULL; 885 VOID *Buffer2 = NULL; 886 UINTN Size1; 887 UINTN Size2; 888 UINTN Offset; 889 UINTN Chunk = FILE_COPY_CHUNK; 890 891 if (Argc != 3) { 892 return EFI_INVALID_PARAMETER; 893 } 894 895 File1 = EfiOpen(Argv[1], EFI_FILE_MODE_READ, 0); 896 if (File1 == NULL) { 897 AsciiPrint("File 1 open error.\n"); 898 return EFI_NOT_FOUND; 899 } 900 901 File2 = EfiOpen(Argv[2], EFI_FILE_MODE_READ, 0); 902 if (File2 == NULL) { 903 AsciiPrint("File 2 open error.\n"); 904 return EFI_NOT_FOUND; 905 } 906 907 Size1 = EfiTell(File1, NULL); 908 Size2 = EfiTell(File2, NULL); 909 910 if (Size1 != Size2) { 911 AsciiPrint("Files differ.\n"); 912 goto Exit; 913 } 914 915 Buffer1 = AllocatePool(FILE_COPY_CHUNK); 916 if (Buffer1 == NULL) { 917 goto Exit; 918 } 919 920 Buffer2 = AllocatePool(FILE_COPY_CHUNK); 921 if (Buffer2 == NULL) { 922 goto Exit; 923 } 924 925 for (Offset = 0; Offset + FILE_COPY_CHUNK <= Size1; Offset += Chunk) { 926 Chunk = FILE_COPY_CHUNK; 927 928 Status = EfiRead(File1, Buffer1, &Chunk); 929 if (EFI_ERROR(Status)) { 930 AsciiPrint("File 1 read error\n"); 931 goto Exit; 932 } 933 934 Status = EfiRead(File2, Buffer2, &Chunk); 935 if (EFI_ERROR(Status)) { 936 AsciiPrint("File 2 read error\n"); 937 goto Exit; 938 } 939 940 if (CompareMem(Buffer1, Buffer2, Chunk) != 0) { 941 AsciiPrint("Files differ.\n"); 942 goto Exit; 943 }; 944 } 945 946 // Any left over? 947 if (Offset < Size1) { 948 Chunk = Size1 - Offset; 949 950 Status = EfiRead(File1, Buffer1, &Chunk); 951 if (EFI_ERROR(Status)) { 952 AsciiPrint("File 1 read error\n"); 953 goto Exit; 954 } 955 956 Status = EfiRead(File2, Buffer2, &Chunk); 957 if (EFI_ERROR(Status)) { 958 AsciiPrint("File 2 read error\n"); 959 goto Exit; 960 } 961 } 962 963 if (CompareMem(Buffer1, Buffer2, Chunk) != 0) { 964 AsciiPrint("Files differ.\n"); 965 } else { 966 AsciiPrint("Files are identical.\n"); 967 } 968 969 Exit: 970 if (File1 != NULL) { 971 Status = EfiClose(File1); 972 if (EFI_ERROR(Status)) { 973 AsciiPrint("File 1 close error %r\n", Status); 974 } 975 } 976 977 if (File2 != NULL) { 978 Status = EfiClose(File2); 979 if (EFI_ERROR(Status)) { 980 AsciiPrint("File 2 close error %r\n", Status); 981 } 982 } 983 984 if (Buffer1 != NULL) { 985 FreePool(Buffer1); 986 } 987 988 if (Buffer2 != NULL) { 989 FreePool(Buffer2); 990 } 991 992 return Status; 993 } 994 995 GLOBAL_REMOVE_IF_UNREFERENCED const EBL_COMMAND_TABLE mCmdDeviceTemplate[] = 996 { 997 { 998 "connect", 999 "[d]; Connect all EFI devices. d means disconnect", 1000 NULL, 1001 EblConnectCmd 1002 }, 1003 { 1004 "device", 1005 "; Show information about boot devices", 1006 NULL, 1007 EblDeviceCmd 1008 }, 1009 { 1010 "go", 1011 " dev:path loadaddress entrypoint args; load to given address and jump in", 1012 NULL, 1013 EblGoCmd 1014 }, 1015 { 1016 "loadfv", 1017 " devname; Load PI FV from device", 1018 NULL, 1019 EblLoadFvCmd 1020 }, 1021 { 1022 "start", 1023 " path; EFI Boot Device:filepath. fs1:\\EFI\\BOOT.EFI", 1024 NULL, 1025 EblStartCmd 1026 }, 1027 { 1028 "memmap", 1029 "; dump EFI memory map", 1030 NULL, 1031 EblMemMapCmd 1032 }, 1033 { 1034 "cp", 1035 " file1 file2; copy file only.", 1036 NULL, 1037 EblFileCopyCmd 1038 }, 1039 { 1040 "diff", 1041 " file1 file2; compare files", 1042 NULL, 1043 EblFileDiffCmd 1044 } 1045 }; 1046 1047 1048 /** 1049 Initialize the commands in this in this file 1050 **/ 1051 1052 VOID 1053 EblInitializeDeviceCmd ( 1054 VOID 1055 ) 1056 { 1057 EfiGetSystemConfigurationTable (&gEfiDxeServicesTableGuid, (VOID **) &gDS); 1058 EblAddCommands (mCmdDeviceTemplate, sizeof (mCmdDeviceTemplate)/sizeof (EBL_COMMAND_TABLE)); 1059 } 1060 1061