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