Adding support for BeagleBoard.
[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 if (File == NULL) {
35 return;
36 }
37
38 AsciiPrint (" %a: ", File->DeviceName);
39 if (File->FsInfo != NULL) {
40 AsciiPrint ("%s: ", File->FsInfo->VolumeLabel);
41 if (File->FsInfo->ReadOnly) {
42 AsciiPrint ("ReadOnly");
43 }
44 }
45
46 AsciiPrint ("\n");
47 EfiClose (File);
48 }
49
50
51 /**
52 Print information about the FV devices.
53
54 @param File Open File for the device
55
56 **/
57 VOID
58 EblPrintFvbInfo (
59 IN EFI_OPEN_FILE *File
60 )
61 {
62 if (File == NULL) {
63 return;
64 }
65
66 AsciiPrint (" %a: 0x%08lx - 0x%08lx : 0x%08x\n", File->DeviceName, File->FvStart, File->FvStart + File->FvSize - 1, File->FvSize);
67 EfiClose (File);
68 }
69
70
71 /**
72 Print information about the Blk IO devices.
73 If the device supports PXE dump out extra information
74
75 @param File Open File for the device
76
77 **/
78 VOID
79 EblPrintBlkIoInfo (
80 IN EFI_OPEN_FILE *File
81 )
82 {
83 UINT64 DeviceSize;
84
85
86 if (File == NULL) {
87 return;
88 }
89
90 AsciiPrint (" %a: ", File->DeviceName);
91 if (File->FsBlockIoMedia.RemovableMedia) {
92 AsciiPrint ("Removable ");
93 }
94 if (!File->FsBlockIoMedia.MediaPresent) {
95 AsciiPrint ("No Media ");
96 }
97 if (File->FsBlockIoMedia.LogicalPartition) {
98 AsciiPrint ("Partition ");
99 }
100 DeviceSize = MultU64x32 (File->FsBlockIoMedia.LastBlock + 1, File->FsBlockIoMedia.BlockSize);
101 AsciiPrint ("Size = 0x%lX\n", DeviceSize);
102
103 EfiClose (File);
104 }
105
106
107 /**
108 Print information about the Load File devices.
109 If the device supports PXE dump out extra information
110
111 @param File Open File for the device
112
113 **/
114 VOID
115 EblPrintLoadFileInfo (
116 IN EFI_OPEN_FILE *File
117 )
118 {
119 EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
120 MAC_ADDR_DEVICE_PATH *MacAddr;
121 UINTN HwAddressSize;
122 UINTN Index;
123
124 if (File == NULL) {
125 return;
126 }
127
128 AsciiPrint (" %a: %a ", File->DeviceName, EblLoadFileBootTypeString (File->EfiHandle));
129
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)) {
135
136 if ((DevicePathType (DevicePathNode) == MESSAGING_DEVICE_PATH) && (DevicePathSubType (DevicePathNode) == MSG_MAC_ADDR_DP)) {
137 MacAddr = (MAC_ADDR_DEVICE_PATH *)DevicePathNode;
138
139 HwAddressSize = sizeof (EFI_MAC_ADDRESS);
140 if (MacAddr->IfType == 0x01 || MacAddr->IfType == 0x00) {
141 HwAddressSize = 6;
142 }
143
144 AsciiPrint ("MAC ");
145 for (Index = 0; Index < HwAddressSize; Index++) {
146 AsciiPrint ("%02x", MacAddr->MacAddress.Addr[Index] & 0xff);
147 }
148 }
149 }
150 }
151
152 AsciiPrint ("\n");
153 EfiClose (File);
154 return;
155 }
156
157
158
159 /**
160 Dump information about devices in the system.
161
162 fv: PI Firmware Volume
163 fs: EFI Simple File System
164 blk: EFI Block IO
165 LoadFile: EFI Load File Protocol (commonly PXE network boot)
166
167 Argv[0] - "device"
168
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
172
173 @return EFI_SUCCESS
174
175 **/
176 EFI_STATUS
177 EblDeviceCmd (
178 IN UINTN Argc,
179 IN CHAR8 **Argv
180 )
181 {
182 UINTN Index;
183 UINTN CurrentRow;
184 UINTN Max;
185
186 CurrentRow = 0;
187
188 // Need to call here to make sure Device Counts are valid
189 EblUpdateDeviceLists ();
190
191 Max = EfiGetDeviceCounts (EfiOpenFirmwareVolume);
192 if (Max != 0) {
193 AsciiPrint ("Firmware Volume Devices:\n");
194 for (Index = 0; Index < Max; Index++) {
195 EblPrintFvbInfo (EfiDeviceOpenByType (EfiOpenFirmwareVolume, Index));
196 if (EblAnyKeyToContinueQtoQuit (&CurrentRow, TRUE)) {
197 break;
198 }
199 }
200 }
201
202 Max = EfiGetDeviceCounts (EfiOpenFileSystem);
203 if (Max != 0) {
204 AsciiPrint ("File System Devices:\n");
205 for (Index = 0; Index < Max; Index++) {
206 EblPrintFsInfo (EfiDeviceOpenByType (EfiOpenFileSystem, Index));
207 if (EblAnyKeyToContinueQtoQuit (&CurrentRow, TRUE)) {
208 break;
209 }
210 }
211 }
212
213 Max = EfiGetDeviceCounts (EfiOpenBlockIo);
214 if (Max != 0) {
215 AsciiPrint ("Block IO Devices:\n");
216 for (Index = 0; Index < Max; Index++) {
217 EblPrintBlkIoInfo (EfiDeviceOpenByType (EfiOpenBlockIo, Index));
218 if (EblAnyKeyToContinueQtoQuit (&CurrentRow, TRUE)) {
219 break;
220 }
221 }
222 }
223
224 Max = EfiGetDeviceCounts (EfiOpenLoadFile);
225 if (Max != 0) {
226 AsciiPrint ("LoadFile Devices: (usually network)\n");
227 for (Index = 0; Index < Max; Index++) {
228 EblPrintLoadFileInfo (EfiDeviceOpenByType (EfiOpenLoadFile, Index));
229 if (EblAnyKeyToContinueQtoQuit (&CurrentRow, TRUE)) {
230 break;
231 }
232 }
233 }
234
235 return EFI_SUCCESS;
236 }
237
238
239 /**
240 Start an EFI image (PE32+ with EFI defined entry point).
241
242 Argv[0] - "start"
243 Argv[1] - device name and path
244 Argv[2] - "" string to pass into image being started
245
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
250
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
254
255 @return EFI_SUCCESS
256
257 **/
258 EFI_STATUS
259 EblStartCmd (
260 IN UINTN Argc,
261 IN CHAR8 **Argv
262 )
263 {
264 EFI_STATUS Status;
265 EFI_OPEN_FILE *File;
266 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
267 EFI_HANDLE ImageHandle;
268 UINTN ExitDataSize;
269 CHAR16 *ExitData;
270 VOID *Buffer;
271 UINTN BufferSize;
272 EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;
273
274 ImageHandle = NULL;
275
276 if (Argc < 2) {
277 return EFI_INVALID_PARAMETER;
278 }
279
280 File = EfiOpen (Argv[1], EFI_FILE_MODE_READ, 0);
281 if (File == NULL) {
282 return EFI_INVALID_PARAMETER;
283 }
284
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);
289 } else {
290 // Check for buffer form: A0x12345678:0x1234 syntax.
291 // Means load using buffer starting at 0x12345678 of size 0x1234.
292
293 Status = EfiReadAllocatePool (File, &Buffer, &BufferSize);
294 if (EFI_ERROR (Status)) {
295 EfiClose (File);
296 return Status;
297 }
298 Status = gBS->LoadImage (FALSE, gImageHandle, DevicePath, Buffer, BufferSize, &ImageHandle);
299
300 FreePool (Buffer);
301 }
302
303 EfiClose (File);
304
305 if (!EFI_ERROR (Status)) {
306 if (Argc >= 3) {
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);
311
312 ImageInfo->LoadOptionsSize = (UINT32)AsciiStrSize (Argv[2]);
313 ImageInfo->LoadOptions = AllocatePool (ImageInfo->LoadOptionsSize);
314 AsciiStrCpy (ImageInfo->LoadOptions, Argv[2]);
315 }
316
317 // Transfer control to the EFI image we loaded with LoadImage()
318 Status = gBS->StartImage (ImageHandle, &ExitDataSize, &ExitData);
319 }
320
321 return Status;
322 }
323
324
325 /**
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.
328
329 Argv[0] - "loadfv"
330 Argv[1] - device name and path
331
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
335
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
339
340 @return EFI_SUCCESS
341
342 **/
343 EFI_STATUS
344 EblLoadFvCmd (
345 IN UINTN Argc,
346 IN CHAR8 **Argv
347 )
348 {
349 EFI_STATUS Status;
350 EFI_OPEN_FILE *File;
351 VOID *FvStart;
352 UINTN FvSize;
353 EFI_HANDLE FvHandle;
354
355
356 if (Argc < 2) {
357 return EFI_INVALID_PARAMETER;
358 }
359
360 File = EfiOpen (Argv[1], EFI_FILE_MODE_READ, 0);
361 if (File == NULL) {
362 return EFI_INVALID_PARAMETER;
363 }
364
365 if (File->Type == EfiOpenMemoryBuffer) {
366 // If it is a address just use it.
367 Status = gDS->ProcessFirmwareVolume (File->Buffer, File->Size, &FvHandle);
368 } else {
369 // If it is a file read it into memory and use it
370 Status = EfiReadAllocatePool (File, &FvStart, &FvSize);
371 EfiClose (File);
372 if (EFI_ERROR (Status)) {
373 return Status;
374 }
375
376 Status = gDS->ProcessFirmwareVolume (FvStart, FvSize, &FvHandle);
377 FreePool (FvStart);
378 }
379 return Status;
380 }
381
382
383 /**
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).
387
388 Argv[0] - "connect"
389
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
393
394 @return EFI_SUCCESS
395
396 **/
397 EFI_STATUS
398 EblConnectCmd (
399 IN UINTN Argc,
400 IN CHAR8 **Argv
401 )
402 {
403 EFI_STATUS Status;
404 UINTN HandleCount;
405 EFI_HANDLE *HandleBuffer;
406 UINTN Index;
407 BOOLEAN Dispatch;
408 EFI_OPEN_FILE *File;
409
410
411 if (Argc > 1) {
412 if ((*Argv[1] == 'd') || (*Argv[1] == 'D')) {
413 Status = gBS->LocateHandleBuffer (
414 AllHandles,
415 NULL,
416 NULL,
417 &HandleCount,
418 &HandleBuffer
419 );
420 if (EFI_ERROR (Status)) {
421 return Status;
422 }
423
424 for (Index = 0; Index < HandleCount; Index++) {
425 gBS->DisconnectController (HandleBuffer[Index], NULL, NULL);
426 }
427
428 //
429 // Given we disconnect our console we should go and do a connect now
430 //
431 } else {
432 File = EfiOpen (Argv[1], EFI_FILE_MODE_READ, 0);
433 if (File != NULL) {
434 AsciiPrint ("Connecting %a\n", Argv[1]);
435 gBS->ConnectController (File->EfiHandle, NULL, NULL, TRUE);
436 EfiClose (File);
437 return EFI_SUCCESS;
438 }
439 }
440 }
441
442 Dispatch = FALSE;
443 do {
444 Status = gBS->LocateHandleBuffer (
445 AllHandles,
446 NULL,
447 NULL,
448 &HandleCount,
449 &HandleBuffer
450 );
451 if (EFI_ERROR (Status)) {
452 return Status;
453 }
454
455 for (Index = 0; Index < HandleCount; Index++) {
456 gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE);
457 }
458
459 FreePool (HandleBuffer);
460
461 //
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.
466 //
467 if (gDS == NULL) {
468 Status = EFI_NOT_FOUND;
469 } else {
470 Status = gDS->Dispatch ();
471 if (!EFI_ERROR (Status)) {
472 Dispatch = TRUE;
473 }
474 }
475
476 } while (!EFI_ERROR (Status));
477
478 if (Dispatch) {
479 AsciiPrint ("Connected and dispatched\n");
480 } else {
481 AsciiPrint ("Connect\n");
482 }
483
484 return EFI_SUCCESS;
485 }
486
487
488
489 CHAR8 *gMemMapType[] = {
490 "reserved ",
491 "LoaderCode",
492 "LoaderData",
493 "BS_code ",
494 "BS_data ",
495 "RT_code ",
496 "RT_data ",
497 "available ",
498 "Unusable ",
499 "ACPI_recl ",
500 "ACPI_NVS ",
501 "MemMapIO ",
502 "MemPortIO ",
503 "PAL_code "
504 };
505
506
507 /**
508 Dump out the EFI memory map
509
510 Argv[0] - "memmap"
511
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
515
516 @return EFI_SUCCESS
517
518 **/
519 EFI_STATUS
520 EblMemMapCmd (
521 IN UINTN Argc,
522 IN CHAR8 **Argv
523 )
524 {
525 EFI_STATUS Status;
526 EFI_MEMORY_DESCRIPTOR *MemMap;
527 EFI_MEMORY_DESCRIPTOR *OrigMemMap;
528 UINTN MemMapSize;
529 UINTN MapKey;
530 UINTN DescriptorSize;
531 UINT32 DescriptorVersion;
532 UINT64 PageCount[EfiMaxMemoryType];
533 UINTN Index;
534 UINT64 EntrySize;
535 UINTN CurrentRow;
536 UINT64 TotalMemory;
537
538 ZeroMem (PageCount, sizeof (PageCount));
539
540 AsciiPrint ("EFI Memory Map\n");
541
542 // First call is to figure out how big the buffer needs to be
543 MemMapSize = 0;
544 MemMap = NULL;
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)) {
558 break;
559 }
560
561 PageCount[MemMap->Type % EfiMaxMemoryType] += MemMap->NumberOfPages;
562 MemMap = NEXT_MEMORY_DESCRIPTOR (MemMap, DescriptorSize);
563 }
564 }
565
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 ||
578 Index == EfiPalCode
579 ) {
580 // Count total memory
581 TotalMemory += PageCount[Index];
582 }
583 }
584 }
585
586 AsciiPrint ("\nTotal Memory: %,ld MB (%,ld bytes)\n", RShiftU64 (TotalMemory, 8), LShiftU64 (TotalMemory, 12));
587
588 FreePool (OrigMemMap);
589
590 }
591 }
592
593 return EFI_SUCCESS;
594 }
595
596
597
598
599 /**
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.
603
604 Argv[0] - "go"
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
610
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.
614
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.
618
619 go fv1:\EblCmdX 0x10000; Load EblCmdX to address 0x10000 and return
620
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
624
625 @return EFI_SUCCESS
626
627 **/
628 EFI_STATUS
629 EblGoCmd (
630 IN UINTN Argc,
631 IN CHAR8 **Argv
632 )
633 {
634 EFI_STATUS Status;
635 EFI_OPEN_FILE *File;
636 VOID *Address;
637 UINTN Size;
638 EBL_COMMMAND EntryPoint;
639 UINTN EntryPointArgc;
640 CHAR8 *EntryPointArgv[MAX_ARGS];
641
642
643 if (Argc <= 2) {
644 // device name and laod address are required
645 return EFI_SUCCESS;
646 }
647
648 File = EfiOpen (Argv[1], EFI_FILE_MODE_READ, 0);
649 if (File == NULL) {
650 AsciiPrint (" %a is not a valid path\n", Argv[1]);
651 return EFI_SUCCESS;
652 }
653
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);
658
659 // EntryPoint is relatvie to the start of the image
660 EntryPoint = (EBL_COMMMAND)((UINTN)EntryPoint + (UINTN)Address);
661
662 } else {
663 Address = (VOID *)AsciiStrHexToUintn (Argv[2]);
664 Size = File->Size;
665
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);
669 }
670
671 if (!EFI_ERROR (Status)) {
672 AsciiPrint ("Loaded %,d bytes to 0x%08x\n", Size, Address);
673
674 if (Argc > 3) {
675 if (Argc > 4) {
676 ParseArguments (Argv[4], &EntryPointArgc, EntryPointArgv);
677 } else {
678 EntryPointArgc = 1;
679 EntryPointArgv[0] = File->FileName;
680 }
681
682 Status = EntryPoint (EntryPointArgc, EntryPointArgv);
683 }
684 }
685
686 EfiClose (File);
687 return Status;
688 }
689
690 #define FILE_COPY_CHUNK 0x20000
691
692 EFI_STATUS
693 EblFileCopyCmd (
694 IN UINTN Argc,
695 IN CHAR8 **Argv
696 )
697 {
698 EFI_OPEN_FILE *Source = NULL;
699 EFI_OPEN_FILE *Destination = NULL;
700 EFI_STATUS Status = EFI_SUCCESS;
701 VOID *Buffer = NULL;
702 UINTN Size;
703 UINTN Offset;
704 UINTN Chunk = FILE_COPY_CHUNK;
705
706 if (Argc < 3) {
707 return EFI_INVALID_PARAMETER;
708 }
709
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;
714 }
715
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;
720 }
721
722 Buffer = AllocatePool(FILE_COPY_CHUNK);
723 if (Buffer == NULL) {
724 goto Exit;
725 }
726
727 Size = EfiTell(Source, NULL);
728
729 for (Offset = 0; Offset + FILE_COPY_CHUNK <= Size; Offset += Chunk) {
730 Chunk = FILE_COPY_CHUNK;
731
732 Status = EfiRead(Source, Buffer, &Chunk);
733 if (EFI_ERROR(Status)) {
734 AsciiPrint("Read file error\n");
735 goto Exit;
736 }
737
738 Status = EfiWrite(Destination, Buffer, &Chunk);
739 if (EFI_ERROR(Status)) {
740 AsciiPrint("Write file error\n");
741 goto Exit;
742 }
743 }
744
745 // Any left over?
746 if (Offset < Size) {
747 Chunk = Size - Offset;
748
749 Status = EfiRead(Source, Buffer, &Chunk);
750 if (EFI_ERROR(Status)) {
751 AsciiPrint("Read file error\n");
752 goto Exit;
753 }
754
755 Status = EfiWrite(Destination, Buffer, &Chunk);
756 if (EFI_ERROR(Status)) {
757 AsciiPrint("Write file error\n");
758 goto Exit;
759 }
760 }
761
762 Exit:
763 if (Source != NULL) {
764 Status = EfiClose(Source);
765 if (EFI_ERROR(Status)) {
766 AsciiPrint("Source close error %r\n", Status);
767 }
768 }
769
770 if (Destination != NULL) {
771 Status = EfiClose(Destination);
772 if (EFI_ERROR(Status)) {
773 AsciiPrint("Destination close error %r\n", Status);
774 }
775 }
776
777 if (Buffer != NULL) {
778 FreePool(Buffer);
779 }
780
781 return Status;
782 }
783
784 EFI_STATUS
785 EblFileDiffCmd (
786 IN UINTN Argc,
787 IN CHAR8 **Argv
788 )
789 {
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;
795 UINTN Size1;
796 UINTN Size2;
797 UINTN Offset;
798 UINTN Chunk = FILE_COPY_CHUNK;
799
800 if (Argc != 3) {
801 return EFI_INVALID_PARAMETER;
802 }
803
804 File1 = EfiOpen(Argv[1], EFI_FILE_MODE_READ, 0);
805 if (File1 == NULL) {
806 AsciiPrint("File 1 open error.\n");
807 return EFI_NOT_FOUND;
808 }
809
810 File2 = EfiOpen(Argv[2], EFI_FILE_MODE_READ, 0);
811 if (File2 == NULL) {
812 AsciiPrint("File 2 open error.\n");
813 return EFI_NOT_FOUND;
814 }
815
816 Size1 = EfiTell(File1, NULL);
817 Size2 = EfiTell(File2, NULL);
818
819 if (Size1 != Size2) {
820 AsciiPrint("Files differ.\n");
821 goto Exit;
822 }
823
824 Buffer1 = AllocatePool(FILE_COPY_CHUNK);
825 if (Buffer1 == NULL) {
826 goto Exit;
827 }
828
829 Buffer2 = AllocatePool(FILE_COPY_CHUNK);
830 if (Buffer2 == NULL) {
831 goto Exit;
832 }
833
834 for (Offset = 0; Offset + FILE_COPY_CHUNK <= Size1; Offset += Chunk) {
835 Chunk = FILE_COPY_CHUNK;
836
837 Status = EfiRead(File1, Buffer1, &Chunk);
838 if (EFI_ERROR(Status)) {
839 AsciiPrint("File 1 read error\n");
840 goto Exit;
841 }
842
843 Status = EfiRead(File2, Buffer2, &Chunk);
844 if (EFI_ERROR(Status)) {
845 AsciiPrint("File 2 read error\n");
846 goto Exit;
847 }
848
849 if (CompareMem(Buffer1, Buffer2, Chunk) != 0) {
850 AsciiPrint("Files differ.\n");
851 goto Exit;
852 };
853 }
854
855 // Any left over?
856 if (Offset < Size1) {
857 Chunk = Size1 - Offset;
858
859 Status = EfiRead(File1, Buffer1, &Chunk);
860 if (EFI_ERROR(Status)) {
861 AsciiPrint("File 1 read error\n");
862 goto Exit;
863 }
864
865 Status = EfiRead(File2, Buffer2, &Chunk);
866 if (EFI_ERROR(Status)) {
867 AsciiPrint("File 2 read error\n");
868 goto Exit;
869 }
870 }
871
872 if (CompareMem(Buffer1, Buffer2, Chunk) != 0) {
873 AsciiPrint("Files differ.\n");
874 } else {
875 AsciiPrint("Files are identical.\n");
876 }
877
878 Exit:
879 if (File1 != NULL) {
880 Status = EfiClose(File1);
881 if (EFI_ERROR(Status)) {
882 AsciiPrint("File 1 close error %r\n", Status);
883 }
884 }
885
886 if (File2 != NULL) {
887 Status = EfiClose(File2);
888 if (EFI_ERROR(Status)) {
889 AsciiPrint("File 2 close error %r\n", Status);
890 }
891 }
892
893 if (Buffer1 != NULL) {
894 FreePool(Buffer1);
895 }
896
897 if (Buffer2 != NULL) {
898 FreePool(Buffer2);
899 }
900
901 return Status;
902 }
903
904 GLOBAL_REMOVE_IF_UNREFERENCED const EBL_COMMAND_TABLE mCmdDeviceTemplate[] =
905 {
906 {
907 "connect",
908 "[d]; Connect all EFI devices. d means disconnect",
909 NULL,
910 EblConnectCmd
911 },
912 {
913 "device",
914 "; Show information about boot devices",
915 NULL,
916 EblDeviceCmd
917 },
918 {
919 "go",
920 " dev:path loadaddress entrypoint args; load to given address and jump in",
921 NULL,
922 EblGoCmd
923 },
924 {
925 "loadfv",
926 " devname; Load PI FV from device",
927 NULL,
928 EblLoadFvCmd
929 },
930 {
931 "start",
932 " path; EFI Boot Device:filepath. fs1:\\EFI\\BOOT.EFI",
933 NULL,
934 EblStartCmd
935 },
936 {
937 "memmap",
938 "; dump EFI memory map",
939 NULL,
940 EblMemMapCmd
941 },
942 {
943 "cp",
944 " file1 file2; copy file",
945 NULL,
946 EblFileCopyCmd
947 },
948 {
949 "diff",
950 " file1 file2; compare files",
951 NULL,
952 EblFileDiffCmd
953 }
954 };
955
956
957 /**
958 Initialize the commands in this in this file
959 **/
960
961 VOID
962 EblInitializeDeviceCmd (
963 VOID
964 )
965 {
966 EfiGetSystemConfigurationTable (&gEfiDxeServicesTableGuid, (VOID **) &gDS);
967 EblAddCommands (mCmdDeviceTemplate, sizeof (mCmdDeviceTemplate)/sizeof (EBL_COMMAND_TABLE));
968 }
969