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