/** Execute the passed in file like a series of commands. The ; can be used on a single line to indicate multiple commands per line. The Ascii text file can contain any number of lines. The following line termination forms are supported: LF : Unix, Mac OS X*, BeOS CR+LF: MS-DOS*, Microsoft Windows* CR : Commodore, Apple II, and really Mac OS LF+CR: for simplicity and completeness Argv[0] - "script" Argv[1] - Device Name:path for the file to load script fv1:\script.txt @param Argc Number of command arguments in Argv @param Argv Array of strings that represent the parsed command line. Argv[0] is the command name @return EFI_SUCCESS **/ EFI_STATUS EblScriptCmd ( IN UINTN Argc, IN CHAR8 **Argv ) { EFI_STATUS Status; EFI_OPEN_FILE *File; VOID *Address; UINTN Size; CHAR8 *Ptr; CHAR8 *ScanPtr; UINTN CmdLineSize; if (Argc < 2) { // file name required return EFI_SUCCESS; } File = EfiOpen (Argv[1], EFI_FILE_MODE_READ, 0); if (File == NULL) { AsciiPrint (" %a is not a valid path\n", Argv[1]); return EFI_SUCCESS; } Status = EfiReadAllocatePool (File, &Address, &Size); if (!EFI_ERROR (Status)) { // Loop through each line in the text file for (Ptr = (CHAR8 *)Address; (Ptr < (((CHAR8 *)Address) + Size)) && !EFI_ERROR (Status); Ptr += CmdLineSize) { for (CmdLineSize = 0, ScanPtr = Ptr; ; CmdLineSize++, ScanPtr++) { // look for the end of the line if ((*ScanPtr == EBL_CR) || (*ScanPtr == EBL_LF)) { // convert to NULL as this is what input routine would do *ScanPtr = 0; if ((*(ScanPtr + 1) == EBL_CR) || (*(ScanPtr + 1) == EBL_LF)) { // if its a set get the 2nd EOL char CmdLineSize++; *(ScanPtr + 1) = 0; } CmdLineSize++; break; } } Status = ProcessCmdLine (Ptr, CmdLineSize); } FreePool (Address); } EfiClose (File); return Status; }
/** Load a Firmware Volume (FV) into memory from a device. This causes drivers in the FV to be dispatched if the dependencies of the drivers are met. Argv[0] - "loadfv" Argv[1] - device name and path loadfv fs1:\Temp\Fv.Fv ; load an FV from the disk loadfv fv0:\FV ; load an FV from an FV (not common) loadfv LoadFile0: ; load an FV via a PXE boot @param Argc Number of command arguments in Argv @param Argv Array of strings that represent the parsed command line. Argv[0] is the command name @return EFI_SUCCESS **/ EFI_STATUS EblLoadFvCmd ( IN UINTN Argc, IN CHAR8 **Argv ) { EFI_STATUS Status; EFI_OPEN_FILE *File; VOID *FvStart; UINTN FvSize; EFI_HANDLE FvHandle; if (Argc < 2) { return EFI_INVALID_PARAMETER; } File = EfiOpen (Argv[1], EFI_FILE_MODE_READ, 0); if (File == NULL) { return EFI_INVALID_PARAMETER; } if (File->Type == EfiOpenMemoryBuffer) { // If it is a address just use it. Status = gDS->ProcessFirmwareVolume (File->Buffer, File->Size, &FvHandle); } else { // If it is a file read it into memory and use it Status = EfiReadAllocatePool (File, &FvStart, &FvSize); EfiClose (File); if (EFI_ERROR (Status)) { return Status; } Status = gDS->ProcessFirmwareVolume (FvStart, FvSize, &FvHandle); if (EFI_ERROR (Status)) { FreePool (FvStart); } } return Status; }
/** Load a file into memory and optionally jump to it. A load address can be specified or automatically allocated. A quoted command line can optionally be passed into the image. Argv[0] - "go" Argv[1] - Device Name:path for the file to load Argv[2] - Address to load to or '*' if the load address will be allocated Argv[3] - Optional Entry point to the image. Image will be called if present Argv[4] - "" string that will be passed as Argc & Argv to EntryPoint. Needs to include the command name go fv1:\EblCmdX 0x10000 0x10010 "EblCmdX Arg2 Arg3 Arg4"; - load EblCmdX from FV1 to location 0x10000 and call the entry point at 0x10010 passing in "EblCmdX Arg2 Arg3 Arg4" as the arguments. go fv0:\EblCmdX * 0x10 "EblCmdX Arg2 Arg3 Arg4"; - load EblCmdX from FS0 to location allocated by this command and call the entry point at offset 0x10 passing in "EblCmdX Arg2 Arg3 Arg4" as the arguments. go fv1:\EblCmdX 0x10000; Load EblCmdX to address 0x10000 and return @param Argc Number of command arguments in Argv @param Argv Array of strings that represent the parsed command line. Argv[0] is the command name @return EFI_SUCCESS **/ EFI_STATUS EblGoCmd ( IN UINTN Argc, IN CHAR8 **Argv ) { EFI_STATUS Status; EFI_OPEN_FILE *File; VOID *Address; UINTN Size; EBL_COMMMAND EntryPoint; UINTN EntryPointArgc; CHAR8 *EntryPointArgv[MAX_ARGS]; if (Argc <= 2) { // device name and laod address are required return EFI_SUCCESS; } File = EfiOpen (Argv[1], EFI_FILE_MODE_READ, 0); if (File == NULL) { AsciiPrint (" %a is not a valid path\n", Argv[1]); return EFI_SUCCESS; } EntryPoint = (EBL_COMMMAND)((Argc > 3) ? (UINTN)AsciiStrHexToUintn (Argv[3]) : (UINTN)NULL); if (Argv[2][0] == '*') { // * Means allocate the buffer Status = EfiReadAllocatePool (File, &Address, &Size); // EntryPoint is relative to the start of the image EntryPoint = (EBL_COMMMAND)((UINTN)EntryPoint + (UINTN)Address); } else { Address = (VOID *)AsciiStrHexToUintn (Argv[2]); Size = File->Size; // File->Size for LoadFile is lazy so we need to use the tell to figure it out EfiTell (File, NULL); Status = EfiRead (File, Address, &Size); } if (!EFI_ERROR (Status)) { AsciiPrint ("Loaded %,d bytes to 0x%08x\n", Size, Address); if (Argc > 3) { if (Argc > 4) { ParseArguments (Argv[4], &EntryPointArgc, EntryPointArgv); } else { EntryPointArgc = 1; EntryPointArgv[0] = File->FileName; } Status = EntryPoint (EntryPointArgc, EntryPointArgv); } } EfiClose (File); return Status; }
/** Start an EFI image (PE32+ with EFI defined entry point). Argv[0] - "start" Argv[1] - device name and path Argv[2] - "" string to pass into image being started start fs1:\Temp\Fv.Fv "arg to pass" ; load an FV from the disk and pass the ; ascii string arg to pass to the image start fv0:\FV ; load an FV from an FV (not common) start LoadFile0: ; load an FV via a PXE boot @param Argc Number of command arguments in Argv @param Argv Array of strings that represent the parsed command line. Argv[0] is the command name @return EFI_SUCCESS **/ EFI_STATUS EblStartCmd ( IN UINTN Argc, IN CHAR8 **Argv ) { EFI_STATUS Status; EFI_OPEN_FILE *File; EFI_DEVICE_PATH_PROTOCOL *DevicePath; EFI_HANDLE ImageHandle; UINTN ExitDataSize; CHAR16 *ExitData; VOID *Buffer; UINTN BufferSize; EFI_LOADED_IMAGE_PROTOCOL *ImageInfo; ImageHandle = NULL; if (Argc < 2) { return EFI_INVALID_PARAMETER; } File = EfiOpen (Argv[1], EFI_FILE_MODE_READ, 0); if (File == NULL) { return EFI_INVALID_PARAMETER; } DevicePath = File->DevicePath; if (DevicePath != NULL) { // check for device path form: blk, fv, fs, and loadfile Status = gBS->LoadImage (FALSE, gImageHandle, DevicePath, NULL, 0, &ImageHandle); } else { // Check for buffer form: A0x12345678:0x1234 syntax. // Means load using buffer starting at 0x12345678 of size 0x1234. Status = EfiReadAllocatePool (File, &Buffer, &BufferSize); if (EFI_ERROR (Status)) { EfiClose (File); return Status; } Status = gBS->LoadImage (FALSE, gImageHandle, DevicePath, Buffer, BufferSize, &ImageHandle); FreePool (Buffer); } EfiClose (File); if (!EFI_ERROR (Status)) { if (Argc >= 3) { // Argv[2] is a "" string that we pass directly to the EFI application without the "" // We don't pass Argv[0] to the EFI Application (it's name) just the args Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **)&ImageInfo); ASSERT_EFI_ERROR (Status); ImageInfo->LoadOptionsSize = (UINT32)AsciiStrSize (Argv[2]); ImageInfo->LoadOptions = AllocatePool (ImageInfo->LoadOptionsSize); AsciiStrCpy (ImageInfo->LoadOptions, Argv[2]); } // Transfer control to the EFI image we loaded with LoadImage() Status = gBS->StartImage (ImageHandle, &ExitDataSize, &ExitData); } return Status; }