]> git.proxmox.com Git - mirror_edk2.git/blob - EmbeddedPkg/Ebl/EfiDevice.c
ARM Packages: Removed trailing spaces
[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 command 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 command 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 dependencies 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 command 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 if (EFI_ERROR (Status)) {
407 FreePool (FvStart);
408 }
409 }
410 return Status;
411 }
412
413
414 /**
415 Perform an EFI connect to connect devices that follow the EFI driver model.
416 If it is a PI system also call the dispatcher in case a new FV was made
417 available by one of the connect EFI drivers (this is not a common case).
418
419 Argv[0] - "connect"
420
421 @param Argc Number of command arguments in Argv
422 @param Argv Array of strings that represent the parsed command line.
423 Argv[0] is the command name
424
425 @return EFI_SUCCESS
426
427 **/
428 EFI_STATUS
429 EblConnectCmd (
430 IN UINTN Argc,
431 IN CHAR8 **Argv
432 )
433 {
434 EFI_STATUS Status;
435 UINTN HandleCount;
436 EFI_HANDLE *HandleBuffer;
437 UINTN Index;
438 BOOLEAN Dispatch;
439 EFI_OPEN_FILE *File;
440
441
442 if (Argc > 1) {
443 if ((*Argv[1] == 'd') || (*Argv[1] == 'D')) {
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->DisconnectController (HandleBuffer[Index], NULL, NULL);
457 }
458
459 //
460 // Given we disconnect our console we should go and do a connect now
461 //
462 } else {
463 File = EfiOpen (Argv[1], EFI_FILE_MODE_READ, 0);
464 if (File != NULL) {
465 AsciiPrint ("Connecting %a\n", Argv[1]);
466 gBS->ConnectController (File->EfiHandle, NULL, NULL, TRUE);
467 EfiClose (File);
468 return EFI_SUCCESS;
469 }
470 }
471 }
472
473 Dispatch = FALSE;
474 do {
475 Status = gBS->LocateHandleBuffer (
476 AllHandles,
477 NULL,
478 NULL,
479 &HandleCount,
480 &HandleBuffer
481 );
482 if (EFI_ERROR (Status)) {
483 return Status;
484 }
485
486 for (Index = 0; Index < HandleCount; Index++) {
487 gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE);
488 }
489
490 FreePool (HandleBuffer);
491
492 //
493 // Check to see if it's possible to dispatch an more DXE drivers.
494 // The BdsLibConnectAllEfi () may have made new DXE drivers show up.
495 // If anything is Dispatched Status == EFI_SUCCESS and we will try
496 // the connect again.
497 //
498 if (gDS == NULL) {
499 Status = EFI_NOT_FOUND;
500 } else {
501 Status = gDS->Dispatch ();
502 if (!EFI_ERROR (Status)) {
503 Dispatch = TRUE;
504 }
505 }
506
507 } while (!EFI_ERROR (Status));
508
509 if (Dispatch) {
510 AsciiPrint ("Connected and dispatched\n");
511 } else {
512 AsciiPrint ("Connect\n");
513 }
514
515 return EFI_SUCCESS;
516 }
517
518
519
520 CHAR8 *gMemMapType[] = {
521 "reserved ",
522 "LoaderCode",
523 "LoaderData",
524 "BS_code ",
525 "BS_data ",
526 "RT_code ",
527 "RT_data ",
528 "available ",
529 "Unusable ",
530 "ACPI_recl ",
531 "ACPI_NVS ",
532 "MemMapIO ",
533 "MemPortIO ",
534 "PAL_code "
535 };
536
537
538 /**
539 Dump out the EFI memory map
540
541 Argv[0] - "memmap"
542
543 @param Argc Number of command arguments in Argv
544 @param Argv Array of strings that represent the parsed command line.
545 Argv[0] is the command name
546
547 @return EFI_SUCCESS
548
549 **/
550 EFI_STATUS
551 EblMemMapCmd (
552 IN UINTN Argc,
553 IN CHAR8 **Argv
554 )
555 {
556 EFI_STATUS Status;
557 EFI_MEMORY_DESCRIPTOR *MemMap;
558 EFI_MEMORY_DESCRIPTOR *OrigMemMap;
559 UINTN MemMapSize;
560 UINTN MapKey;
561 UINTN DescriptorSize;
562 UINT32 DescriptorVersion;
563 UINT64 PageCount[EfiMaxMemoryType];
564 UINTN Index;
565 UINT64 EntrySize;
566 UINTN CurrentRow;
567 UINT64 TotalMemory;
568
569 ZeroMem (PageCount, sizeof (PageCount));
570
571 AsciiPrint ("EFI Memory Map\n");
572
573 // First call is to figure out how big the buffer needs to be
574 MemMapSize = 0;
575 MemMap = NULL;
576 Status = gBS->GetMemoryMap (&MemMapSize, MemMap, &MapKey, &DescriptorSize, &DescriptorVersion);
577 if (Status == EFI_BUFFER_TOO_SMALL) {
578 // In case the AllocatPool changes the memory map we added in some extra descriptors
579 MemMapSize += (DescriptorSize * 0x100);
580 OrigMemMap = MemMap = AllocatePool (MemMapSize);
581 if (OrigMemMap != NULL) {
582 // 2nd time we get the data
583 Status = gBS->GetMemoryMap (&MemMapSize, MemMap, &MapKey, &DescriptorSize, &DescriptorVersion);
584 if (!EFI_ERROR (Status)) {
585 for (Index = 0, CurrentRow = 0; Index < MemMapSize/DescriptorSize; Index++) {
586 EntrySize = LShiftU64 (MemMap->NumberOfPages, 12);
587 AsciiPrint ("\n%a %016lx - %016lx: # %08lx %016lx", gMemMapType[MemMap->Type % EfiMaxMemoryType], MemMap->PhysicalStart, MemMap->PhysicalStart + EntrySize -1, MemMap->NumberOfPages, MemMap->Attribute);
588 if (EblAnyKeyToContinueQtoQuit (&CurrentRow, TRUE)) {
589 break;
590 }
591
592 PageCount[MemMap->Type % EfiMaxMemoryType] += MemMap->NumberOfPages;
593 MemMap = NEXT_MEMORY_DESCRIPTOR (MemMap, DescriptorSize);
594 }
595 }
596
597 for (Index = 0, TotalMemory = 0; Index < EfiMaxMemoryType; Index++) {
598 if (PageCount[Index] != 0) {
599 AsciiPrint ("\n %a %,7ld Pages (%,14ld)", gMemMapType[Index], PageCount[Index], LShiftU64 (PageCount[Index], 12));
600 if (Index == EfiLoaderCode ||
601 Index == EfiLoaderData ||
602 Index == EfiBootServicesCode ||
603 Index == EfiBootServicesData ||
604 Index == EfiRuntimeServicesCode ||
605 Index == EfiRuntimeServicesData ||
606 Index == EfiConventionalMemory ||
607 Index == EfiACPIReclaimMemory ||
608 Index == EfiACPIMemoryNVS ||
609 Index == EfiPalCode
610 ) {
611 // Count total memory
612 TotalMemory += PageCount[Index];
613 }
614 }
615 }
616
617 AsciiPrint ("\nTotal Memory: %,ld MB (%,ld bytes)\n", RShiftU64 (TotalMemory, 8), LShiftU64 (TotalMemory, 12));
618
619 FreePool (OrigMemMap);
620
621 }
622 }
623
624 return EFI_SUCCESS;
625 }
626
627
628
629
630 /**
631 Load a file into memory and optionally jump to it. A load address can be
632 specified or automatically allocated. A quoted command line can optionally
633 be passed into the image.
634
635 Argv[0] - "go"
636 Argv[1] - Device Name:path for the file to load
637 Argv[2] - Address to load to or '*' if the load address will be allocated
638 Argv[3] - Optional Entry point to the image. Image will be called if present
639 Argv[4] - "" string that will be passed as Argc & Argv to EntryPoint. Needs
640 to include the command name
641
642 go fv1:\EblCmdX 0x10000 0x10010 "EblCmdX Arg2 Arg3 Arg4"; - load EblCmdX
643 from FV1 to location 0x10000 and call the entry point at 0x10010 passing
644 in "EblCmdX Arg2 Arg3 Arg4" as the arguments.
645
646 go fv0:\EblCmdX * 0x10 "EblCmdX Arg2 Arg3 Arg4"; - load EblCmdX from FS0
647 to location allocated by this command and call the entry point at offset 0x10
648 passing in "EblCmdX Arg2 Arg3 Arg4" as the arguments.
649
650 go fv1:\EblCmdX 0x10000; Load EblCmdX to address 0x10000 and return
651
652 @param Argc Number of command arguments in Argv
653 @param Argv Array of strings that represent the parsed command line.
654 Argv[0] is the command name
655
656 @return EFI_SUCCESS
657
658 **/
659 EFI_STATUS
660 EblGoCmd (
661 IN UINTN Argc,
662 IN CHAR8 **Argv
663 )
664 {
665 EFI_STATUS Status;
666 EFI_OPEN_FILE *File;
667 VOID *Address;
668 UINTN Size;
669 EBL_COMMMAND EntryPoint;
670 UINTN EntryPointArgc;
671 CHAR8 *EntryPointArgv[MAX_ARGS];
672
673
674 if (Argc <= 2) {
675 // device name and laod address are required
676 return EFI_SUCCESS;
677 }
678
679 File = EfiOpen (Argv[1], EFI_FILE_MODE_READ, 0);
680 if (File == NULL) {
681 AsciiPrint (" %a is not a valid path\n", Argv[1]);
682 return EFI_SUCCESS;
683 }
684
685 EntryPoint = (EBL_COMMMAND)((Argc > 3) ? (UINTN)AsciiStrHexToUintn (Argv[3]) : (UINTN)NULL);
686 if (Argv[2][0] == '*') {
687 // * Means allocate the buffer
688 Status = EfiReadAllocatePool (File, &Address, &Size);
689
690 // EntryPoint is relative to the start of the image
691 EntryPoint = (EBL_COMMMAND)((UINTN)EntryPoint + (UINTN)Address);
692
693 } else {
694 Address = (VOID *)AsciiStrHexToUintn (Argv[2]);
695 Size = File->Size;
696
697 // File->Size for LoadFile is lazy so we need to use the tell to figure it out
698 EfiTell (File, NULL);
699 Status = EfiRead (File, Address, &Size);
700 }
701
702 if (!EFI_ERROR (Status)) {
703 AsciiPrint ("Loaded %,d bytes to 0x%08x\n", Size, Address);
704
705 if (Argc > 3) {
706 if (Argc > 4) {
707 ParseArguments (Argv[4], &EntryPointArgc, EntryPointArgv);
708 } else {
709 EntryPointArgc = 1;
710 EntryPointArgv[0] = File->FileName;
711 }
712
713 Status = EntryPoint (EntryPointArgc, EntryPointArgv);
714 }
715 }
716
717 EfiClose (File);
718 return Status;
719 }
720
721 #define FILE_COPY_CHUNK 0x20000
722
723 EFI_STATUS
724 EblFileCopyCmd (
725 IN UINTN Argc,
726 IN CHAR8 **Argv
727 )
728 {
729 EFI_OPEN_FILE *Source = NULL;
730 EFI_OPEN_FILE *Destination = NULL;
731 EFI_STATUS Status = EFI_SUCCESS;
732 VOID *Buffer = NULL;
733 UINTN Size;
734 UINTN Offset;
735 UINTN Chunk = FILE_COPY_CHUNK;
736 UINTN FileNameLen;
737 CHAR8* DestFileName;
738 CHAR8* SrcFileName;
739 CHAR8* SrcPtr;
740
741 if (Argc < 3) {
742 return EFI_INVALID_PARAMETER;
743 }
744
745 DestFileName = Argv[2];
746 FileNameLen = AsciiStrLen (DestFileName);
747
748 // Check if the destination file name looks like a directory
749 if ((DestFileName[FileNameLen-1] == '\\') || (DestFileName[FileNameLen-1] == ':')) {
750 // Set the pointer after the source drive (eg: after fs1:)
751 SrcPtr = AsciiStrStr (Argv[1], ":");
752 if (SrcPtr == NULL) {
753 SrcPtr = Argv[1];
754 } else {
755 SrcPtr++;
756 if (*SrcPtr == '\\') {
757 SrcPtr++;
758 }
759 }
760
761 if (*SrcPtr == '\0') {
762 AsciiPrint("Source file incorrect.\n");
763 }
764
765 // Skip the Source Directories
766 while (1) {
767 SrcFileName = SrcPtr;
768 SrcPtr = AsciiStrStr (SrcPtr,"\\");
769 if (SrcPtr != NULL) {
770 SrcPtr++;
771 } else {
772 break;
773 }
774 }
775
776 if (*SrcFileName == '\0') {
777 AsciiPrint("Source file incorrect (Error 2).\n");
778 }
779
780 // Construct the destination filepath
781 DestFileName = (CHAR8*)AllocatePool (FileNameLen + AsciiStrLen (SrcFileName) + 1);
782 AsciiStrCpy (DestFileName, Argv[2]);
783 AsciiStrCat (DestFileName, SrcFileName);
784 }
785
786 Source = EfiOpen(Argv[1], EFI_FILE_MODE_READ, 0);
787 if (Source == NULL) {
788 AsciiPrint("Source file open error.\n");
789 return EFI_NOT_FOUND;
790 }
791
792 Destination = EfiOpen(DestFileName, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE, 0);
793 if (Destination == NULL) {
794 AsciiPrint("Destination file open error.\n");
795 return EFI_NOT_FOUND;
796 }
797
798 Buffer = AllocatePool(FILE_COPY_CHUNK);
799 if (Buffer == NULL) {
800 goto Exit;
801 }
802
803 Size = EfiTell(Source, NULL);
804
805 for (Offset = 0; Offset + FILE_COPY_CHUNK <= Size; Offset += Chunk) {
806 Chunk = FILE_COPY_CHUNK;
807
808 Status = EfiRead(Source, Buffer, &Chunk);
809 if (EFI_ERROR(Status)) {
810 AsciiPrint("Read file error %r\n", Status);
811 goto Exit;
812 }
813
814 Status = EfiWrite(Destination, Buffer, &Chunk);
815 if (EFI_ERROR(Status)) {
816 AsciiPrint("Write file error %r\n", Status);
817 goto Exit;
818 }
819 }
820
821 // Any left over?
822 if (Offset < Size) {
823 Chunk = Size - Offset;
824
825 Status = EfiRead(Source, Buffer, &Chunk);
826 if (EFI_ERROR(Status)) {
827 AsciiPrint("Read file error %r\n", Status);
828 goto Exit;
829 }
830
831 Status = EfiWrite(Destination, Buffer, &Chunk);
832 if (EFI_ERROR(Status)) {
833 AsciiPrint("Write file error %r\n", Status);
834 goto Exit;
835 }
836 }
837
838
839 Exit:
840 if (Source != NULL) {
841 Status = EfiClose(Source);
842 if (EFI_ERROR(Status)) {
843 AsciiPrint("Source close error %r\n", Status);
844 }
845 }
846 if (Destination != NULL) {
847 Status = EfiClose(Destination);
848 if (EFI_ERROR(Status)) {
849 AsciiPrint("Destination close error %r\n", Status);
850 }
851
852 // Case when we have concated the filename to the destination directory
853 if (DestFileName != Argv[2]) {
854 FreePool (DestFileName);
855 }
856 }
857
858 if (Buffer != NULL) {
859 FreePool(Buffer);
860 }
861
862 return Status;
863 }
864
865 EFI_STATUS
866 EblFileDiffCmd (
867 IN UINTN Argc,
868 IN CHAR8 **Argv
869 )
870 {
871 EFI_OPEN_FILE *File1 = NULL;
872 EFI_OPEN_FILE *File2 = NULL;
873 EFI_STATUS Status = EFI_SUCCESS;
874 VOID *Buffer1 = NULL;
875 VOID *Buffer2 = NULL;
876 UINTN Size1;
877 UINTN Size2;
878 UINTN Offset;
879 UINTN Chunk = FILE_COPY_CHUNK;
880
881 if (Argc != 3) {
882 return EFI_INVALID_PARAMETER;
883 }
884
885 File1 = EfiOpen(Argv[1], EFI_FILE_MODE_READ, 0);
886 if (File1 == NULL) {
887 AsciiPrint("File 1 open error.\n");
888 return EFI_NOT_FOUND;
889 }
890
891 File2 = EfiOpen(Argv[2], EFI_FILE_MODE_READ, 0);
892 if (File2 == NULL) {
893 AsciiPrint("File 2 open error.\n");
894 return EFI_NOT_FOUND;
895 }
896
897 Size1 = EfiTell(File1, NULL);
898 Size2 = EfiTell(File2, NULL);
899
900 if (Size1 != Size2) {
901 AsciiPrint("Files differ.\n");
902 goto Exit;
903 }
904
905 Buffer1 = AllocatePool(FILE_COPY_CHUNK);
906 if (Buffer1 == NULL) {
907 goto Exit;
908 }
909
910 Buffer2 = AllocatePool(FILE_COPY_CHUNK);
911 if (Buffer2 == NULL) {
912 goto Exit;
913 }
914
915 for (Offset = 0; Offset + FILE_COPY_CHUNK <= Size1; Offset += Chunk) {
916 Chunk = FILE_COPY_CHUNK;
917
918 Status = EfiRead(File1, Buffer1, &Chunk);
919 if (EFI_ERROR(Status)) {
920 AsciiPrint("File 1 read error\n");
921 goto Exit;
922 }
923
924 Status = EfiRead(File2, Buffer2, &Chunk);
925 if (EFI_ERROR(Status)) {
926 AsciiPrint("File 2 read error\n");
927 goto Exit;
928 }
929
930 if (CompareMem(Buffer1, Buffer2, Chunk) != 0) {
931 AsciiPrint("Files differ.\n");
932 goto Exit;
933 };
934 }
935
936 // Any left over?
937 if (Offset < Size1) {
938 Chunk = Size1 - Offset;
939
940 Status = EfiRead(File1, Buffer1, &Chunk);
941 if (EFI_ERROR(Status)) {
942 AsciiPrint("File 1 read error\n");
943 goto Exit;
944 }
945
946 Status = EfiRead(File2, Buffer2, &Chunk);
947 if (EFI_ERROR(Status)) {
948 AsciiPrint("File 2 read error\n");
949 goto Exit;
950 }
951 }
952
953 if (CompareMem(Buffer1, Buffer2, Chunk) != 0) {
954 AsciiPrint("Files differ.\n");
955 } else {
956 AsciiPrint("Files are identical.\n");
957 }
958
959 Exit:
960 if (File1 != NULL) {
961 Status = EfiClose(File1);
962 if (EFI_ERROR(Status)) {
963 AsciiPrint("File 1 close error %r\n", Status);
964 }
965 }
966
967 if (File2 != NULL) {
968 Status = EfiClose(File2);
969 if (EFI_ERROR(Status)) {
970 AsciiPrint("File 2 close error %r\n", Status);
971 }
972 }
973
974 if (Buffer1 != NULL) {
975 FreePool(Buffer1);
976 }
977
978 if (Buffer2 != NULL) {
979 FreePool(Buffer2);
980 }
981
982 return Status;
983 }
984
985 GLOBAL_REMOVE_IF_UNREFERENCED const EBL_COMMAND_TABLE mCmdDeviceTemplate[] =
986 {
987 {
988 "connect",
989 "[d]; Connect all EFI devices. d means disconnect",
990 NULL,
991 EblConnectCmd
992 },
993 {
994 "device",
995 "; Show information about boot devices",
996 NULL,
997 EblDeviceCmd
998 },
999 {
1000 "go",
1001 " dev:path loadaddress entrypoint args; load to given address and jump in",
1002 NULL,
1003 EblGoCmd
1004 },
1005 {
1006 "loadfv",
1007 " devname; Load PI FV from device",
1008 NULL,
1009 EblLoadFvCmd
1010 },
1011 {
1012 "start",
1013 " path; EFI Boot Device:filepath. fs1:\\EFI\\BOOT.EFI",
1014 NULL,
1015 EblStartCmd
1016 },
1017 {
1018 "memmap",
1019 "; dump EFI memory map",
1020 NULL,
1021 EblMemMapCmd
1022 },
1023 {
1024 "cp",
1025 " file1 file2; copy file only.",
1026 NULL,
1027 EblFileCopyCmd
1028 },
1029 {
1030 "diff",
1031 " file1 file2; compare files",
1032 NULL,
1033 EblFileDiffCmd
1034 }
1035 };
1036
1037
1038 /**
1039 Initialize the commands in this in this file
1040 **/
1041
1042 VOID
1043 EblInitializeDeviceCmd (
1044 VOID
1045 )
1046 {
1047 EfiGetSystemConfigurationTable (&gEfiDxeServicesTableGuid, (VOID **) &gDS);
1048 EblAddCommands (mCmdDeviceTemplate, sizeof (mCmdDeviceTemplate)/sizeof (EBL_COMMAND_TABLE));
1049 }
1050