/** Send null requests to all removable media block IO devices so the a media add/remove/change can be detected in real before we execute a command. This is mainly due to the fact that the FAT driver does not do this today so you can get stale dir commands after an SD Card has been removed. **/ VOID EblProbeRemovableMedia ( VOID ) { UINTN Index; UINTN Max; EFI_OPEN_FILE *File; // // Probe for media insertion/removal in removable media devices // Max = EfiGetDeviceCounts (EfiOpenBlockIo); if (Max != 0) { for (Index = 0; Index < Max; Index++) { File = EfiDeviceOpenByType (EfiOpenBlockIo, Index); if (File != NULL) { if (File->FsBlockIoMedia->RemovableMedia) { // Probe to see if media is present (or not) or media changed // this causes the ReinstallProtocolInterface() to fire in the // block io driver to update the system about media change events File->FsBlockIo->ReadBlocks (File->FsBlockIo, File->FsBlockIo->Media->MediaId, (EFI_LBA)0, 0, NULL); } EfiClose (File); } } } }
/** Print information about the File System device. @param File Open File for the device **/ VOID EblPrintFsInfo ( IN EFI_OPEN_FILE *File ) { CHAR16 *Str; if (File == NULL) { return; } AsciiPrint (" %a: ", File->DeviceName); if (File->FsInfo != NULL) { for (Str = File->FsInfo->VolumeLabel; *Str != '\0'; Str++) { if (*Str == ' ') { // UI makes you enter _ for space, so make the printout match that *Str = '_'; } AsciiPrint ("%c", *Str); } AsciiPrint (":"); if (File->FsInfo->ReadOnly) { AsciiPrint ("ReadOnly"); } } AsciiPrint ("\n"); EfiClose (File); }
/** Print information about the Blk IO devices. If the device supports PXE dump out extra information @param File Open File for the device **/ VOID EblPrintBlkIoInfo ( IN EFI_OPEN_FILE *File ) { UINT64 DeviceSize; UINTN Index; UINTN Max; EFI_OPEN_FILE *FsFile; if (File == NULL) { return; } AsciiPrint (" %a: ", File->DeviceName); // print out name of file system, if any, on this block device Max = EfiGetDeviceCounts (EfiOpenFileSystem); if (Max != 0) { for (Index = 0; Index < Max; Index++) { FsFile = EfiDeviceOpenByType (EfiOpenFileSystem, Index); if (FsFile != NULL) { if (FsFile->EfiHandle == File->EfiHandle) { AsciiPrint ("fs%d: ", Index); EfiClose (FsFile); break; } EfiClose (FsFile); } } } // Print out useful Block IO media properties if (File->FsBlockIoMedia->RemovableMedia) { AsciiPrint ("Removable "); } if (!File->FsBlockIoMedia->MediaPresent) { AsciiPrint ("No Media\n"); } else { if (File->FsBlockIoMedia->LogicalPartition) { AsciiPrint ("Partition "); } DeviceSize = MultU64x32 (File->FsBlockIoMedia->LastBlock + 1, File->FsBlockIoMedia->BlockSize); AsciiPrint ("Size = 0x%lX\n", DeviceSize); } EfiClose (File); }
/** 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; }
/** Print information about the FV devices. @param File Open File for the device **/ VOID EblPrintFvbInfo ( IN EFI_OPEN_FILE *File ) { if (File == NULL) { return; } AsciiPrint (" %a: 0x%08lx - 0x%08lx : 0x%08x\n", File->DeviceName, File->FvStart, File->FvStart + File->FvSize - 1, File->FvSize); EfiClose (File); }
/** Print information about the Load File devices. If the device supports PXE dump out extra information @param File Open File for the device **/ VOID EblPrintLoadFileInfo ( IN EFI_OPEN_FILE *File ) { EFI_DEVICE_PATH_PROTOCOL *DevicePathNode; MAC_ADDR_DEVICE_PATH *MacAddr; UINTN HwAddressSize; UINTN Index; if (File == NULL) { return; } AsciiPrint (" %a: %a ", File->DeviceName, EblLoadFileBootTypeString (File->EfiHandle)); if (File->DevicePath != NULL) { // Try to print out the MAC address for (DevicePathNode = File->DevicePath; !IsDevicePathEnd (DevicePathNode); DevicePathNode = NextDevicePathNode (DevicePathNode)) { if ((DevicePathType (DevicePathNode) == MESSAGING_DEVICE_PATH) && (DevicePathSubType (DevicePathNode) == MSG_MAC_ADDR_DP)) { MacAddr = (MAC_ADDR_DEVICE_PATH *)DevicePathNode; HwAddressSize = sizeof (EFI_MAC_ADDRESS); if (MacAddr->IfType == 0x01 || MacAddr->IfType == 0x00) { HwAddressSize = 6; } AsciiPrint ("MAC "); for (Index = 0; Index < HwAddressSize; Index++) { AsciiPrint ("%02x", MacAddr->MacAddress.Addr[Index] & 0xff); } } } } AsciiPrint ("\n"); EfiClose (File); return; }
/** 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; }
EFI_STATUS EfiCopyFile ( IN CHAR8 *DestinationFile, IN CHAR8 *SourceFile ) { EFI_OPEN_FILE *Source = NULL; EFI_OPEN_FILE *Destination = NULL; EFI_STATUS Status = EFI_SUCCESS; VOID *Buffer = NULL; UINTN Size; UINTN Offset; UINTN Chunk = FILE_COPY_CHUNK; Source = EfiOpen (SourceFile, EFI_FILE_MODE_READ, 0); if (Source == NULL) { AsciiPrint("Source file open error.\n"); Status = EFI_NOT_FOUND; goto Exit; } Destination = EfiOpen (DestinationFile, EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE, 0); if (Destination == NULL) { AsciiPrint("Destination file open error.\n"); Status = EFI_NOT_FOUND; goto Exit; } Buffer = AllocatePool(FILE_COPY_CHUNK); if (Buffer == NULL) { Status = EFI_OUT_OF_RESOURCES; goto Exit; } Size = EfiTell(Source, NULL); for (Offset = 0; Offset + FILE_COPY_CHUNK <= Size; Offset += Chunk) { Chunk = FILE_COPY_CHUNK; Status = EfiRead(Source, Buffer, &Chunk); if (EFI_ERROR(Status)) { AsciiPrint("Read file error %r\n", Status); goto Exit; } Status = EfiWrite(Destination, Buffer, &Chunk); if (EFI_ERROR(Status)) { AsciiPrint("Write file error %r\n", Status); goto Exit; } } // Any left over? if (Offset < Size) { Chunk = Size - Offset; Status = EfiRead(Source, Buffer, &Chunk); if (EFI_ERROR(Status)) { AsciiPrint("Read file error\n"); goto Exit; } Status = EfiWrite(Destination, Buffer, &Chunk); if (EFI_ERROR(Status)) { AsciiPrint("Write file error\n"); goto Exit; } } Exit: if (Source != NULL) { Status = EfiClose(Source); if (EFI_ERROR(Status)) { AsciiPrint("Source close error"); } } if (Destination != NULL) { Status = EfiClose(Destination); if (EFI_ERROR(Status)) { AsciiPrint("Destination close error"); } } if (Buffer != NULL) { FreePool(Buffer); } return Status; }
/** Perform a dir on a device. The device must support Simple File System Protocol or the FV protocol. Argv[0] - "dir" Argv[1] - Device Name:path. Path is optional Argv[2] - Optional filename to match on. A leading * means match substring Argv[3] - Optional FV file type dir fs1:\efi ; perform a dir on fs1: device in the efi directory dir fs1:\efi *.efi; perform a dir on fs1: device in the efi directory but only print out files that contain the string *.efi dir fv1:\ ; perform a dir on fv1: device in the efi directory NOTE: fv devices do not contain subdirs dir fv1:\ * PEIM ; will match all files of type PEIM @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 EblDirCmd ( IN UINTN Argc, IN CHAR8 **Argv ) { EFI_STATUS Status; EFI_OPEN_FILE *File; EFI_FILE_INFO *DirInfo; UINTN ReadSize; UINTN CurrentRow; CHAR16 *MatchSubString; EFI_STATUS GetNextFileStatus; UINTN Key; EFI_FV_FILETYPE SearchType; EFI_FV_FILETYPE Type; EFI_FV_FILE_ATTRIBUTES Attributes; UINTN Size; EFI_GUID NameGuid; EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv; UINT32 AuthenticationStatus; VOID *Section; UINTN SectionSize; EFI_FV_FILETYPE Index; UINTN Length; UINTN BestMatchCount; CHAR16 UnicodeFileName[MAX_CMD_LINE]; CHAR8 *Path; CHAR8 *TypeStr; UINTN TotalSize; if (Argc <= 1) { Path = EfiGetCwd (); if (Path == NULL) { return EFI_SUCCESS; } } else { Path = Argv[1]; } File = EfiOpen (Path, EFI_FILE_MODE_READ, 0); if (File == NULL) { return EFI_SUCCESS; } if (File->Type == EfiOpenFirmwareVolume) { // FV Dir SearchType = EFI_FV_FILETYPE_ALL; UnicodeFileName[0] = '\0'; MatchSubString = &UnicodeFileName[0]; if (Argc > 2) { AsciiStrToUnicodeStr (Argv[2], UnicodeFileName); if (UnicodeFileName[0] == '*') { // Handle *Name substring matching MatchSubString = &UnicodeFileName[1]; } // Handle file type matchs if (Argc > 3) { // match a specific file type, always last argument Length = AsciiStrLen (Argv[3]); for (Index = 1, BestMatchCount = 0; Index < sizeof (gFvFileType)/sizeof (CHAR8 *); Index++) { if (AsciiStriCmp (gFvFileType[Index], Argv[3]) == 0) { // exact match SearchType = Index; break; } if (AsciiStrniCmp (Argv[3], gFvFileType[Index], Length) == 0) { // partial match, so keep looking to make sure there is only one partial match BestMatchCount++; SearchType = Index; } } if (BestMatchCount > 1) { SearchType = EFI_FV_FILETYPE_ALL; } } } TotalSize = 0; Fv = File->Fv; Key = 0; CurrentRow = 0; do { Type = SearchType; GetNextFileStatus = Fv->GetNextFile ( Fv, &Key, &Type, &NameGuid, &Attributes, &Size ); if (!EFI_ERROR (GetNextFileStatus)) { TotalSize += Size; // Calculate size of entire file Section = NULL; Size = 0; Status = Fv->ReadFile ( Fv, &NameGuid, Section, &Size, &Type, &Attributes, &AuthenticationStatus ); if (!((Status == EFI_BUFFER_TOO_SMALL) || !EFI_ERROR (Status))) { // EFI_SUCCESS or EFI_BUFFER_TOO_SMALL mean size is valid Size = 0; } TypeStr = (Type <= EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) ? gFvFileType[Type] : "UNKNOWN"; // read the UI seciton to do a name match. Section = NULL; Status = Fv->ReadSection ( Fv, &NameGuid, EFI_SECTION_USER_INTERFACE, 0, &Section, &SectionSize, &AuthenticationStatus ); if (!EFI_ERROR (Status)) { if (StrStr (Section, MatchSubString) != NULL) { AsciiPrint ("%,9d %7a %g %s\n", Size, TypeStr, &NameGuid, Section); if (EblAnyKeyToContinueQtoQuit (&CurrentRow, FALSE)) { break; } } FreePool (Section); } else { if (*MatchSubString == '\0') { AsciiPrint ("%,9d %7a %g\n", Size, TypeStr, &NameGuid); if (EblAnyKeyToContinueQtoQuit (&CurrentRow, FALSE)) { break; } } } } } while (!EFI_ERROR (GetNextFileStatus)); if (SearchType == EFI_FV_FILETYPE_ALL) { AsciiPrint ("%,20d bytes in files %,d bytes free\n", TotalSize, File->FvSize - File->FvHeaderSize - TotalSize); } } else if ((File->Type == EfiOpenFileSystem) || (File->Type == EfiOpenBlockIo)) { // Simple File System DIR if (File->FsFileInfo == NULL) { return EFI_SUCCESS; } if (!(File->FsFileInfo->Attribute & EFI_FILE_DIRECTORY)) { return EFI_SUCCESS; } // Handle *Name substring matching MatchSubString = NULL; UnicodeFileName[0] = '\0'; if (Argc > 2) { AsciiStrToUnicodeStr (Argv[2], UnicodeFileName); if (UnicodeFileName[0] == '*') { MatchSubString = &UnicodeFileName[1]; } } File->FsFileHandle->SetPosition (File->FsFileHandle, 0); for (CurrentRow = 0;;) { // First read gets the size DirInfo = NULL; ReadSize = 0; Status = File->FsFileHandle->Read (File->FsFileHandle, &ReadSize, DirInfo); if (Status == EFI_BUFFER_TOO_SMALL) { // Allocate the buffer for the real read DirInfo = AllocatePool (ReadSize); if (DirInfo == NULL) { goto Done; } // Read the data Status = File->FsFileHandle->Read (File->FsFileHandle, &ReadSize, DirInfo); if ((EFI_ERROR (Status)) || (ReadSize == 0)) { break; } } else { break; } if (MatchSubString != NULL) { if (StrStr (&DirInfo->FileName[0], MatchSubString) == NULL) { // does not match *name argument, so skip continue; } } else if (UnicodeFileName[0] != '\0') { // is not an exact match for name argument, so skip if (StrCmp (&DirInfo->FileName[0], UnicodeFileName) != 0) { continue; } } if (DirInfo->Attribute & EFI_FILE_DIRECTORY) { AsciiPrint (" <DIR> %s\n", &DirInfo->FileName[0]); } else { AsciiPrint ("%,14ld %s\n", DirInfo->FileSize, &DirInfo->FileName[0]); } if (EblAnyKeyToContinueQtoQuit (&CurrentRow, FALSE)) { break; } FreePool (DirInfo); } Done: if (DirInfo != NULL) { FreePool (DirInfo); } } EfiClose (File); return EFI_SUCCESS; }
/** Toggle page break global. This turns on and off prompting to Quit or hit any key to continue when a command is about to scroll the screen with its output Argv[0] - "hexdump"[.#] # is optional 1,2, or 4 for width Argv[1] - Device or File to dump. Argv[2] - Optional offset to start dumping Argv[3] - Optional number of bytes to dump @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 EFIAPI EblHexdumpCmd ( IN UINTN Argc, IN CHAR8 **Argv ) { EFI_OPEN_FILE *File; VOID *Location; UINTN Size; UINTN Width; UINTN Offset = 0; EFI_STATUS Status; UINTN Chunk = HEXDUMP_CHUNK; if ((Argc < 2) || (Argc > 4)) { return EFI_INVALID_PARAMETER; } Width = WidthFromCommandName (Argv[0], 1); if ((Width != 1) && (Width != 2) && (Width != 4)) { return EFI_INVALID_PARAMETER; } File = EfiOpen (Argv[1], EFI_FILE_MODE_READ, 0); if (File == NULL) { return EFI_NOT_FOUND; } Location = AllocatePool (Chunk); Size = (Argc > 3) ? AsciiStrHexToUintn (Argv[3]) : EfiTell (File, NULL); Offset = 0; if (Argc > 2) { Offset = AsciiStrHexToUintn (Argv[2]); if (Offset > 0) { // Make sure size includes the part of the file we have skipped Size += Offset; } } Status = EfiSeek (File, Offset, EfiSeekStart); if (EFI_ERROR (Status)) { goto Exit; } for (; Offset + HEXDUMP_CHUNK <= Size; Offset += Chunk) { Chunk = HEXDUMP_CHUNK; Status = EfiRead (File, Location, &Chunk); if (EFI_ERROR(Status)) { AsciiPrint ("Error reading file content\n"); goto Exit; } Status = OutputData (Location, Chunk, Width, File->BaseOffset + Offset); if (EFI_ERROR(Status)) { if (Status == EFI_END_OF_FILE) { Status = EFI_SUCCESS; } goto Exit; } } // Any left over? if (Offset < Size) { Chunk = Size - Offset; Status = EfiRead (File, Location, &Chunk); if (EFI_ERROR(Status)) { AsciiPrint ("Error reading file content\n"); goto Exit; } Status = OutputData (Location, Chunk, Width, File->BaseOffset + Offset); if (EFI_ERROR(Status)) { if (Status == EFI_END_OF_FILE) { Status = EFI_SUCCESS; } goto Exit; } } Exit: EfiClose (File); FreePool (Location); return EFI_SUCCESS; }
EFI_STATUS EblFileDiffCmd ( IN UINTN Argc, IN CHAR8 **Argv ) { EFI_OPEN_FILE *File1 = NULL; EFI_OPEN_FILE *File2 = NULL; EFI_STATUS Status = EFI_SUCCESS; VOID *Buffer1 = NULL; VOID *Buffer2 = NULL; UINTN Size1; UINTN Size2; UINTN Offset; UINTN Chunk = FILE_COPY_CHUNK; if (Argc != 3) { return EFI_INVALID_PARAMETER; } File1 = EfiOpen(Argv[1], EFI_FILE_MODE_READ, 0); if (File1 == NULL) { AsciiPrint("File 1 open error.\n"); return EFI_NOT_FOUND; } File2 = EfiOpen(Argv[2], EFI_FILE_MODE_READ, 0); if (File2 == NULL) { AsciiPrint("File 2 open error.\n"); return EFI_NOT_FOUND; } Size1 = EfiTell(File1, NULL); Size2 = EfiTell(File2, NULL); if (Size1 != Size2) { AsciiPrint("Files differ.\n"); goto Exit; } Buffer1 = AllocatePool(FILE_COPY_CHUNK); if (Buffer1 == NULL) { goto Exit; } Buffer2 = AllocatePool(FILE_COPY_CHUNK); if (Buffer2 == NULL) { goto Exit; } for (Offset = 0; Offset + FILE_COPY_CHUNK <= Size1; Offset += Chunk) { Chunk = FILE_COPY_CHUNK; Status = EfiRead(File1, Buffer1, &Chunk); if (EFI_ERROR(Status)) { AsciiPrint("File 1 read error\n"); goto Exit; } Status = EfiRead(File2, Buffer2, &Chunk); if (EFI_ERROR(Status)) { AsciiPrint("File 2 read error\n"); goto Exit; } if (CompareMem(Buffer1, Buffer2, Chunk) != 0) { AsciiPrint("Files differ.\n"); goto Exit; }; } // Any left over? if (Offset < Size1) { Chunk = Size1 - Offset; Status = EfiRead(File1, Buffer1, &Chunk); if (EFI_ERROR(Status)) { AsciiPrint("File 1 read error\n"); goto Exit; } Status = EfiRead(File2, Buffer2, &Chunk); if (EFI_ERROR(Status)) { AsciiPrint("File 2 read error\n"); goto Exit; } } if (CompareMem(Buffer1, Buffer2, Chunk) != 0) { AsciiPrint("Files differ.\n"); } else { AsciiPrint("Files are identical.\n"); } Exit: if (File1 != NULL) { Status = EfiClose(File1); if (EFI_ERROR(Status)) { AsciiPrint("File 1 close error %r\n", Status); } } if (File2 != NULL) { Status = EfiClose(File2); if (EFI_ERROR(Status)) { AsciiPrint("File 2 close error %r\n", Status); } } if (Buffer1 != NULL) { FreePool(Buffer1); } if (Buffer2 != NULL) { FreePool(Buffer2); } return Status; }
EFI_STATUS EblFileCopyCmd ( IN UINTN Argc, IN CHAR8 **Argv ) { EFI_OPEN_FILE *Source = NULL; EFI_OPEN_FILE *Destination = NULL; EFI_STATUS Status = EFI_SUCCESS; VOID *Buffer = NULL; UINTN Size; UINTN Offset; UINTN Chunk = FILE_COPY_CHUNK; UINTN FileNameLen; CHAR8* DestFileName; CHAR8* SrcFileName; CHAR8* SrcPtr; if (Argc < 3) { return EFI_INVALID_PARAMETER; } DestFileName = Argv[2]; FileNameLen = AsciiStrLen (DestFileName); // Check if the destination file name looks like a directory if ((DestFileName[FileNameLen-1] == '\\') || (DestFileName[FileNameLen-1] == ':')) { // Set the pointer after the source drive (eg: after fs1:) SrcPtr = AsciiStrStr (Argv[1], ":"); if (SrcPtr == NULL) { SrcPtr = Argv[1]; } else { SrcPtr++; if (*SrcPtr == '\\') { SrcPtr++; } } if (*SrcPtr == '\0') { AsciiPrint("Source file incorrect.\n"); } // Skip the Source Directories while (1) { SrcFileName = SrcPtr; SrcPtr = AsciiStrStr (SrcPtr,"\\"); if (SrcPtr != NULL) { SrcPtr++; } else { break; } } if (*SrcFileName == '\0') { AsciiPrint("Source file incorrect (Error 2).\n"); } // Construct the destination filepath DestFileName = (CHAR8*)AllocatePool (FileNameLen + AsciiStrLen (SrcFileName) + 1); AsciiStrCpy (DestFileName, Argv[2]); AsciiStrCat (DestFileName, SrcFileName); } Source = EfiOpen(Argv[1], EFI_FILE_MODE_READ, 0); if (Source == NULL) { AsciiPrint("Source file open error.\n"); return EFI_NOT_FOUND; } Destination = EfiOpen(DestFileName, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE, 0); if (Destination == NULL) { AsciiPrint("Destination file open error.\n"); return EFI_NOT_FOUND; } Buffer = AllocatePool(FILE_COPY_CHUNK); if (Buffer == NULL) { goto Exit; } Size = EfiTell(Source, NULL); for (Offset = 0; Offset + FILE_COPY_CHUNK <= Size; Offset += Chunk) { Chunk = FILE_COPY_CHUNK; Status = EfiRead(Source, Buffer, &Chunk); if (EFI_ERROR(Status)) { AsciiPrint("Read file error %r\n", Status); goto Exit; } Status = EfiWrite(Destination, Buffer, &Chunk); if (EFI_ERROR(Status)) { AsciiPrint("Write file error %r\n", Status); goto Exit; } } // Any left over? if (Offset < Size) { Chunk = Size - Offset; Status = EfiRead(Source, Buffer, &Chunk); if (EFI_ERROR(Status)) { AsciiPrint("Read file error %r\n", Status); goto Exit; } Status = EfiWrite(Destination, Buffer, &Chunk); if (EFI_ERROR(Status)) { AsciiPrint("Write file error %r\n", Status); goto Exit; } } Exit: if (Source != NULL) { Status = EfiClose(Source); if (EFI_ERROR(Status)) { AsciiPrint("Source close error %r\n", Status); } } if (Destination != NULL) { Status = EfiClose(Destination); if (EFI_ERROR(Status)) { AsciiPrint("Destination close error %r\n", Status); } // Case when we have concated the filename to the destination directory if (DestFileName != Argv[2]) { FreePool (DestFileName); } } if (Buffer != NULL) { FreePool(Buffer); } 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; }
/** Perform an EFI connect to connect devices that follow the EFI driver model. If it is a PI system also call the dispatcher in case a new FV was made available by one of the connect EFI drivers (this is not a common case). Argv[0] - "connect" @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 EblConnectCmd ( IN UINTN Argc, IN CHAR8 **Argv ) { EFI_STATUS Status; UINTN HandleCount; EFI_HANDLE *HandleBuffer; UINTN Index; BOOLEAN Dispatch; EFI_OPEN_FILE *File; if (Argc > 1) { if ((*Argv[1] == 'd') || (*Argv[1] == 'D')) { Status = gBS->LocateHandleBuffer ( AllHandles, NULL, NULL, &HandleCount, &HandleBuffer ); if (EFI_ERROR (Status)) { return Status; } for (Index = 0; Index < HandleCount; Index++) { gBS->DisconnectController (HandleBuffer[Index], NULL, NULL); } // // Given we disconnect our console we should go and do a connect now // } else { File = EfiOpen (Argv[1], EFI_FILE_MODE_READ, 0); if (File != NULL) { AsciiPrint ("Connecting %a\n", Argv[1]); gBS->ConnectController (File->EfiHandle, NULL, NULL, TRUE); EfiClose (File); return EFI_SUCCESS; } } } Dispatch = FALSE; do { Status = gBS->LocateHandleBuffer ( AllHandles, NULL, NULL, &HandleCount, &HandleBuffer ); if (EFI_ERROR (Status)) { return Status; } for (Index = 0; Index < HandleCount; Index++) { gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE); } FreePool (HandleBuffer); // // Check to see if it's possible to dispatch an more DXE drivers. // The BdsLibConnectAllEfi () may have made new DXE drivers show up. // If anything is Dispatched Status == EFI_SUCCESS and we will try // the connect again. // if (gDS == NULL) { Status = EFI_NOT_FOUND; } else { Status = gDS->Dispatch (); if (!EFI_ERROR (Status)) { Dispatch = TRUE; } } } while (!EFI_ERROR (Status)); if (Dispatch) { AsciiPrint ("Connected and dispatched\n"); } else { AsciiPrint ("Connect\n"); } return EFI_SUCCESS; }
/** 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; }