/** This function is to display the IPv6 address. @param[in] Ip The pointer to the IPv6 address. **/ VOID HttpBootShowIp6Addr ( IN EFI_IPv6_ADDRESS *Ip ) { UINTN Index; for (Index = 0; Index < 16; Index++) { if (Ip->Addr[Index] != 0) { AsciiPrint ("%x", Ip->Addr[Index]); } Index++; if (Index > 15) { return; } if (((Ip->Addr[Index] & 0xf0) == 0) && (Ip->Addr[Index - 1] != 0)) { AsciiPrint ("0"); } AsciiPrint ("%x", Ip->Addr[Index]); if (Index < 15) { AsciiPrint (":"); } } }
MMU_ENTRY DumpMmuLevel ( IN MMU_LEVEL Level, IN UINT32* Table, IN MMU_ENTRY PreviousEntry ) { UINT32 Index = 0, Count; MMU_ENTRY LastEntry, Entry; ASSERT((Level == Level1) || (Level == Level2)); if (Level == Level1) Count = 4096; else Count = 256; // At Level1, we will get into this function because PreviousEntry is not valid if (!MmuEntryIsValidAddress((MMU_LEVEL)(Level-1),PreviousEntry.Value)) { // Find the first valid address for (; (Index < Count) && (!MmuEntryIsValidAddress(Level,Table[Index])); Index++); LastEntry = MmuEntryCreate(Level,Table,Index); Index++; } else { LastEntry = PreviousEntry; } for (; Index < Count; Index++) { Entry = MmuEntryCreate(Level,Table,Index); if ((Level == Level1) && ((Entry.Value & 0x3) == 1)) { // We have got a Level2 table redirection LastEntry = DumpMmuLevel(Level2,(UINT32*)(Entry.Value & 0xFFFFFC00),LastEntry); } else if (!MmuEntryIsValidAddress(Level,Table[Index])) { if (MmuEntryIsValidAddress(LastEntry.Level,LastEntry.Value)) { AsciiPrint("0x%08X-0x%08X\t%a\n", MmuEntryGetAddress(LastEntry),MmuEntryGetAddress(PreviousEntry)+MmuEntryGetSize(PreviousEntry)-1, MmuEntryGetAttributesName(LastEntry)); } LastEntry = Entry; } else { if (MmuEntryGetAttributes(LastEntry) != MmuEntryGetAttributes(Entry)) { if (MmuEntryIsValidAddress(Level,LastEntry.Value)) { AsciiPrint("0x%08X-0x%08X\t%a\n", MmuEntryGetAddress(LastEntry),MmuEntryGetAddress(PreviousEntry)+MmuEntryGetSize(PreviousEntry)-1, MmuEntryGetAttributesName(LastEntry)); } LastEntry = Entry; } else { ASSERT(LastEntry.Value != 0); } } PreviousEntry = Entry; } if ((Level == Level1) && (LastEntry.Index != Index) && MmuEntryIsValidAddress(Level,LastEntry.Value)) { AsciiPrint("0x%08X-0x%08X\t%a\n", MmuEntryGetAddress(LastEntry),MmuEntryGetAddress(PreviousEntry)+MmuEntryGetSize(PreviousEntry)-1, MmuEntryGetAttributesName(LastEntry)); } return LastEntry; }
/** 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); }
/** This routine is used prevent command output data from scrolling off the end of the screen. The global gPageBreak is used to turn on or off this feature. If the CurrentRow is near the end of the screen pause and print out a prompt If the use hits Q to quit return TRUE else for any other key return FALSE. PrefixNewline is used to figure out if a newline is needed before the prompt string. This depends on the last print done before calling this function. CurrentRow is updated by one on a call or set back to zero if a prompt is needed. @param CurrentRow Used to figure out if its the end of the page and updated @param PrefixNewline Did previous print issue a newline @return TRUE if Q was hit to quit, FALSE in all other cases. **/ BOOLEAN EFIAPI EblAnyKeyToContinueQtoQuit ( IN UINTN *CurrentRow, IN BOOLEAN PrefixNewline ) { EFI_INPUT_KEY InputKey; if (!gPageBreak) { // global disable for this feature return FALSE; } if (*CurrentRow >= (gScreenRows - 2)) { if (PrefixNewline) { AsciiPrint ("\n"); } AsciiPrint ("Any key to continue (Q to quit): "); EblGetCharKey (&InputKey, 0, NULL); AsciiPrint ("\n"); // Time to promt to stop the screen. We have to leave space for the prompt string *CurrentRow = 0; if (InputKey.UnicodeChar == 'Q' || InputKey.UnicodeChar == 'q') { return TRUE; } } else { *CurrentRow += 1; } return FALSE; }
/** Simple arm disassembler via a library Argv[0] - symboltable Argv[1] - Optional qoted format string Argv[2] - Optional flag @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 EblSymbolTable ( IN UINTN Argc, IN CHAR8 **Argv ) { EFI_STATUS Status; EFI_DEBUG_IMAGE_INFO_TABLE_HEADER *DebugImageTableHeader = NULL; EFI_DEBUG_IMAGE_INFO *DebugTable; UINTN Entry; CHAR8 *Format; CHAR8 *Pdb; UINT32 PeCoffSizeOfHeaders; UINT32 ImageBase; BOOLEAN Elf; // Need to add lots of error checking on the passed in string // Default string is for RealView debugger #if (__ARMCC_VERSION < 500000) Format = (Argc > 1) ? Argv[1] : "load /a /ni /np %a &0x%x"; #else Format = (Argc > 1) ? Argv[1] : "add-symbol-file %a 0x%x"; #endif Elf = (Argc > 2) ? FALSE : TRUE; Status = EfiGetSystemConfigurationTable (&gEfiDebugImageInfoTableGuid, (VOID **)&DebugImageTableHeader); if (EFI_ERROR (Status)) { return Status; } DebugTable = DebugImageTableHeader->EfiDebugImageInfoTable; if (DebugTable == NULL) { return EFI_SUCCESS; } for (Entry = 0; Entry < DebugImageTableHeader->TableSize; Entry++, DebugTable++) { if (DebugTable->NormalImage != NULL) { if ((DebugTable->NormalImage->ImageInfoType == EFI_DEBUG_IMAGE_INFO_TYPE_NORMAL) && (DebugTable->NormalImage->LoadedImageProtocolInstance != NULL)) { ImageBase = (UINTN)DebugTable->NormalImage->LoadedImageProtocolInstance->ImageBase; PeCoffSizeOfHeaders = PeCoffGetSizeOfHeaders ((VOID *)(UINTN)ImageBase); Pdb = PeCoffLoaderGetPdbPointer (DebugTable->NormalImage->LoadedImageProtocolInstance->ImageBase); if (Pdb != NULL) { if (Elf) { // ELF and Mach-O images don't include the header so the linked address does not include header ImageBase += PeCoffSizeOfHeaders; } AsciiPrint (Format, Pdb, ImageBase); AsciiPrint ("\n"); } else { } } } } return EFI_SUCCESS; }
/** Print the prompt for the EBL. **/ VOID EblPrompt ( VOID ) { EblSetTextColor (EFI_YELLOW); AsciiPrint ("%a %a",(CHAR8 *)PcdGetPtr (PcdEmbeddedPrompt), EfiGetCwd ()); EblSetTextColor (0); AsciiPrint ("%a", ">"); }
/** Print the boot up banner for the EBL. **/ VOID EblPrintStartupBanner ( VOID ) { AsciiPrint ("Embedded Boot Loader ("); EblSetTextColor (EFI_YELLOW); AsciiPrint ("EBL"); EblSetTextColor (0); AsciiPrint (") prototype. Built at %a on %a\n",__TIME__, __DATE__); AsciiPrint ("THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN 'AS IS' BASIS,\nWITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\n"); AsciiPrint ("Please send feedback to [email protected]\n"); }
/** This function is to display the IPv4 address. @param[in] Ip The pointer to the IPv4 address. **/ VOID HttpBootShowIp4Addr ( IN EFI_IPv4_ADDRESS *Ip ) { UINTN Index; for (Index = 0; Index < 4; Index++) { AsciiPrint ("%d", Ip->Addr[Index]); if (Index < 3) { AsciiPrint ("."); } } }
/** Entry point with Argc, Argv. Put your code here. @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 EblMain ( IN UINTN Argc, IN CHAR8 **Argv ) { UINTN Index; AsciiPrint ("Hello World\n"); for (Index = 0; Index < Argc; Index++) { AsciiPrint ("Argv[%d] = %a\n", Index, Argv[Index]); } return EFI_SUCCESS; }
/** Simple arm disassembler via a library Argv[0] - disasm Argv[1] - Address to start disassembling from ARgv[2] - Number of instructions to disassembly (optional) @param Argc Number of command arguments in Argv @param Argv Array of strings that represent the parsed command line. Argv[0] is the comamnd name @return EFI_SUCCESS **/ EFI_STATUS EblDisassembler ( IN UINTN Argc, IN CHAR8 **Argv ) { UINT8 *Ptr, *CurrentAddress; UINT32 Address; UINT32 Count; CHAR8 Buffer[80]; UINT32 ItBlock; if (Argc < 2) { return EFI_INVALID_PARAMETER; } Address = AsciiStrHexToUintn (Argv[1]); Count = (Argc > 2) ? (UINT32)AsciiStrHexToUintn (Argv[2]) : 20; Ptr = (UINT8 *)(UINTN)Address; ItBlock = 0; do { CurrentAddress = Ptr; DisassembleInstruction (&Ptr, TRUE, TRUE, &ItBlock, Buffer, sizeof (Buffer)); AsciiPrint ("0x%08x: %a\n", CurrentAddress, Buffer); } while (Count-- > 0); return EFI_SUCCESS; }
/** Read from IO space Argv[0] - "ioread"[.#] # is optional width 1, 2, or 4. Default 1 Argv[1] - Hex IO address ior.4 0x3f8 ;Do a 32-bit IO Read from 0x3f8 ior 0x3f8 ;Do a 8-bit IO Read from 0x3f8 @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 EblIoReadCmd ( IN UINTN Argc, IN CHAR8 **Argv ) { UINTN Width; UINTN Port; UINTN Data; if (Argc < 2) { return EFI_INVALID_PARAMETER; } Port = AsciiStrHexToUintn (Argv[1]); Width = WidthFromCommandName (Argv[0], 1); if (Width == 1) { Data = IoRead8 (Port); } else if (Width == 2) { Data = IoRead16 (Port); } else if (Width == 4) { Data = IoRead32 (Port); } else { return EFI_INVALID_PARAMETER; } AsciiPrint ("0x%04x = 0x%x", Port, Data); return EFI_SUCCESS; }
/** Update the screen by decrementing the timeout value. This AsciiPrint has to match the AsciiPrint in EblPauseCmd. @param ElaspedTime Current timeout value remaining **/ VOID EFIAPI EblPauseCallback ( IN UINTN ElapsedTime ) { AsciiPrint ("\b\b\b\b\b\b\b\b\b\b\b\b \b\b%3d seconds", ElapsedTime); }
/** 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; }
/** List out help information on all the commands or print extended information about a specific passed in command. Argv[0] - "help" Argv[1] - Command to display help about @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 EblHelpCmd ( IN UINTN Argc, IN CHAR8 **Argv ) { UINTN Index; CHAR8 *Ptr; UINTN CurrentRow = 0; if (Argc == 1) { // Print all the commands AsciiPrint ("Embedded Boot Loader (EBL) commands (help command for more info):\n"); CurrentRow++; for (Index = 0; Index < mCmdTableNextFreeIndex; Index++) { EblSetTextColor (EFI_YELLOW); AsciiPrint (" %a", mCmdTable[Index]->Name); EblSetTextColor (0); AsciiPrint ("%a\n", mCmdTable[Index]->HelpSummary); // Handle multi line help summaries CurrentRow += CountNewLines (mCmdTable[Index]->HelpSummary); if (EblAnyKeyToContinueQtoQuit (&CurrentRow, FALSE)) { break; } } } else if (Argv[1] != NULL) { // Print specific help for (Index = 0, CurrentRow = 0; Index < mCmdTableNextFreeIndex; Index++) { if (AsciiStriCmp (Argv[1], mCmdTable[Index]->Name) == 0) { Ptr = (mCmdTable[Index]->Help == NULL) ? mCmdTable[Index]->HelpSummary : mCmdTable[Index]->Help; AsciiPrint ("%a%a\n", Argv[1], Ptr); // Handle multi line help summaries CurrentRow += CountNewLines (Ptr); if (EblAnyKeyToContinueQtoQuit (&CurrentRow, FALSE)) { break; } } } } return EFI_SUCCESS; }
/** 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; }
EFI_STATUS EblDumpMmu ( IN UINTN Argc, IN CHAR8 **Argv ) { UINT32 *TTEntry; MMU_ENTRY NoEntry; TTEntry = ArmGetTTBR0BaseAddress(); AsciiPrint ("\nTranslation Table:0x%X\n",TTEntry); AsciiPrint ("Address Range\t\tAttributes\n"); AsciiPrint ("____________________________________________________\n"); NoEntry.Level = (MMU_LEVEL)200; DumpMmuLevel(Level1,TTEntry,NoEntry); return EFI_SUCCESS; }
/** 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); }
/** Pause until a key is pressed and abort the remaining commands on the command line. If no key is pressed continue processing the command line. This command allows the user to stop an operation from happening and return control to the command prompt. Argv[0] - "pause" Argv[1] - timeout value is decimal seconds @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 Timeout expired with no input @return EFI_TIMEOUT Stop processing other commands on the same command line **/ EFI_STATUS EFIAPI EblPauseCmd ( IN UINTN Argc, IN CHAR8 **Argv ) { EFI_STATUS Status; UINTN Delay; EFI_INPUT_KEY Key; Delay = (Argc == 1)? 10 : AsciiStrDecimalToUintn (Argv[1]); AsciiPrint ("Hit any key to break. You have %3d seconds", Delay); Status = EblGetCharKey (&Key, Delay, EblPauseCallback); AsciiPrint ("\n"); // If we timeout then the pause succeeded thus return success // If we get a key return timeout to stop other command on this cmd line return (Status == EFI_SUCCESS) ? EFI_TIMEOUT : EFI_SUCCESS;; }
/** Close a file handle opened by EfiOpen() and free all resources allocated by EfiOpen(). @param Stream Open File Handle @return EFI_INVALID_PARAMETER Stream is not an Open File @return EFI_SUCCESS Steam closed **/ EFI_STATUS EfiClose ( IN EFI_OPEN_FILE *File ) { EFI_STATUS Status; UINT64 TftpBufferSize; if (!FileHandleValid (File)) { return EFI_INVALID_PARAMETER; } //Write the buffer contents to TFTP file. if ((File->Type == EfiOpenTftp) && (File->IsDirty)) { TftpBufferSize = File->Size; Status = EblMtftp ( EFI_PXE_BASE_CODE_TFTP_WRITE_FILE, File->Buffer, TRUE, &TftpBufferSize, NULL, &File->ServerIp, (UINT8 *)File->FileName, NULL, FALSE ); if (EFI_ERROR(Status)) { AsciiPrint("TFTP error during APPLE_NSP_TFTP_WRITE_FILE: %r\n", Status); return Status; } } if ((File->Type == EfiOpenLoadFile) || ((File->Type == EfiOpenTftp) && (File->IsBufferValid == TRUE)) || ((File->Type == EfiOpenFirmwareVolume) && (File->IsBufferValid == TRUE))) { EblFreePool(File->Buffer); } EblFreePool (File->DevicePath); EblFreePool (File->DeviceName); EblFreePool (File->FsFileInfo); EblFreePool (File->FsInfo); if (File->FsFileHandle != NULL) { File->FsFileHandle->Close (File->FsFileHandle); } // Need to free File and it's Guard structures EblFreePool (BASE_CR (File, EFI_OPEN_FILE_GUARD, File)); return EFI_SUCCESS; }
/** Parse a command line and execute the commands. The ; separator allows multiple commands for each command line. Stop processing if one of the commands returns an error. @param CmdLine Command Line to process. @param MaxCmdLineSize MaxSize of the Command line @return EFI status of the Command **/ EFI_STATUS ProcessCmdLine ( IN CHAR8 *CmdLine, IN UINTN MaxCmdLineSize ) { EFI_STATUS Status; EBL_COMMAND_TABLE *Cmd; CHAR8 *Ptr; UINTN Argc; CHAR8 *Argv[MAX_ARGS]; // Parse the command line. The loop processes commands separated by ; for (Ptr = CmdLine, Status = EFI_SUCCESS; Ptr != NULL;) { Ptr = ParseArguments (Ptr, &Argc, Argv); if (Argc != 0) { Cmd = EblGetCommand (Argv[0]); if (Cmd != NULL) { // Execute the Command! Status = Cmd->Command (Argc, Argv); if (Status == EFI_ABORTED) { // exit command so lets exit break; } else if (Status == EFI_TIMEOUT) { // pause command got input so don't process any more cmd on this cmd line break; } else if (EFI_ERROR (Status)) { AsciiPrint ("%a returned %r error\n", Cmd->Name, Status); // if any command fails stop processing CmdLine break; } } else { AsciiPrint ("The command '%a' is not supported.\n", Argv[0]); } } } return Status; }
/** Collect the keyboard input for a cmd line. Carriage Return, New Line, or ESC terminates the command line. You can edit the command line via left arrow, delete and backspace and they all back up and erase the command line. No edit of command line is possible without deletion at this time! The up arrow and down arrow fill Cmd with information from the history buffer. @param Cmd Command line to return @param CmdMaxSize Maximum size of Cmd @return The Status of EblGetCharKey() **/ EFI_STATUS GetCmd ( IN OUT CHAR8 *Cmd, IN UINTN CmdMaxSize ) { EFI_STATUS Status; UINTN Index; UINTN Index2; CHAR8 Char; CHAR8 *History; EFI_INPUT_KEY Key; for (Index = 0; Index < CmdMaxSize - 1;) { Status = EblGetCharKey (&Key, 0, NULL); if (EFI_ERROR (Status)) { Cmd[Index] = '\0'; AsciiPrint ("\n"); return Status; } Char = (CHAR8)Key.UnicodeChar; if ((Char == '\n') || (Char == '\r') || (Char == 0x7f)) { Cmd[Index] = '\0'; if (FixedPcdGetBool(PcdEmbeddedShellCharacterEcho) == TRUE) { AsciiPrint ("\n\r"); } return EFI_SUCCESS; } else if ((Char == '\b') || (Key.ScanCode == SCAN_LEFT) || (Key.ScanCode == SCAN_DELETE)){ if (Index != 0) { Index--; // // Update the display // AsciiPrint ("\b \b"); } } else if ((Key.ScanCode == SCAN_UP) || Key.ScanCode == SCAN_DOWN) { History = GetCmdHistory (Key.ScanCode); // // Clear display line // for (Index2 = 0; Index2 < Index; Index2++) { AsciiPrint ("\b \b"); } AsciiPrint (History); Index = AsciiStrLen (History); AsciiStrnCpyS (Cmd, CmdMaxSize, History, CmdMaxSize); } else { Cmd[Index++] = Char; if (FixedPcdGetBool(PcdEmbeddedShellCharacterEcho) == TRUE) { AsciiPrint ("%c", Char); } } } return EFI_SUCCESS; }
EFI_STATUS EblDevicePaths ( IN UINTN Argc, IN CHAR8 **Argv ) { EFI_STATUS Status; UINTN HandleCount; EFI_HANDLE *HandleBuffer; UINTN Index; CHAR16* String; EFI_DEVICE_PATH_PROTOCOL* DevicePathProtocol; EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol; BdsConnectAllDrivers(); Status = gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol); if (EFI_ERROR (Status)) { AsciiPrint ("Did not find the DevicePathToTextProtocol.\n"); return EFI_SUCCESS; } Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiDevicePathProtocolGuid, NULL, &HandleCount, &HandleBuffer); if (EFI_ERROR (Status)) { AsciiPrint ("No device path found\n"); return EFI_SUCCESS; } for (Index = 0; Index < HandleCount; Index++) { Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **)&DevicePathProtocol); String = DevicePathToTextProtocol->ConvertDevicePathToText(DevicePathProtocol,TRUE,TRUE); Print (L"[0x%X] %s\n",(UINTN)HandleBuffer[Index], String); } return EFI_SUCCESS; }
/** Display the string of the boot item. If the length of the boot item string beyond 70 Char, just display 70 Char. @param[in] Str The pointer to the string. @param[in] Len The length of the string. **/ VOID PxeBcDisplayBootItem ( IN UINT8 *Str, IN UINT8 Len ) { UINT8 Tmp; // // Cut off the chars behind 70th. // Len = (UINT8) MIN (PXEBC_DISPLAY_MAX_LINE, Len); Tmp = Str[Len]; Str[Len] = 0; AsciiPrint ("%a \n", Str); // // Restore the original 70th char. // Str[Len] = Tmp; }
/** 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); }
EFI_STATUS EFIAPI EblSetCmd ( IN UINTN Argc, IN CHAR8 **Argv ) { EFI_STATUS Status = EFI_INVALID_PARAMETER; CHAR8* AsciiVariableSetting = NULL; CHAR8* AsciiVariableName; CHAR8* AsciiValue; UINT32 AsciiValueLength; CHAR16* VariableName; UINT32 Index; UINT32 EscapedQuotes = 0; BOOLEAN Volatile = FALSE; if (Argc == 1) { AsciiPrint("Variable name is missing.\n"); return Status; } for (Index = 1; Index < Argc; Index++) { if (AsciiStrCmp(Argv[Index],"-v") == 0) { Volatile = 0; } else if (Argv[Index][0] == '-') { AsciiPrint("Warning: '%a' not recognized.\n",Argv[Index]); } else { AsciiVariableSetting = Argv[Index]; } } if (AsciiVariableSetting == NULL) { AsciiPrint("Variable name is missing.\n"); return Status; } // Check if it is a valid variable setting AsciiValue = AsciiStrStr (AsciiVariableSetting,"="); if (AsciiValue == NULL) { // // There is no value. It means this variable will be deleted // // Convert VariableName into Unicode VariableName = AllocatePool((AsciiStrLen (AsciiVariableSetting) + 1) * sizeof (CHAR16)); AsciiStrToUnicodeStr (AsciiVariableSetting,VariableName); Status = gRT->SetVariable ( VariableName, &gEfiGlobalVariableGuid, ( !Volatile ? EFI_VARIABLE_NON_VOLATILE : 0) | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, 0, NULL ); if (!EFI_ERROR(Status)) { AsciiPrint("Variable '%s' deleted\n",VariableName); } else { AsciiPrint("Variable setting is incorrect. It should be VariableName=Value\n"); } return Status; } AsciiValue[0] = '\0'; AsciiVariableName = AsciiVariableSetting; AsciiValue++; // Clean AsciiValue from quote if (AsciiValue[0] == '"') { AsciiValue++; } AsciiValueLength = AsciiStrLen (AsciiValue); if ((AsciiValue[AsciiValueLength-2] != '\\') && (AsciiValue[AsciiValueLength-1] == '"')) { AsciiValue[AsciiValueLength-1] = '\0'; } // Clean AsciiValue from escaped quotes for (Index = 0; Index < AsciiValueLength; Index++) { if ((Index > 0) && (AsciiValue[Index-1] == '\\') && (AsciiValue[Index] == '"')) { EscapedQuotes++; } AsciiValue[Index-EscapedQuotes] = AsciiValue[Index]; } // Fill the end of the value with '\0' for (Index = 0; Index < EscapedQuotes; Index++) { AsciiValue[AsciiValueLength-1-Index] = '\0'; } // Convert VariableName into Unicode VariableName = AllocatePool((AsciiStrLen (AsciiVariableName) + 1) * sizeof (CHAR16)); AsciiStrToUnicodeStr (AsciiVariableName,VariableName); Status = gRT->SetVariable ( VariableName, &gEfiGlobalVariableGuid, ( !Volatile ? EFI_VARIABLE_NON_VOLATILE : 0) | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, AsciiStrLen (AsciiValue)+1, AsciiValue ); if (!EFI_ERROR(Status)) { AsciiPrint("'%a'='%a'\n",AsciiVariableName,AsciiValue); } return Status; }
EFI_STATUS EFIAPI EblGetCmd ( IN UINTN Argc, IN CHAR8 **Argv ) { EFI_STATUS Status = EFI_INVALID_PARAMETER; UINTN Size; VOID* Value; CHAR8* AsciiVariableName = NULL; CHAR16* VariableName; UINT32 Index; if (Argc == 1) { AsciiPrint("Variable name is missing.\n"); return Status; } for (Index = 1; Index < Argc; Index++) { if (Argv[Index][0] == '-') { AsciiPrint("Warning: '%a' not recognized.\n",Argv[Index]); } else { AsciiVariableName = Argv[Index]; } } if (AsciiVariableName == NULL) { AsciiPrint("Variable name is missing.\n"); return Status; } else { VariableName = AllocatePool((AsciiStrLen (AsciiVariableName) + 1) * sizeof (CHAR16)); AsciiStrToUnicodeStr (AsciiVariableName,VariableName); } // Try to get the variable size. Value = NULL; Size = 0; Status = gRT->GetVariable (VariableName, &gEfiGlobalVariableGuid, NULL, &Size, Value); if (Status == EFI_NOT_FOUND) { AsciiPrint("Variable name '%s' not found.\n",VariableName); } else if (Status == EFI_BUFFER_TOO_SMALL) { // Get the environment variable value Value = AllocatePool (Size); if (Value == NULL) { return EFI_OUT_OF_RESOURCES; } Status = gRT->GetVariable ((CHAR16 *)VariableName, &gEfiGlobalVariableGuid, NULL, &Size, Value); if (EFI_ERROR (Status)) { AsciiPrint("Error: '%r'\n",Status); } else { AsciiPrint("%a=%a\n",AsciiVariableName,Value); } FreePool(Value); } else { AsciiPrint("Error: '%r'\n",Status); } FreePool(VariableName); return Status; }
/** Attempt to download the boot file through HTTP message exchange. @param[in] Private The pointer to the driver's private data. @param[in, out] BufferSize On input the size of Buffer in bytes. On output with a return code of EFI_SUCCESS, the amount of data transferred to Buffer. On output with a return code of EFI_BUFFER_TOO_SMALL, the size of Buffer required to retrieve the requested file. @param[in] Buffer The memory buffer to transfer the file to. If Buffer is NULL, then the size of the requested file is returned in BufferSize. @param[out] ImageType The image type of the downloaded file. @retval EFI_SUCCESS Boot file was loaded successfully. @retval EFI_INVALID_PARAMETER Private is NULL, or ImageType is NULL, or BufferSize is NULL. @retval EFI_INVALID_PARAMETER *BufferSize is not zero, and Buffer is NULL. @retval EFI_NOT_STARTED The driver is in stopped state. @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the boot file. BufferSize has been updated with the size needed to complete the request. @retval EFI_DEVICE_ERROR An unexpected network error occurred. @retval Others Other errors as indicated. **/ EFI_STATUS HttpBootLoadFile ( IN HTTP_BOOT_PRIVATE_DATA *Private, IN OUT UINTN *BufferSize, IN VOID *Buffer, OPTIONAL OUT HTTP_BOOT_IMAGE_TYPE *ImageType ) { EFI_STATUS Status; if (Private == NULL || ImageType == NULL || BufferSize == NULL ) { return EFI_INVALID_PARAMETER; } if (*BufferSize != 0 && Buffer == NULL) { return EFI_INVALID_PARAMETER; } if (!Private->Started) { return EFI_NOT_STARTED; } Status = HttpBootInstallCallback (Private); if (EFI_ERROR(Status)) { goto ON_EXIT; } if (Private->BootFileUri == NULL) { // // Parse the cached offer to get the boot file URL first. // Status = HttpBootDiscoverBootInfo (Private); if (EFI_ERROR (Status)) { AsciiPrint ("\n Error: Could not retrieve NBP file size from HTTP server.\n"); goto ON_EXIT; } } if (!Private->HttpCreated) { // // Create HTTP child. // Status = HttpBootCreateHttpIo (Private); if (EFI_ERROR (Status)) { goto ON_EXIT; } } if (Private->BootFileSize == 0) { // // Discover the information about the bootfile if we haven't. // // // Try to use HTTP HEAD method. // Status = HttpBootGetBootFile ( Private, TRUE, &Private->BootFileSize, NULL, &Private->ImageType ); if (EFI_ERROR (Status) && Status != EFI_BUFFER_TOO_SMALL) { // // Failed to get file size by HEAD method, may be trunked encoding, try HTTP GET method. // ASSERT (Private->BootFileSize == 0); Status = HttpBootGetBootFile ( Private, FALSE, &Private->BootFileSize, NULL, &Private->ImageType ); if (EFI_ERROR (Status) && Status != EFI_BUFFER_TOO_SMALL) { AsciiPrint ("\n Error: Could not retrieve NBP file size from HTTP server.\n"); goto ON_EXIT; } } } if (*BufferSize < Private->BootFileSize) { *BufferSize = Private->BootFileSize; *ImageType = Private->ImageType; Status = EFI_BUFFER_TOO_SMALL; goto ON_EXIT; } // // Load the boot file into Buffer // Status = HttpBootGetBootFile ( Private, FALSE, BufferSize, Buffer, ImageType ); ON_EXIT: HttpBootUninstallCallback (Private); if (EFI_ERROR (Status)) { if (Status == EFI_ACCESS_DENIED) { AsciiPrint ("\n Error: Could not establish connection with HTTP server.\n"); } else if (Status == EFI_BUFFER_TOO_SMALL && Buffer != NULL) { AsciiPrint ("\n Error: Buffer size is smaller than the requested file.\n"); } else if (Status == EFI_OUT_OF_RESOURCES) { AsciiPrint ("\n Error: Could not allocate I/O buffers.\n"); } else if (Status == EFI_DEVICE_ERROR) { AsciiPrint ("\n Error: Network device error.\n"); } else if (Status == EFI_TIMEOUT) { AsciiPrint ("\n Error: Server response timeout.\n"); } else if (Status == EFI_ABORTED) { AsciiPrint ("\n Error: Remote boot cancelled.\n"); } else if (Status != EFI_BUFFER_TOO_SMALL) { AsciiPrint ("\n Error: Unexpected network error.\n"); } } return Status; }
EFI_STATUS BootMenuMain ( VOID ) { LIST_ENTRY BootOptionsList; UINTN OptionCount; UINTN BootOptionCount; EFI_STATUS Status; LIST_ENTRY* Entry; BDS_LOAD_OPTION* BootOption; UINTN BootOptionSelected; UINTN Index; UINTN BootMainEntryCount; BOOLEAN IsUnicode; BootOption = NULL; BootMainEntryCount = sizeof(BootMainEntries) / sizeof(struct BOOT_MAIN_ENTRY); while (TRUE) { // Get Boot#### list BootOptionList (&BootOptionsList); OptionCount = 1; // Display the Boot options for (Entry = GetFirstNode (&BootOptionsList); !IsNull (&BootOptionsList,Entry); Entry = GetNextNode (&BootOptionsList,Entry) ) { BootOption = LOAD_OPTION_FROM_LINK(Entry); Print(L"[%d] %s\n", OptionCount, BootOption->Description); DEBUG_CODE_BEGIN(); CHAR16* DevicePathTxt; EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol; ARM_BDS_LOADER_OPTIONAL_DATA* OptionalData; UINTN CmdLineSize; ARM_BDS_LOADER_TYPE LoaderType; Status = gBS->LocateProtocol (&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol); if (EFI_ERROR(Status)) { // You must provide an implementation of DevicePathToTextProtocol in your firmware (eg: DevicePathDxe) DEBUG((EFI_D_ERROR,"Error: Bds requires DevicePathToTextProtocol\n")); return Status; } DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText (BootOption->FilePathList, TRUE, TRUE); Print(L"\t- %s\n",DevicePathTxt); // If it is a supported BootEntry then print its details if (IS_ARM_BDS_BOOTENTRY (BootOption)) { OptionalData = BootOption->OptionalData; LoaderType = (ARM_BDS_LOADER_TYPE)ReadUnaligned32 ((CONST UINT32*)&OptionalData->Header.LoaderType); if ((LoaderType == BDS_LOADER_KERNEL_LINUX_ATAG) || (LoaderType == BDS_LOADER_KERNEL_LINUX_FDT)) { if (ReadUnaligned16 (&OptionalData->Arguments.LinuxArguments.InitrdSize) > 0) { CmdLineSize = ReadUnaligned16 (&OptionalData->Arguments.LinuxArguments.CmdLineSize); DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText ( GetAlignedDevicePath ((EFI_DEVICE_PATH*)((UINTN)(&OptionalData->Arguments.LinuxArguments + 1) + CmdLineSize)), TRUE, TRUE); Print(L"\t- Initrd: %s\n", DevicePathTxt); } if (ReadUnaligned16 (&OptionalData->Arguments.LinuxArguments.CmdLineSize) > 0) { Print(L"\t- Arguments: %a\n", (&OptionalData->Arguments.LinuxArguments + 1)); } } switch (LoaderType) { case BDS_LOADER_EFI_APPLICATION: Print(L"\t- LoaderType: EFI Application\n"); break; case BDS_LOADER_KERNEL_LINUX_ATAG: Print(L"\t- LoaderType: Linux kernel with ATAG support\n"); break; case BDS_LOADER_KERNEL_LINUX_FDT: Print(L"\t- LoaderType: Linux kernel with FDT support\n"); break; default: Print(L"\t- LoaderType: Not recognized (%d)\n", LoaderType); } } else if (BootOption->OptionalData != NULL) { if (IsPrintableString (BootOption->OptionalData, &IsUnicode)) { if (IsUnicode) { Print (L"\t- Arguments: %s\n", BootOption->OptionalData); } else { AsciiPrint ("\t- Arguments: %a\n", BootOption->OptionalData); } } } FreePool(DevicePathTxt); DEBUG_CODE_END(); OptionCount++; } BootOptionCount = OptionCount-1; // Display the hardcoded Boot entries for (Index = 0; Index < BootMainEntryCount; Index++) { Print(L"[%d] %s\n",OptionCount,BootMainEntries[Index]); OptionCount++; } // Request the boot entry from the user BootOptionSelected = 0; while (BootOptionSelected == 0) { Print(L"Start: "); Status = GetHIInputInteger (&BootOptionSelected); if (EFI_ERROR(Status) || (BootOptionSelected == 0) || (BootOptionSelected > OptionCount)) { Print(L"Invalid input (max %d)\n",(OptionCount-1)); BootOptionSelected = 0; } } // Start the selected entry if (BootOptionSelected > BootOptionCount) { // Start the hardcoded entry Status = BootMainEntries[BootOptionSelected - BootOptionCount - 1].Callback (&BootOptionsList); } else { // Find the selected entry from the Boot#### list Index = 1; for (Entry = GetFirstNode (&BootOptionsList); !IsNull (&BootOptionsList,Entry); Entry = GetNextNode (&BootOptionsList,Entry) ) { if (Index == BootOptionSelected) { BootOption = LOAD_OPTION_FROM_LINK(Entry); break; } Index++; } Status = BootOptionStart (BootOption); } } // Should never go here }
/** Open a device named by PathName. The PathName includes a device name and path separated by a :. See file header for more details on the PathName syntax. There is no checking to prevent a file from being opened more than one type. SectionType is only used to open an FV. Each file in an FV contains multiple sections and only the SectionType section is opened. For any file that is opened with EfiOpen() must be closed with EfiClose(). @param PathName Path to parse to open @param OpenMode Same as EFI_FILE.Open() @param SectionType Section in FV to open. @return NULL Open failed @return Valid EFI_OPEN_FILE handle **/ EFI_OPEN_FILE * EfiOpen ( IN CHAR8 *PathName, IN CONST UINT64 OpenMode, IN CONST EFI_SECTION_TYPE SectionType ) { EFI_STATUS Status; EFI_OPEN_FILE *File; EFI_OPEN_FILE FileData; UINTN StrLen; UINTN FileStart; UINTN DevNumber = 0; EFI_OPEN_FILE_GUARD *GuardFile; BOOLEAN VolumeNameMatch; EFI_DEVICE_PATH_PROTOCOL *DevicePath; UINTN Size; EFI_IP_ADDRESS Ip; CHAR8 *CwdPlusPathName; UINTN Index; EFI_SECTION_TYPE ModifiedSectionType; EblUpdateDeviceLists (); File = &FileData; ZeroMem (File, sizeof (EFI_OPEN_FILE)); StrLen = AsciiStrSize (PathName); if (StrLen <= 1) { // Smallest valid path is 1 char and a null return NULL; } for (FileStart = 0; FileStart < StrLen; FileStart++) { if (PathName[FileStart] == ':') { FileStart++; break; } } // // Matching volume name has precedence over handle based names // VolumeNameMatch = EblMatchVolumeName (PathName, FileStart, &DevNumber); if (!VolumeNameMatch) { if (FileStart == StrLen) { // No Volume name or device name, so try Current Working Directory if (gCwd == NULL) { // No CWD return NULL; } // We could add a current working directory concept CwdPlusPathName = AllocatePool (AsciiStrSize (gCwd) + AsciiStrSize (PathName)); if (CwdPlusPathName == NULL) { return NULL; } if ((PathName[0] == '/') || (PathName[0] == '\\')) { // PathName starts in / so this means we go to the root of the device in the CWD. CwdPlusPathName[0] = '\0'; for (FileStart = 0; gCwd[FileStart] != '\0'; FileStart++) { CwdPlusPathName[FileStart] = gCwd[FileStart]; if (gCwd[FileStart] == ':') { FileStart++; CwdPlusPathName[FileStart] = '\0'; break; } } } else { AsciiStrCpy (CwdPlusPathName, gCwd); StrLen = AsciiStrLen (gCwd); if ((*PathName != '/') && (*PathName != '\\') && (gCwd[StrLen-1] != '/') && (gCwd[StrLen-1] != '\\')) { AsciiStrCat (CwdPlusPathName, "\\"); } } AsciiStrCat (CwdPlusPathName, PathName); if (AsciiStrStr (CwdPlusPathName, ":") == NULL) { // Extra error check to make sure we don't recurse and blow stack return NULL; } File = EfiOpen (CwdPlusPathName, OpenMode, SectionType); FreePool (CwdPlusPathName); return File; } DevNumber = EblConvertDevStringToNumber ((CHAR8 *)PathName); } File->DeviceName = AllocatePool (StrLen); AsciiStrCpy (File->DeviceName, PathName); File->DeviceName[FileStart - 1] = '\0'; File->FileName = &File->DeviceName[FileStart]; if (File->FileName[0] == '\0') { // if it is just a file name use / as root File->FileName = "\\"; } // // Use best match algorithm on the dev names so we only need to look at the // first few charters to match the full device name. Short name forms are // legal from the caller. // Status = EFI_SUCCESS; if (*PathName == 'f' || *PathName == 'F' || VolumeNameMatch) { if (PathName[1] == 's' || PathName[1] == 'S' || VolumeNameMatch) { if (DevNumber >= mFsCount) { goto ErrorExit; } File->Type = EfiOpenFileSystem; File->EfiHandle = mFs[DevNumber]; Status = EblFileDevicePath (File, &PathName[FileStart], OpenMode); } else if (PathName[1] == 'v' || PathName[1] == 'V') { if (DevNumber >= mFvCount) { goto ErrorExit; } File->Type = EfiOpenFirmwareVolume; File->EfiHandle = mFv[DevNumber]; if ((PathName[FileStart] == '/') || (PathName[FileStart] == '\\')) { // Skip leading / as its not really needed for the FV since no directories are supported FileStart++; } // Check for 2nd : ModifiedSectionType = SectionType; for (Index = FileStart; PathName[Index] != '\0'; Index++) { if (PathName[Index] == ':') { // Support fv0:\DxeCore:0x10 // This means open the PE32 Section of the file ModifiedSectionType = (EFI_SECTION_TYPE)AsciiStrHexToUintn (&PathName[Index + 1]); PathName[Index] = '\0'; } } File->FvSectionType = ModifiedSectionType; Status = EblFvFileDevicePath (File, &PathName[FileStart], ModifiedSectionType); } } else if ((*PathName == 'A') || (*PathName == 'a')) { // Handle a:0x10000000:0x1234 address form a:ADDRESS:SIZE File->Type = EfiOpenMemoryBuffer; // 1st colon is at PathName[FileStart - 1] File->Buffer = (VOID *)AsciiStrHexToUintn (&PathName[FileStart]); // Find 2nd colon while ((PathName[FileStart] != ':') && (PathName[FileStart] != '\0')) { FileStart++; } // If we ran out of string, there's no extra data if (PathName[FileStart] == '\0') { File->Size = 0; } else { File->Size = AsciiStrHexToUintn (&PathName[FileStart + 1]); } // if there's no number after the second colon, default // the end of memory if (File->Size == 0) { File->Size = (UINTN)(0 - (UINTN)File->Buffer); } File->MaxPosition = File->Size; File->BaseOffset = (UINTN)File->Buffer; } else if (*PathName== 'l' || *PathName == 'L') { if (DevNumber >= mLoadFileCount) { goto ErrorExit; } File->Type = EfiOpenLoadFile; File->EfiHandle = mLoadFile[DevNumber]; Status = gBS->HandleProtocol (File->EfiHandle, &gEfiLoadFileProtocolGuid, (VOID **)&File->LoadFile); if (EFI_ERROR (Status)) { goto ErrorExit; } Status = gBS->HandleProtocol (File->EfiHandle, &gEfiDevicePathProtocolGuid, (VOID **)&DevicePath); if (EFI_ERROR (Status)) { goto ErrorExit; } File->DevicePath = DuplicateDevicePath (DevicePath); } else if (*PathName == 'b' || *PathName == 'B') { // Handle b#:0x10000000:0x1234 address form b#:ADDRESS:SIZE if (DevNumber >= mBlkIoCount) { goto ErrorExit; } File->Type = EfiOpenBlockIo; File->EfiHandle = mBlkIo[DevNumber]; EblFileDevicePath (File, "", OpenMode); // 1st colon is at PathName[FileStart - 1] File->DiskOffset = AsciiStrHexToUintn (&PathName[FileStart]); // Find 2nd colon while ((PathName[FileStart] != ':') && (PathName[FileStart] != '\0')) { FileStart++; } // If we ran out of string, there's no extra data if (PathName[FileStart] == '\0') { Size = 0; } else { Size = AsciiStrHexToUintn (&PathName[FileStart + 1]); } // if a zero size is passed in (or the size is left out entirely), // go to the end of the device. if (Size == 0) { File->Size = File->Size - File->DiskOffset; } else { File->Size = Size; } File->MaxPosition = File->Size; File->BaseOffset = File->DiskOffset; } else if ((*PathName) >= '0' && (*PathName <= '9')) { // Get current IP address Status = EblGetCurrentIpAddress (&Ip); if (EFI_ERROR(Status)) { AsciiPrint("Device IP Address is not configured.\n"); goto ErrorExit; } // Parse X.X.X.X:Filename, only support IPv4 TFTP for now... File->Type = EfiOpenTftp; File->IsDirty = FALSE; File->IsBufferValid = FALSE; Status = ConvertIpStringToEfiIp (PathName, &File->ServerIp); } if (EFI_ERROR (Status)) { goto ErrorExit; } GuardFile = (EFI_OPEN_FILE_GUARD *)AllocateZeroPool (sizeof (EFI_OPEN_FILE_GUARD)); if (GuardFile == NULL) { goto ErrorExit; } GuardFile->Header = EFI_OPEN_FILE_GUARD_HEADER; CopyMem (&(GuardFile->File), &FileData, sizeof (EFI_OPEN_FILE)); GuardFile->Footer = EFI_OPEN_FILE_GUARD_FOOTER; return &(GuardFile->File); ErrorExit: FreePool (File->DeviceName); return NULL; }
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; }