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