2 EBL commands for EFI and PI Devices
4 Copyright (c) 2007, Intel Corporation<BR>
5 Portions copyright (c) 2008-2009, Apple Inc. All rights reserved.
7 All rights reserved. This program and the accompanying materials
8 are licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
20 EFI_DXE_SERVICES
*gDS
= NULL
;
24 Print information about the File System device.
26 @param File Open File for the device
31 IN EFI_OPEN_FILE
*File
38 AsciiPrint (" %a: ", File
->DeviceName
);
39 if (File
->FsInfo
!= NULL
) {
40 AsciiPrint ("%s: ", File
->FsInfo
->VolumeLabel
);
41 if (File
->FsInfo
->ReadOnly
) {
42 AsciiPrint ("ReadOnly");
52 Print information about the FV devices.
54 @param File Open File for the device
59 IN EFI_OPEN_FILE
*File
66 AsciiPrint (" %a: 0x%08lx - 0x%08lx : 0x%08x\n", File
->DeviceName
, File
->FvStart
, File
->FvStart
+ File
->FvSize
- 1, File
->FvSize
);
72 Print information about the Blk IO devices.
73 If the device supports PXE dump out extra information
75 @param File Open File for the device
80 IN EFI_OPEN_FILE
*File
86 EFI_OPEN_FILE
*FsFile
;
92 AsciiPrint (" %a: ", File
->DeviceName
);
94 // print out name of file system, if any, on this block device
95 Max
= EfiGetDeviceCounts (EfiOpenFileSystem
);
97 for (Index
= 0; Index
< Max
; Index
++) {
98 FsFile
= EfiDeviceOpenByType (EfiOpenFileSystem
, Index
);
100 if (FsFile
->EfiHandle
== File
->EfiHandle
) {
101 AsciiPrint ("fs%d: ", Index
);
110 // Print out useful Block IO media properties
111 if (File
->FsBlockIoMedia
.RemovableMedia
) {
112 AsciiPrint ("Removable ");
114 if (!File
->FsBlockIoMedia
.MediaPresent
) {
115 AsciiPrint ("No Media ");
117 if (File
->FsBlockIoMedia
.LogicalPartition
) {
118 AsciiPrint ("Partition ");
120 DeviceSize
= MultU64x32 (File
->FsBlockIoMedia
.LastBlock
+ 1, File
->FsBlockIoMedia
.BlockSize
);
121 AsciiPrint ("Size = 0x%lX\n", DeviceSize
);
127 Print information about the Load File devices.
128 If the device supports PXE dump out extra information
130 @param File Open File for the device
134 EblPrintLoadFileInfo (
135 IN EFI_OPEN_FILE
*File
138 EFI_DEVICE_PATH_PROTOCOL
*DevicePathNode
;
139 MAC_ADDR_DEVICE_PATH
*MacAddr
;
147 AsciiPrint (" %a: %a ", File
->DeviceName
, EblLoadFileBootTypeString (File
->EfiHandle
));
149 if (File
->DevicePath
!= NULL
) {
150 // Try to print out the MAC address
151 for (DevicePathNode
= File
->DevicePath
;
152 !IsDevicePathEnd (DevicePathNode
);
153 DevicePathNode
= NextDevicePathNode (DevicePathNode
)) {
155 if ((DevicePathType (DevicePathNode
) == MESSAGING_DEVICE_PATH
) && (DevicePathSubType (DevicePathNode
) == MSG_MAC_ADDR_DP
)) {
156 MacAddr
= (MAC_ADDR_DEVICE_PATH
*)DevicePathNode
;
158 HwAddressSize
= sizeof (EFI_MAC_ADDRESS
);
159 if (MacAddr
->IfType
== 0x01 || MacAddr
->IfType
== 0x00) {
164 for (Index
= 0; Index
< HwAddressSize
; Index
++) {
165 AsciiPrint ("%02x", MacAddr
->MacAddress
.Addr
[Index
] & 0xff);
179 Dump information about devices in the system.
181 fv: PI Firmware Volume
182 fs: EFI Simple File System
184 LoadFile: EFI Load File Protocol (commonly PXE network boot)
188 @param Argc Number of command arguments in Argv
189 @param Argv Array of strings that represent the parsed command line.
190 Argv[0] is the comamnd name
207 // Need to call here to make sure Device Counts are valid
208 EblUpdateDeviceLists ();
210 Max
= EfiGetDeviceCounts (EfiOpenFirmwareVolume
);
212 AsciiPrint ("Firmware Volume Devices:\n");
213 for (Index
= 0; Index
< Max
; Index
++) {
214 EblPrintFvbInfo (EfiDeviceOpenByType (EfiOpenFirmwareVolume
, Index
));
215 if (EblAnyKeyToContinueQtoQuit (&CurrentRow
, TRUE
)) {
221 Max
= EfiGetDeviceCounts (EfiOpenFileSystem
);
223 AsciiPrint ("File System Devices:\n");
224 for (Index
= 0; Index
< Max
; Index
++) {
225 EblPrintFsInfo (EfiDeviceOpenByType (EfiOpenFileSystem
, Index
));
226 if (EblAnyKeyToContinueQtoQuit (&CurrentRow
, TRUE
)) {
232 Max
= EfiGetDeviceCounts (EfiOpenBlockIo
);
234 AsciiPrint ("Block IO Devices:\n");
235 for (Index
= 0; Index
< Max
; Index
++) {
236 EblPrintBlkIoInfo (EfiDeviceOpenByType (EfiOpenBlockIo
, Index
));
237 if (EblAnyKeyToContinueQtoQuit (&CurrentRow
, TRUE
)) {
243 Max
= EfiGetDeviceCounts (EfiOpenLoadFile
);
245 AsciiPrint ("LoadFile Devices: (usually network)\n");
246 for (Index
= 0; Index
< Max
; Index
++) {
247 EblPrintLoadFileInfo (EfiDeviceOpenByType (EfiOpenLoadFile
, Index
));
248 if (EblAnyKeyToContinueQtoQuit (&CurrentRow
, TRUE
)) {
259 Start an EFI image (PE32+ with EFI defined entry point).
262 Argv[1] - device name and path
263 Argv[2] - "" string to pass into image being started
265 start fs1:\Temp\Fv.Fv "arg to pass" ; load an FV from the disk and pass the
266 ; ascii string arg to pass to the image
267 start fv0:\FV ; load an FV from an FV (not common)
268 start LoadFile0: ; load an FV via a PXE boot
270 @param Argc Number of command arguments in Argv
271 @param Argv Array of strings that represent the parsed command line.
272 Argv[0] is the comamnd name
285 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
286 EFI_HANDLE ImageHandle
;
291 EFI_LOADED_IMAGE_PROTOCOL
*ImageInfo
;
296 return EFI_INVALID_PARAMETER
;
299 File
= EfiOpen (Argv
[1], EFI_FILE_MODE_READ
, 0);
301 return EFI_INVALID_PARAMETER
;
304 DevicePath
= File
->DevicePath
;
305 if (DevicePath
!= NULL
) {
306 // check for device path form: blk, fv, fs, and loadfile
307 Status
= gBS
->LoadImage (FALSE
, gImageHandle
, DevicePath
, NULL
, 0, &ImageHandle
);
309 // Check for buffer form: A0x12345678:0x1234 syntax.
310 // Means load using buffer starting at 0x12345678 of size 0x1234.
312 Status
= EfiReadAllocatePool (File
, &Buffer
, &BufferSize
);
313 if (EFI_ERROR (Status
)) {
317 Status
= gBS
->LoadImage (FALSE
, gImageHandle
, DevicePath
, Buffer
, BufferSize
, &ImageHandle
);
324 if (!EFI_ERROR (Status
)) {
326 // Argv[2] is a "" string that we pass directly to the EFI application without the ""
327 // We don't pass Argv[0] to the EFI Application (it's name) just the args
328 Status
= gBS
->HandleProtocol (ImageHandle
, &gEfiLoadedImageProtocolGuid
, (VOID
**)&ImageInfo
);
329 ASSERT_EFI_ERROR (Status
);
331 ImageInfo
->LoadOptionsSize
= (UINT32
)AsciiStrSize (Argv
[2]);
332 ImageInfo
->LoadOptions
= AllocatePool (ImageInfo
->LoadOptionsSize
);
333 AsciiStrCpy (ImageInfo
->LoadOptions
, Argv
[2]);
336 // Transfer control to the EFI image we loaded with LoadImage()
337 Status
= gBS
->StartImage (ImageHandle
, &ExitDataSize
, &ExitData
);
345 Load a Firmware Volume (FV) into memory from a device. This causes drivers in
346 the FV to be dispatched if the dependancies of the drivers are met.
349 Argv[1] - device name and path
351 loadfv fs1:\Temp\Fv.Fv ; load an FV from the disk
352 loadfv fv0:\FV ; load an FV from an FV (not common)
353 loadfv LoadFile0: ; load an FV via a PXE boot
355 @param Argc Number of command arguments in Argv
356 @param Argv Array of strings that represent the parsed command line.
357 Argv[0] is the comamnd name
376 return EFI_INVALID_PARAMETER
;
379 File
= EfiOpen (Argv
[1], EFI_FILE_MODE_READ
, 0);
381 return EFI_INVALID_PARAMETER
;
384 if (File
->Type
== EfiOpenMemoryBuffer
) {
385 // If it is a address just use it.
386 Status
= gDS
->ProcessFirmwareVolume (File
->Buffer
, File
->Size
, &FvHandle
);
388 // If it is a file read it into memory and use it
389 Status
= EfiReadAllocatePool (File
, &FvStart
, &FvSize
);
391 if (EFI_ERROR (Status
)) {
395 Status
= gDS
->ProcessFirmwareVolume (FvStart
, FvSize
, &FvHandle
);
403 Perform an EFI connect to connect devices that follow the EFI driver model.
404 If it is a PI system also call the dispatcher in case a new FV was made
405 availible by one of the connect EFI drivers (this is not a common case).
409 @param Argc Number of command arguments in Argv
410 @param Argv Array of strings that represent the parsed command line.
411 Argv[0] is the comamnd name
424 EFI_HANDLE
*HandleBuffer
;
431 if ((*Argv
[1] == 'd') || (*Argv
[1] == 'D')) {
432 Status
= gBS
->LocateHandleBuffer (
439 if (EFI_ERROR (Status
)) {
443 for (Index
= 0; Index
< HandleCount
; Index
++) {
444 gBS
->DisconnectController (HandleBuffer
[Index
], NULL
, NULL
);
448 // Given we disconnect our console we should go and do a connect now
451 File
= EfiOpen (Argv
[1], EFI_FILE_MODE_READ
, 0);
453 AsciiPrint ("Connecting %a\n", Argv
[1]);
454 gBS
->ConnectController (File
->EfiHandle
, NULL
, NULL
, TRUE
);
463 Status
= gBS
->LocateHandleBuffer (
470 if (EFI_ERROR (Status
)) {
474 for (Index
= 0; Index
< HandleCount
; Index
++) {
475 gBS
->ConnectController (HandleBuffer
[Index
], NULL
, NULL
, TRUE
);
478 FreePool (HandleBuffer
);
481 // Check to see if it's possible to dispatch an more DXE drivers.
482 // The BdsLibConnectAllEfi () may have made new DXE drivers show up.
483 // If anything is Dispatched Status == EFI_SUCCESS and we will try
484 // the connect again.
487 Status
= EFI_NOT_FOUND
;
489 Status
= gDS
->Dispatch ();
490 if (!EFI_ERROR (Status
)) {
495 } while (!EFI_ERROR (Status
));
498 AsciiPrint ("Connected and dispatched\n");
500 AsciiPrint ("Connect\n");
508 CHAR8
*gMemMapType
[] = {
527 Dump out the EFI memory map
531 @param Argc Number of command arguments in Argv
532 @param Argv Array of strings that represent the parsed command line.
533 Argv[0] is the comamnd name
545 EFI_MEMORY_DESCRIPTOR
*MemMap
;
546 EFI_MEMORY_DESCRIPTOR
*OrigMemMap
;
549 UINTN DescriptorSize
;
550 UINT32 DescriptorVersion
;
551 UINT64 PageCount
[EfiMaxMemoryType
];
557 ZeroMem (PageCount
, sizeof (PageCount
));
559 AsciiPrint ("EFI Memory Map\n");
561 // First call is to figure out how big the buffer needs to be
564 Status
= gBS
->GetMemoryMap (&MemMapSize
, MemMap
, &MapKey
, &DescriptorSize
, &DescriptorVersion
);
565 if (Status
== EFI_BUFFER_TOO_SMALL
) {
566 // In case the AllocatPool changes the memory map we added in some extra descriptors
567 MemMapSize
+= (DescriptorSize
* 0x100);
568 OrigMemMap
= MemMap
= AllocatePool (MemMapSize
);
569 if (OrigMemMap
!= NULL
) {
570 // 2nd time we get the data
571 Status
= gBS
->GetMemoryMap (&MemMapSize
, MemMap
, &MapKey
, &DescriptorSize
, &DescriptorVersion
);
572 if (!EFI_ERROR (Status
)) {
573 for (Index
= 0, CurrentRow
= 0; Index
< MemMapSize
/DescriptorSize
; Index
++) {
574 EntrySize
= LShiftU64 (MemMap
->NumberOfPages
, 12);
575 AsciiPrint ("\n%a %016lx - %016lx: # %08lx %016lx", gMemMapType
[MemMap
->Type
% EfiMaxMemoryType
], MemMap
->PhysicalStart
, MemMap
->PhysicalStart
+ EntrySize
-1, MemMap
->NumberOfPages
, MemMap
->Attribute
);
576 if (EblAnyKeyToContinueQtoQuit (&CurrentRow
, TRUE
)) {
580 PageCount
[MemMap
->Type
% EfiMaxMemoryType
] += MemMap
->NumberOfPages
;
581 MemMap
= NEXT_MEMORY_DESCRIPTOR (MemMap
, DescriptorSize
);
585 for (Index
= 0, TotalMemory
= 0; Index
< EfiMaxMemoryType
; Index
++) {
586 if (PageCount
[Index
] != 0) {
587 AsciiPrint ("\n %a %,7ld Pages (%,14ld)", gMemMapType
[Index
], PageCount
[Index
], LShiftU64 (PageCount
[Index
], 12));
588 if (Index
== EfiLoaderCode
||
589 Index
== EfiLoaderData
||
590 Index
== EfiBootServicesCode
||
591 Index
== EfiBootServicesData
||
592 Index
== EfiRuntimeServicesCode
||
593 Index
== EfiRuntimeServicesData
||
594 Index
== EfiConventionalMemory
||
595 Index
== EfiACPIReclaimMemory
||
596 Index
== EfiACPIMemoryNVS
||
599 // Count total memory
600 TotalMemory
+= PageCount
[Index
];
605 AsciiPrint ("\nTotal Memory: %,ld MB (%,ld bytes)\n", RShiftU64 (TotalMemory
, 8), LShiftU64 (TotalMemory
, 12));
607 FreePool (OrigMemMap
);
619 Load a file into memory and optionally jump to it. A load addres can be
620 specified or automatically allocated. A quoted command line can optionally
621 be passed into the image.
624 Argv[1] - Device Name:path for the file to load
625 Argv[2] - Address to load to or '*' if the load address will be allocated
626 Argv[3] - Optional Entry point to the image. Image will be called if present
627 Argv[4] - "" string that will be passed as Argc & Argv to EntryPoint. Needs
628 to include the command name
630 go fv1:\EblCmdX 0x10000 0x10010 "EblCmdX Arg2 Arg3 Arg4"; - load EblCmdX
631 from FV1 to location 0x10000 and call the entry point at 0x10010 passing
632 in "EblCmdX Arg2 Arg3 Arg4" as the arguments.
634 go fv0:\EblCmdX * 0x10 "EblCmdX Arg2 Arg3 Arg4"; - load EblCmdX from FS0
635 to location allocated by this comamnd and call the entry point at offset 0x10
636 passing in "EblCmdX Arg2 Arg3 Arg4" as the arguments.
638 go fv1:\EblCmdX 0x10000; Load EblCmdX to address 0x10000 and return
640 @param Argc Number of command arguments in Argv
641 @param Argv Array of strings that represent the parsed command line.
642 Argv[0] is the comamnd name
657 EBL_COMMMAND EntryPoint
;
658 UINTN EntryPointArgc
;
659 CHAR8
*EntryPointArgv
[MAX_ARGS
];
663 // device name and laod address are required
667 File
= EfiOpen (Argv
[1], EFI_FILE_MODE_READ
, 0);
669 AsciiPrint (" %a is not a valid path\n", Argv
[1]);
673 EntryPoint
= (EBL_COMMMAND
)((Argc
> 3) ? (UINTN
)AsciiStrHexToUintn (Argv
[3]) : (UINTN
)NULL
);
674 if (Argv
[2][0] == '*') {
675 // * Means allocate the buffer
676 Status
= EfiReadAllocatePool (File
, &Address
, &Size
);
678 // EntryPoint is relatvie to the start of the image
679 EntryPoint
= (EBL_COMMMAND
)((UINTN
)EntryPoint
+ (UINTN
)Address
);
682 Address
= (VOID
*)AsciiStrHexToUintn (Argv
[2]);
685 // File->Size for LoadFile is lazy so we need to use the tell to figure it out
686 EfiTell (File
, NULL
);
687 Status
= EfiRead (File
, Address
, &Size
);
690 if (!EFI_ERROR (Status
)) {
691 AsciiPrint ("Loaded %,d bytes to 0x%08x\n", Size
, Address
);
695 ParseArguments (Argv
[4], &EntryPointArgc
, EntryPointArgv
);
698 EntryPointArgv
[0] = File
->FileName
;
701 Status
= EntryPoint (EntryPointArgc
, EntryPointArgv
);
709 #define FILE_COPY_CHUNK 0x20000
717 EFI_OPEN_FILE
*Source
= NULL
;
718 EFI_OPEN_FILE
*Destination
= NULL
;
719 EFI_STATUS Status
= EFI_SUCCESS
;
723 UINTN Chunk
= FILE_COPY_CHUNK
;
726 return EFI_INVALID_PARAMETER
;
729 Source
= EfiOpen(Argv
[1], EFI_FILE_MODE_READ
, 0);
730 if (Source
== NULL
) {
731 AsciiPrint("Source file open error.\n");
732 return EFI_NOT_FOUND
;
735 Destination
= EfiOpen(Argv
[2], EFI_FILE_MODE_READ
| EFI_FILE_MODE_WRITE
| EFI_FILE_MODE_CREATE
, 0);
736 if (Destination
== NULL
) {
737 AsciiPrint("Destination file open error.\n");
738 return EFI_NOT_FOUND
;
741 Buffer
= AllocatePool(FILE_COPY_CHUNK
);
742 if (Buffer
== NULL
) {
746 Size
= EfiTell(Source
, NULL
);
748 for (Offset
= 0; Offset
+ FILE_COPY_CHUNK
<= Size
; Offset
+= Chunk
) {
749 Chunk
= FILE_COPY_CHUNK
;
751 Status
= EfiRead(Source
, Buffer
, &Chunk
);
752 if (EFI_ERROR(Status
)) {
753 AsciiPrint("Read file error\n");
757 Status
= EfiWrite(Destination
, Buffer
, &Chunk
);
758 if (EFI_ERROR(Status
)) {
759 AsciiPrint("Write file error\n");
766 Chunk
= Size
- Offset
;
768 Status
= EfiRead(Source
, Buffer
, &Chunk
);
769 if (EFI_ERROR(Status
)) {
770 AsciiPrint("Read file error\n");
774 Status
= EfiWrite(Destination
, Buffer
, &Chunk
);
775 if (EFI_ERROR(Status
)) {
776 AsciiPrint("Write file error\n");
782 if (Source
!= NULL
) {
783 Status
= EfiClose(Source
);
784 if (EFI_ERROR(Status
)) {
785 AsciiPrint("Source close error %r\n", Status
);
789 if (Destination
!= NULL
) {
790 Status
= EfiClose(Destination
);
791 if (EFI_ERROR(Status
)) {
792 AsciiPrint("Destination close error %r\n", Status
);
796 if (Buffer
!= NULL
) {
809 EFI_OPEN_FILE
*File1
= NULL
;
810 EFI_OPEN_FILE
*File2
= NULL
;
811 EFI_STATUS Status
= EFI_SUCCESS
;
812 VOID
*Buffer1
= NULL
;
813 VOID
*Buffer2
= NULL
;
817 UINTN Chunk
= FILE_COPY_CHUNK
;
820 return EFI_INVALID_PARAMETER
;
823 File1
= EfiOpen(Argv
[1], EFI_FILE_MODE_READ
, 0);
825 AsciiPrint("File 1 open error.\n");
826 return EFI_NOT_FOUND
;
829 File2
= EfiOpen(Argv
[2], EFI_FILE_MODE_READ
, 0);
831 AsciiPrint("File 2 open error.\n");
832 return EFI_NOT_FOUND
;
835 Size1
= EfiTell(File1
, NULL
);
836 Size2
= EfiTell(File2
, NULL
);
838 if (Size1
!= Size2
) {
839 AsciiPrint("Files differ.\n");
843 Buffer1
= AllocatePool(FILE_COPY_CHUNK
);
844 if (Buffer1
== NULL
) {
848 Buffer2
= AllocatePool(FILE_COPY_CHUNK
);
849 if (Buffer2
== NULL
) {
853 for (Offset
= 0; Offset
+ FILE_COPY_CHUNK
<= Size1
; Offset
+= Chunk
) {
854 Chunk
= FILE_COPY_CHUNK
;
856 Status
= EfiRead(File1
, Buffer1
, &Chunk
);
857 if (EFI_ERROR(Status
)) {
858 AsciiPrint("File 1 read error\n");
862 Status
= EfiRead(File2
, Buffer2
, &Chunk
);
863 if (EFI_ERROR(Status
)) {
864 AsciiPrint("File 2 read error\n");
868 if (CompareMem(Buffer1
, Buffer2
, Chunk
) != 0) {
869 AsciiPrint("Files differ.\n");
875 if (Offset
< Size1
) {
876 Chunk
= Size1
- Offset
;
878 Status
= EfiRead(File1
, Buffer1
, &Chunk
);
879 if (EFI_ERROR(Status
)) {
880 AsciiPrint("File 1 read error\n");
884 Status
= EfiRead(File2
, Buffer2
, &Chunk
);
885 if (EFI_ERROR(Status
)) {
886 AsciiPrint("File 2 read error\n");
891 if (CompareMem(Buffer1
, Buffer2
, Chunk
) != 0) {
892 AsciiPrint("Files differ.\n");
894 AsciiPrint("Files are identical.\n");
899 Status
= EfiClose(File1
);
900 if (EFI_ERROR(Status
)) {
901 AsciiPrint("File 1 close error %r\n", Status
);
906 Status
= EfiClose(File2
);
907 if (EFI_ERROR(Status
)) {
908 AsciiPrint("File 2 close error %r\n", Status
);
912 if (Buffer1
!= NULL
) {
916 if (Buffer2
!= NULL
) {
923 GLOBAL_REMOVE_IF_UNREFERENCED
const EBL_COMMAND_TABLE mCmdDeviceTemplate
[] =
927 "[d]; Connect all EFI devices. d means disconnect",
933 "; Show information about boot devices",
939 " dev:path loadaddress entrypoint args; load to given address and jump in",
945 " devname; Load PI FV from device",
951 " path; EFI Boot Device:filepath. fs1:\\EFI\\BOOT.EFI",
957 "; dump EFI memory map",
963 " file1 file2; copy file",
969 " file1 file2; compare files",
977 Initialize the commands in this in this file
981 EblInitializeDeviceCmd (
985 EfiGetSystemConfigurationTable (&gEfiDxeServicesTableGuid
, (VOID
**) &gDS
);
986 EblAddCommands (mCmdDeviceTemplate
, sizeof (mCmdDeviceTemplate
)/sizeof (EBL_COMMAND_TABLE
));