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