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