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