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