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
90 AsciiPrint (" %a: ", File
->DeviceName
);
91 if (File
->FsBlockIoMedia
.RemovableMedia
) {
92 AsciiPrint ("Removable ");
94 if (!File
->FsBlockIoMedia
.MediaPresent
) {
95 AsciiPrint ("No Media ");
97 if (File
->FsBlockIoMedia
.LogicalPartition
) {
98 AsciiPrint ("Partition ");
100 DeviceSize
= MultU64x32 (File
->FsBlockIoMedia
.LastBlock
+ 1, File
->FsBlockIoMedia
.BlockSize
);
101 AsciiPrint ("Size = 0x%lX\n", DeviceSize
);
108 Print information about the Load File devices.
109 If the device supports PXE dump out extra information
111 @param File Open File for the device
115 EblPrintLoadFileInfo (
116 IN EFI_OPEN_FILE
*File
119 EFI_DEVICE_PATH_PROTOCOL
*DevicePathNode
;
120 MAC_ADDR_DEVICE_PATH
*MacAddr
;
128 AsciiPrint (" %a: %a ", File
->DeviceName
, EblLoadFileBootTypeString (File
->EfiHandle
));
130 if (File
->DevicePath
!= NULL
) {
131 // Try to print out the MAC address
132 for (DevicePathNode
= File
->DevicePath
;
133 !IsDevicePathEnd (DevicePathNode
);
134 DevicePathNode
= NextDevicePathNode (DevicePathNode
)) {
136 if ((DevicePathType (DevicePathNode
) == MESSAGING_DEVICE_PATH
) && (DevicePathSubType (DevicePathNode
) == MSG_MAC_ADDR_DP
)) {
137 MacAddr
= (MAC_ADDR_DEVICE_PATH
*)DevicePathNode
;
139 HwAddressSize
= sizeof (EFI_MAC_ADDRESS
);
140 if (MacAddr
->IfType
== 0x01 || MacAddr
->IfType
== 0x00) {
145 for (Index
= 0; Index
< HwAddressSize
; Index
++) {
146 AsciiPrint ("%02x", MacAddr
->MacAddress
.Addr
[Index
] & 0xff);
160 Dump information about devices in the system.
162 fv: PI Firmware Volume
163 fs: EFI Simple File System
165 LoadFile: EFI Load File Protocol (commonly PXE network boot)
169 @param Argc Number of command arguments in Argv
170 @param Argv Array of strings that represent the parsed command line.
171 Argv[0] is the comamnd name
188 // Need to call here to make sure Device Counts are valid
189 EblUpdateDeviceLists ();
191 Max
= EfiGetDeviceCounts (EfiOpenFirmwareVolume
);
193 AsciiPrint ("Firmware Volume Devices:\n");
194 for (Index
= 0; Index
< Max
; Index
++) {
195 EblPrintFvbInfo (EfiDeviceOpenByType (EfiOpenFirmwareVolume
, Index
));
196 if (EblAnyKeyToContinueQtoQuit (&CurrentRow
, TRUE
)) {
202 Max
= EfiGetDeviceCounts (EfiOpenFileSystem
);
204 AsciiPrint ("File System Devices:\n");
205 for (Index
= 0; Index
< Max
; Index
++) {
206 EblPrintFsInfo (EfiDeviceOpenByType (EfiOpenFileSystem
, Index
));
207 if (EblAnyKeyToContinueQtoQuit (&CurrentRow
, TRUE
)) {
213 Max
= EfiGetDeviceCounts (EfiOpenBlockIo
);
215 AsciiPrint ("Block IO Devices:\n");
216 for (Index
= 0; Index
< Max
; Index
++) {
217 EblPrintBlkIoInfo (EfiDeviceOpenByType (EfiOpenBlockIo
, Index
));
218 if (EblAnyKeyToContinueQtoQuit (&CurrentRow
, TRUE
)) {
224 Max
= EfiGetDeviceCounts (EfiOpenLoadFile
);
226 AsciiPrint ("LoadFile Devices: (usually network)\n");
227 for (Index
= 0; Index
< Max
; Index
++) {
228 EblPrintLoadFileInfo (EfiDeviceOpenByType (EfiOpenLoadFile
, Index
));
229 if (EblAnyKeyToContinueQtoQuit (&CurrentRow
, TRUE
)) {
240 Start an EFI image (PE32+ with EFI defined entry point).
243 Argv[1] - device name and path
244 Argv[2] - "" string to pass into image being started
246 start fs1:\Temp\Fv.Fv "arg to pass" ; load an FV from the disk and pass the
247 ; ascii string arg to pass to the image
248 start fv0:\FV ; load an FV from an FV (not common)
249 start LoadFile0: ; load an FV via a PXE boot
251 @param Argc Number of command arguments in Argv
252 @param Argv Array of strings that represent the parsed command line.
253 Argv[0] is the comamnd name
266 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
267 EFI_HANDLE ImageHandle
;
272 EFI_LOADED_IMAGE_PROTOCOL
*ImageInfo
;
277 return EFI_INVALID_PARAMETER
;
280 File
= EfiOpen (Argv
[1], EFI_FILE_MODE_READ
, 0);
282 return EFI_INVALID_PARAMETER
;
285 DevicePath
= File
->DevicePath
;
286 if (DevicePath
!= NULL
) {
287 // check for device path form: blk, fv, fs, and loadfile
288 Status
= gBS
->LoadImage (FALSE
, gImageHandle
, DevicePath
, NULL
, 0, &ImageHandle
);
290 // Check for buffer form: A0x12345678:0x1234 syntax.
291 // Means load using buffer starting at 0x12345678 of size 0x1234.
293 Status
= EfiReadAllocatePool (File
, &Buffer
, &BufferSize
);
294 if (EFI_ERROR (Status
)) {
298 Status
= gBS
->LoadImage (FALSE
, gImageHandle
, DevicePath
, Buffer
, BufferSize
, &ImageHandle
);
305 if (!EFI_ERROR (Status
)) {
307 // Argv[2] is a "" string that we pass directly to the EFI application without the ""
308 // We don't pass Argv[0] to the EFI Application (it's name) just the args
309 Status
= gBS
->HandleProtocol (ImageHandle
, &gEfiLoadedImageProtocolGuid
, (VOID
**)&ImageInfo
);
310 ASSERT_EFI_ERROR (Status
);
312 ImageInfo
->LoadOptionsSize
= (UINT32
)AsciiStrSize (Argv
[2]);
313 ImageInfo
->LoadOptions
= AllocatePool (ImageInfo
->LoadOptionsSize
);
314 AsciiStrCpy (ImageInfo
->LoadOptions
, Argv
[2]);
317 // Transfer control to the EFI image we loaded with LoadImage()
318 Status
= gBS
->StartImage (ImageHandle
, &ExitDataSize
, &ExitData
);
326 Load a Firmware Volume (FV) into memory from a device. This causes drivers in
327 the FV to be dispatched if the dependancies of the drivers are met.
330 Argv[1] - device name and path
332 loadfv fs1:\Temp\Fv.Fv ; load an FV from the disk
333 loadfv fv0:\FV ; load an FV from an FV (not common)
334 loadfv LoadFile0: ; load an FV via a PXE boot
336 @param Argc Number of command arguments in Argv
337 @param Argv Array of strings that represent the parsed command line.
338 Argv[0] is the comamnd name
357 return EFI_INVALID_PARAMETER
;
360 File
= EfiOpen (Argv
[1], EFI_FILE_MODE_READ
, 0);
362 return EFI_INVALID_PARAMETER
;
365 if (File
->Type
== EfiOpenMemoryBuffer
) {
366 // If it is a address just use it.
367 Status
= gDS
->ProcessFirmwareVolume (File
->Buffer
, File
->Size
, &FvHandle
);
369 // If it is a file read it into memory and use it
370 Status
= EfiReadAllocatePool (File
, &FvStart
, &FvSize
);
372 if (EFI_ERROR (Status
)) {
376 Status
= gDS
->ProcessFirmwareVolume (FvStart
, FvSize
, &FvHandle
);
384 Perform an EFI connect to connect devices that follow the EFI driver model.
385 If it is a PI system also call the dispatcher in case a new FV was made
386 availible by one of the connect EFI drivers (this is not a common case).
390 @param Argc Number of command arguments in Argv
391 @param Argv Array of strings that represent the parsed command line.
392 Argv[0] is the comamnd name
405 EFI_HANDLE
*HandleBuffer
;
412 if ((*Argv
[1] == 'd') || (*Argv
[1] == 'D')) {
413 Status
= gBS
->LocateHandleBuffer (
420 if (EFI_ERROR (Status
)) {
424 for (Index
= 0; Index
< HandleCount
; Index
++) {
425 gBS
->DisconnectController (HandleBuffer
[Index
], NULL
, NULL
);
429 // Given we disconnect our console we should go and do a connect now
432 File
= EfiOpen (Argv
[1], EFI_FILE_MODE_READ
, 0);
434 AsciiPrint ("Connecting %a\n", Argv
[1]);
435 gBS
->ConnectController (File
->EfiHandle
, NULL
, NULL
, TRUE
);
444 Status
= gBS
->LocateHandleBuffer (
451 if (EFI_ERROR (Status
)) {
455 for (Index
= 0; Index
< HandleCount
; Index
++) {
456 gBS
->ConnectController (HandleBuffer
[Index
], NULL
, NULL
, TRUE
);
459 FreePool (HandleBuffer
);
462 // Check to see if it's possible to dispatch an more DXE drivers.
463 // The BdsLibConnectAllEfi () may have made new DXE drivers show up.
464 // If anything is Dispatched Status == EFI_SUCCESS and we will try
465 // the connect again.
468 Status
= EFI_NOT_FOUND
;
470 Status
= gDS
->Dispatch ();
471 if (!EFI_ERROR (Status
)) {
476 } while (!EFI_ERROR (Status
));
479 AsciiPrint ("Connected and dispatched\n");
481 AsciiPrint ("Connect\n");
489 CHAR8
*gMemMapType
[] = {
508 Dump out the EFI memory map
512 @param Argc Number of command arguments in Argv
513 @param Argv Array of strings that represent the parsed command line.
514 Argv[0] is the comamnd name
526 EFI_MEMORY_DESCRIPTOR
*MemMap
;
527 EFI_MEMORY_DESCRIPTOR
*OrigMemMap
;
530 UINTN DescriptorSize
;
531 UINT32 DescriptorVersion
;
532 UINT64 PageCount
[EfiMaxMemoryType
];
538 ZeroMem (PageCount
, sizeof (PageCount
));
540 AsciiPrint ("EFI Memory Map\n");
542 // First call is to figure out how big the buffer needs to be
545 Status
= gBS
->GetMemoryMap (&MemMapSize
, MemMap
, &MapKey
, &DescriptorSize
, &DescriptorVersion
);
546 if (Status
== EFI_BUFFER_TOO_SMALL
) {
547 // In case the AllocatPool changes the memory map we added in some extra descriptors
548 MemMapSize
+= (DescriptorSize
* 0x100);
549 OrigMemMap
= MemMap
= AllocatePool (MemMapSize
);
550 if (OrigMemMap
!= NULL
) {
551 // 2nd time we get the data
552 Status
= gBS
->GetMemoryMap (&MemMapSize
, MemMap
, &MapKey
, &DescriptorSize
, &DescriptorVersion
);
553 if (!EFI_ERROR (Status
)) {
554 for (Index
= 0, CurrentRow
= 0; Index
< MemMapSize
/DescriptorSize
; Index
++) {
555 EntrySize
= LShiftU64 (MemMap
->NumberOfPages
, 12);
556 AsciiPrint ("\n%a %016lx - %016lx: # %08lx %016lx", gMemMapType
[MemMap
->Type
% EfiMaxMemoryType
], MemMap
->PhysicalStart
, MemMap
->PhysicalStart
+ EntrySize
-1, MemMap
->NumberOfPages
, MemMap
->Attribute
);
557 if (EblAnyKeyToContinueQtoQuit (&CurrentRow
, TRUE
)) {
561 PageCount
[MemMap
->Type
% EfiMaxMemoryType
] += MemMap
->NumberOfPages
;
562 MemMap
= NEXT_MEMORY_DESCRIPTOR (MemMap
, DescriptorSize
);
566 for (Index
= 0, TotalMemory
= 0; Index
< EfiMaxMemoryType
; Index
++) {
567 if (PageCount
[Index
] != 0) {
568 AsciiPrint ("\n %a %,7ld Pages (%,14ld)", gMemMapType
[Index
], PageCount
[Index
], LShiftU64 (PageCount
[Index
], 12));
569 if (Index
== EfiLoaderCode
||
570 Index
== EfiLoaderData
||
571 Index
== EfiBootServicesCode
||
572 Index
== EfiBootServicesData
||
573 Index
== EfiRuntimeServicesCode
||
574 Index
== EfiRuntimeServicesData
||
575 Index
== EfiConventionalMemory
||
576 Index
== EfiACPIReclaimMemory
||
577 Index
== EfiACPIMemoryNVS
||
580 // Count total memory
581 TotalMemory
+= PageCount
[Index
];
586 AsciiPrint ("\nTotal Memory: %,ld MB (%,ld bytes)\n", RShiftU64 (TotalMemory
, 8), LShiftU64 (TotalMemory
, 12));
588 FreePool (OrigMemMap
);
600 Load a file into memory and optionally jump to it. A load addres can be
601 specified or automatically allocated. A quoted command line can optionally
602 be passed into the image.
605 Argv[1] - Device Name:path for the file to load
606 Argv[2] - Address to load to or '*' if the load address will be allocated
607 Argv[3] - Optional Entry point to the image. Image will be called if present
608 Argv[4] - "" string that will be passed as Argc & Argv to EntryPoint. Needs
609 to include the command name
611 go fv1:\EblCmdX 0x10000 0x10010 "EblCmdX Arg2 Arg3 Arg4"; - load EblCmdX
612 from FV1 to location 0x10000 and call the entry point at 0x10010 passing
613 in "EblCmdX Arg2 Arg3 Arg4" as the arguments.
615 go fv0:\EblCmdX * 0x10 "EblCmdX Arg2 Arg3 Arg4"; - load EblCmdX from FS0
616 to location allocated by this comamnd and call the entry point at offset 0x10
617 passing in "EblCmdX Arg2 Arg3 Arg4" as the arguments.
619 go fv1:\EblCmdX 0x10000; Load EblCmdX to address 0x10000 and return
621 @param Argc Number of command arguments in Argv
622 @param Argv Array of strings that represent the parsed command line.
623 Argv[0] is the comamnd name
638 EBL_COMMMAND EntryPoint
;
639 UINTN EntryPointArgc
;
640 CHAR8
*EntryPointArgv
[MAX_ARGS
];
644 // device name and laod address are required
648 File
= EfiOpen (Argv
[1], EFI_FILE_MODE_READ
, 0);
650 AsciiPrint (" %a is not a valid path\n", Argv
[1]);
654 EntryPoint
= (EBL_COMMMAND
)((Argc
> 3) ? (UINTN
)AsciiStrHexToUintn (Argv
[3]) : (UINTN
)NULL
);
655 if (Argv
[2][0] == '*') {
656 // * Means allocate the buffer
657 Status
= EfiReadAllocatePool (File
, &Address
, &Size
);
659 // EntryPoint is relatvie to the start of the image
660 EntryPoint
= (EBL_COMMMAND
)((UINTN
)EntryPoint
+ (UINTN
)Address
);
663 Address
= (VOID
*)AsciiStrHexToUintn (Argv
[2]);
666 // File->Size for LoadFile is lazy so we need to use the tell to figure it out
667 EfiTell (File
, NULL
);
668 Status
= EfiRead (File
, Address
, &Size
);
671 if (!EFI_ERROR (Status
)) {
672 AsciiPrint ("Loaded %,d bytes to 0x%08x\n", Size
, Address
);
676 ParseArguments (Argv
[4], &EntryPointArgc
, EntryPointArgv
);
679 EntryPointArgv
[0] = File
->FileName
;
682 Status
= EntryPoint (EntryPointArgc
, EntryPointArgv
);
690 #define FILE_COPY_CHUNK 0x20000
698 EFI_OPEN_FILE
*Source
= NULL
;
699 EFI_OPEN_FILE
*Destination
= NULL
;
700 EFI_STATUS Status
= EFI_SUCCESS
;
704 UINTN Chunk
= FILE_COPY_CHUNK
;
707 return EFI_INVALID_PARAMETER
;
710 Source
= EfiOpen(Argv
[1], EFI_FILE_MODE_READ
, 0);
711 if (Source
== NULL
) {
712 AsciiPrint("Source file open error.\n");
713 return EFI_NOT_FOUND
;
716 Destination
= EfiOpen(Argv
[2], EFI_FILE_MODE_READ
| EFI_FILE_MODE_WRITE
| EFI_FILE_MODE_CREATE
, 0);
717 if (Destination
== NULL
) {
718 AsciiPrint("Destination file open error.\n");
719 return EFI_NOT_FOUND
;
722 Buffer
= AllocatePool(FILE_COPY_CHUNK
);
723 if (Buffer
== NULL
) {
727 Size
= EfiTell(Source
, NULL
);
729 for (Offset
= 0; Offset
+ FILE_COPY_CHUNK
<= Size
; Offset
+= Chunk
) {
730 Chunk
= FILE_COPY_CHUNK
;
732 Status
= EfiRead(Source
, Buffer
, &Chunk
);
733 if (EFI_ERROR(Status
)) {
734 AsciiPrint("Read file error\n");
738 Status
= EfiWrite(Destination
, Buffer
, &Chunk
);
739 if (EFI_ERROR(Status
)) {
740 AsciiPrint("Write file error\n");
747 Chunk
= Size
- Offset
;
749 Status
= EfiRead(Source
, Buffer
, &Chunk
);
750 if (EFI_ERROR(Status
)) {
751 AsciiPrint("Read file error\n");
755 Status
= EfiWrite(Destination
, Buffer
, &Chunk
);
756 if (EFI_ERROR(Status
)) {
757 AsciiPrint("Write file error\n");
763 if (Source
!= NULL
) {
764 Status
= EfiClose(Source
);
765 if (EFI_ERROR(Status
)) {
766 AsciiPrint("Source close error %r\n", Status
);
770 if (Destination
!= NULL
) {
771 Status
= EfiClose(Destination
);
772 if (EFI_ERROR(Status
)) {
773 AsciiPrint("Destination close error %r\n", Status
);
777 if (Buffer
!= NULL
) {
790 EFI_OPEN_FILE
*File1
= NULL
;
791 EFI_OPEN_FILE
*File2
= NULL
;
792 EFI_STATUS Status
= EFI_SUCCESS
;
793 VOID
*Buffer1
= NULL
;
794 VOID
*Buffer2
= NULL
;
798 UINTN Chunk
= FILE_COPY_CHUNK
;
801 return EFI_INVALID_PARAMETER
;
804 File1
= EfiOpen(Argv
[1], EFI_FILE_MODE_READ
, 0);
806 AsciiPrint("File 1 open error.\n");
807 return EFI_NOT_FOUND
;
810 File2
= EfiOpen(Argv
[2], EFI_FILE_MODE_READ
, 0);
812 AsciiPrint("File 2 open error.\n");
813 return EFI_NOT_FOUND
;
816 Size1
= EfiTell(File1
, NULL
);
817 Size2
= EfiTell(File2
, NULL
);
819 if (Size1
!= Size2
) {
820 AsciiPrint("Files differ.\n");
824 Buffer1
= AllocatePool(FILE_COPY_CHUNK
);
825 if (Buffer1
== NULL
) {
829 Buffer2
= AllocatePool(FILE_COPY_CHUNK
);
830 if (Buffer2
== NULL
) {
834 for (Offset
= 0; Offset
+ FILE_COPY_CHUNK
<= Size1
; Offset
+= Chunk
) {
835 Chunk
= FILE_COPY_CHUNK
;
837 Status
= EfiRead(File1
, Buffer1
, &Chunk
);
838 if (EFI_ERROR(Status
)) {
839 AsciiPrint("File 1 read error\n");
843 Status
= EfiRead(File2
, Buffer2
, &Chunk
);
844 if (EFI_ERROR(Status
)) {
845 AsciiPrint("File 2 read error\n");
849 if (CompareMem(Buffer1
, Buffer2
, Chunk
) != 0) {
850 AsciiPrint("Files differ.\n");
856 if (Offset
< Size1
) {
857 Chunk
= Size1
- Offset
;
859 Status
= EfiRead(File1
, Buffer1
, &Chunk
);
860 if (EFI_ERROR(Status
)) {
861 AsciiPrint("File 1 read error\n");
865 Status
= EfiRead(File2
, Buffer2
, &Chunk
);
866 if (EFI_ERROR(Status
)) {
867 AsciiPrint("File 2 read error\n");
872 if (CompareMem(Buffer1
, Buffer2
, Chunk
) != 0) {
873 AsciiPrint("Files differ.\n");
875 AsciiPrint("Files are identical.\n");
880 Status
= EfiClose(File1
);
881 if (EFI_ERROR(Status
)) {
882 AsciiPrint("File 1 close error %r\n", Status
);
887 Status
= EfiClose(File2
);
888 if (EFI_ERROR(Status
)) {
889 AsciiPrint("File 2 close error %r\n", Status
);
893 if (Buffer1
!= NULL
) {
897 if (Buffer2
!= NULL
) {
904 GLOBAL_REMOVE_IF_UNREFERENCED
const EBL_COMMAND_TABLE mCmdDeviceTemplate
[] =
908 "[d]; Connect all EFI devices. d means disconnect",
914 "; Show information about boot devices",
920 " dev:path loadaddress entrypoint args; load to given address and jump in",
926 " devname; Load PI FV from device",
932 " path; EFI Boot Device:filepath. fs1:\\EFI\\BOOT.EFI",
938 "; dump EFI memory map",
944 " file1 file2; copy file",
950 " file1 file2; compare files",
958 Initialize the commands in this in this file
962 EblInitializeDeviceCmd (
966 EfiGetSystemConfigurationTable (&gEfiDxeServicesTableGuid
, (VOID
**) &gDS
);
967 EblAddCommands (mCmdDeviceTemplate
, sizeof (mCmdDeviceTemplate
)/sizeof (EBL_COMMAND_TABLE
));