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