/** Add a command to the mCmdTable. If there is no free space in the command table ASSERT. The mCmdTable is maintained in alphabetical order and the new entry is inserted into its sorted position. @param Entry Command Entry to add to the CmdTable **/ VOID EFIAPI EblAddCommand ( IN const EBL_COMMAND_TABLE *Entry ) { UINTN Count; if (mCmdTableNextFreeIndex == EBL_MAX_COMMAND_COUNT) { // // Ran out of space to store commands. Increase EBL_MAX_COMMAND_COUNT // ASSERT (FALSE); return; } // // Add command and Insertion sort array in the process // mCmdTable[mCmdTableNextFreeIndex] = (EBL_COMMAND_TABLE *)Entry; if (mCmdTableNextFreeIndex != 0) { for (Count = mCmdTableNextFreeIndex; Count > 0; Count--) { if (AsciiStriCmp (mCmdTable[Count - 1]->Name, Entry->Name) <= 0) { break; } mCmdTable[Count] = mCmdTable[Count - 1]; } mCmdTable[Count] = (EBL_COMMAND_TABLE *)Entry; } mCmdTableNextFreeIndex++; }
/** 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; }
/** Check whether the HTTP message is using the "chunked" transfer-coding. @param[in] HeaderCount Number of HTTP header structures in Headers. @param[in] Headers Array containing list of HTTP headers. @return The message is "chunked" transfer-coding (TRUE) or not (FALSE). **/ BOOLEAN HttpIoIsChunked ( IN UINTN HeaderCount, IN EFI_HTTP_HEADER *Headers ) { EFI_HTTP_HEADER *Header; Header = HttpIoFindHeader (HeaderCount, Headers, "Transfer-Encoding"); if (Header == NULL) { return FALSE; } if (AsciiStriCmp (Header->FieldValue, "identity") != 0) { return TRUE; } return FALSE; }
/** Return the best matching command for the passed in command name. The match does not have to be exact, it just needs to be unique. This enables commands to be shortened to the smallest set of starting characters that is unique. @param CommandName Name of command to search for @return NULL CommandName did not match or was not unique Other Pointer to EBL_COMMAND_TABLE entry for CommandName **/ EBL_COMMAND_TABLE * EblGetCommand ( IN CHAR8 *CommandName ) { UINTN Index; UINTN BestMatchCount; UINTN Length; EBL_COMMAND_TABLE *Match; CHAR8 *Str; Length = AsciiStrLen (CommandName); Str = AsciiStrStr (CommandName, "."); if (Str != NULL) { // If the command includes a trailing . command extension skip it for the match. // Example: hexdump.4 Length = (UINTN)(Str - CommandName); } for (Index = 0, BestMatchCount = 0, Match = NULL; Index < mCmdTableNextFreeIndex; Index++) { if (AsciiStriCmp (mCmdTable[Index]->Name, CommandName) == 0) { // match a command exactly return mCmdTable[Index]; } if (AsciiStrniCmp (CommandName, mCmdTable[Index]->Name, Length) == 0) { // partial match, so keep looking to make sure there is only one partial match BestMatchCount++; Match = mCmdTable[Index]; } } if (BestMatchCount == 1) { return Match; } // // We had no matches or too many matches // return NULL; }
/** Find a specified header field according to the field name. @param[in] HeaderCount Number of HTTP header structures in Headers list. @param[in] Headers Array containing list of HTTP headers. @param[in] FieldName Null terminated string which describes a field name. @return Pointer to the found header or NULL. **/ EFI_HTTP_HEADER * HttpIoFindHeader ( IN UINTN HeaderCount, IN EFI_HTTP_HEADER *Headers, IN CHAR8 *FieldName ) { UINTN Index; if (HeaderCount == 0 || Headers == NULL || FieldName == NULL) { return NULL; } for (Index = 0; Index < HeaderCount; Index++){ // // Field names are case-insensitive (RFC 2616). // if (AsciiStriCmp (Headers[Index].FieldName, FieldName) == 0) { return &Headers[Index]; } } return NULL; }
/** Internal work function to fill in EFI_OPEN_FILE information for the FV @param File Open file handle @param FileName Name of file after device stripped off **/ EFI_STATUS EblFvFileDevicePath ( IN OUT EFI_OPEN_FILE *File, IN CHAR8 *FileName, IN CONST UINT64 OpenMode ) { EFI_STATUS Status; EFI_STATUS GetNextFileStatus; MEDIA_FW_VOL_FILEPATH_DEVICE_PATH DevicePathNode; EFI_DEVICE_PATH_PROTOCOL *DevicePath; UINTN Key; UINT32 AuthenticationStatus; CHAR8 AsciiSection[MAX_PATHNAME]; VOID *Section; UINTN SectionSize; EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb; EFI_LBA Lba; UINTN BlockSize; UINTN NumberOfBlocks; EFI_FIRMWARE_VOLUME_HEADER *FvHeader = NULL; UINTN Index; Status = gBS->HandleProtocol (File->EfiHandle, &gEfiFirmwareVolume2ProtocolGuid, (VOID **)&File->Fv); if (EFI_ERROR (Status)) { return Status; } // Get FVB Info about the handle Status = gBS->HandleProtocol (File->EfiHandle, &gEfiFirmwareVolumeBlockProtocolGuid, (VOID **)&Fvb); if (!EFI_ERROR (Status)) { Status = Fvb->GetPhysicalAddress (Fvb, &File->FvStart); if (!EFI_ERROR (Status)) { FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)File->FvStart; File->FvHeaderSize = sizeof (EFI_FIRMWARE_VOLUME_HEADER); for (Index = 0; FvHeader->BlockMap[Index].Length !=0; Index++) { File->FvHeaderSize += sizeof (EFI_FV_BLOCK_MAP_ENTRY); } for (Lba = 0, File->FvSize = 0, NumberOfBlocks = 0; ; File->FvSize += (BlockSize * NumberOfBlocks), Lba += NumberOfBlocks) { Status = Fvb->GetBlockSize (Fvb, Lba, &BlockSize, &NumberOfBlocks); if (EFI_ERROR (Status)) { break; } } } } DevicePath = DevicePathFromHandle (File->EfiHandle); if (*FileName == '\0') { File->DevicePath = DuplicateDevicePath (DevicePath); File->Size = File->FvSize; File->MaxPosition = File->Size; } else { Key = 0; do { File->FvType = EFI_FV_FILETYPE_ALL; GetNextFileStatus = File->Fv->GetNextFile ( File->Fv, &Key, &File->FvType, &File->FvNameGuid, &File->FvAttributes, &File->Size ); if (!EFI_ERROR (GetNextFileStatus)) { // Compare GUID first Status = CompareGuidToString (&File->FvNameGuid, FileName); if (!EFI_ERROR(Status)) { break; } Section = NULL; Status = File->Fv->ReadSection ( File->Fv, &File->FvNameGuid, EFI_SECTION_USER_INTERFACE, 0, &Section, &SectionSize, &AuthenticationStatus ); if (!EFI_ERROR (Status)) { UnicodeStrToAsciiStr (Section, AsciiSection); if (AsciiStriCmp (FileName, AsciiSection) == 0) { FreePool (Section); break; } FreePool (Section); } } } while (!EFI_ERROR (GetNextFileStatus)); if (EFI_ERROR (GetNextFileStatus)) { return GetNextFileStatus; } if (OpenMode != EFI_SECTION_ALL) { // Calculate the size of the section we are targeting Section = NULL; File->Size = 0; Status = File->Fv->ReadSection ( File->Fv, &File->FvNameGuid, (EFI_SECTION_TYPE)OpenMode, 0, &Section, &File->Size, &AuthenticationStatus ); if (EFI_ERROR (Status)) { return Status; } } File->MaxPosition = File->Size; EfiInitializeFwVolDevicepathNode (&DevicePathNode, &File->FvNameGuid); File->DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&DevicePathNode); } // FVB not required if FV was soft loaded... return EFI_SUCCESS; }
/** This function returns the image type according to server replied HTTP message and also the image's URI info. @param[in] Uri The pointer to the image's URI string. @param[in] UriParser URI Parse result returned by NetHttpParseUrl(). @param[in] HeaderCount Number of HTTP header structures in Headers list. @param[in] Headers Array containing list of HTTP headers. @param[out] ImageType The image type of the downloaded file. @retval EFI_SUCCESS The image type is returned in ImageType. @retval EFI_INVALID_PARAMETER ImageType, Uri or UriParser is NULL. @retval EFI_INVALID_PARAMETER HeaderCount is not zero, and Headers is NULL. @retval EFI_NOT_FOUND Failed to identify the image type. @retval Others Unexpect error happened. **/ EFI_STATUS HttpBootCheckImageType ( IN CHAR8 *Uri, IN VOID *UriParser, IN UINTN HeaderCount, IN EFI_HTTP_HEADER *Headers, OUT HTTP_BOOT_IMAGE_TYPE *ImageType ) { EFI_STATUS Status; EFI_HTTP_HEADER *Header; CHAR8 *FilePath; CHAR8 *FilePost; if (Uri == NULL || UriParser == NULL || ImageType == NULL) { return EFI_INVALID_PARAMETER; } if (HeaderCount != 0 && Headers == NULL) { return EFI_INVALID_PARAMETER; } // // Determine the image type by the HTTP Content-Type header field first. // "application/efi" -> EFI Image // "application/vnd.efi-iso" -> CD/DVD Image // "application/vnd.efi-img" -> Virtual Disk Image // Header = HttpFindHeader (HeaderCount, Headers, HTTP_HEADER_CONTENT_TYPE); if (Header != NULL) { if (AsciiStriCmp (Header->FieldValue, HTTP_CONTENT_TYPE_APP_EFI) == 0) { *ImageType = ImageTypeEfi; return EFI_SUCCESS; } else if (AsciiStriCmp (Header->FieldValue, HTTP_CONTENT_TYPE_APP_ISO) == 0) { *ImageType = ImageTypeVirtualCd; return EFI_SUCCESS; } else if (AsciiStriCmp (Header->FieldValue, HTTP_CONTENT_TYPE_APP_IMG) == 0) { *ImageType = ImageTypeVirtualDisk; return EFI_SUCCESS; } } // // Determine the image type by file extension: // *.efi -> EFI Image // *.iso -> CD/DVD Image // *.img -> Virtual Disk Image // Status = HttpUrlGetPath ( Uri, UriParser, &FilePath ); if (EFI_ERROR (Status)) { return Status; } FilePost = FilePath + AsciiStrLen (FilePath) - 4; if (AsciiStrCmp (FilePost, ".efi") == 0) { *ImageType = ImageTypeEfi; } else if (AsciiStrCmp (FilePost, ".iso") == 0) { *ImageType = ImageTypeVirtualCd; } else if (AsciiStrCmp (FilePost, ".img") == 0) { *ImageType = ImageTypeVirtualDisk; } else { *ImageType = ImageTypeMax; } FreePool (FilePath); return (*ImageType < ImageTypeMax) ? EFI_SUCCESS : EFI_NOT_FOUND; }
/** 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; }
/** 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 command name @return EFI_SUCCESS **/ EFI_STATUS EblPerformance ( IN UINTN Argc, IN CHAR8 **Argv ) { UINTN Key; CONST VOID *Handle; CONST CHAR8 *Token, *Module; UINT64 Start, Stop, TimeStamp; UINT64 Delta, TicksPerSecond, Milliseconds, Microseconds; UINTN Index; BOOLEAN CountUp; TicksPerSecond = GetPerformanceCounterProperties (&Start, &Stop); if (Start < Stop) { CountUp = TRUE; } else { CountUp = FALSE; } Key = 0; do { Key = GetPerformanceMeasurement (Key, (CONST VOID **)&Handle, &Token, &Module, &Start, &Stop); if (Key != 0) { if (AsciiStriCmp ("StartImage:", Token) == 0) { if (Stop == 0) { // The entry for EBL is still running so the stop time will be zero. Skip it AsciiPrint (" running %a\n", ImageHandleToPdbFileName ((EFI_HANDLE)Handle)); } else { Delta = CountUp?(Stop - Start):(Start - Stop); Microseconds = DivU64x64Remainder (MultU64x32 (Delta, 1000000), TicksPerSecond, NULL); AsciiPrint ("%10ld us %a\n", Microseconds, ImageHandleToPdbFileName ((EFI_HANDLE)Handle)); } } } } while (Key != 0); AsciiPrint ("\n"); TimeStamp = 0; Key = 0; do { Key = GetPerformanceMeasurement (Key, (CONST VOID **)&Handle, &Token, &Module, &Start, &Stop); if (Key != 0) { for (Index = 0; mTokenList[Index] != NULL; Index++) { if (AsciiStriCmp (mTokenList[Index], Token) == 0) { Delta = CountUp?(Stop - Start):(Start - Stop); TimeStamp += Delta; Milliseconds = DivU64x64Remainder (MultU64x32 (Delta, 1000), TicksPerSecond, NULL); AsciiPrint ("%6a %6ld ms\n", Token, Milliseconds); break; } } } } while (Key != 0); AsciiPrint ("Total Time = %ld ms\n\n", DivU64x64Remainder (MultU64x32 (TimeStamp, 1000), TicksPerSecond, NULL)); return EFI_SUCCESS; }
/** Parse the MTFTP6 extesion options. @param[in] Options The pointer to the extension options list. @param[in] Count The num of the extension options. @param[in] IsRequest If FALSE, the extension options is included by a request packet. @param[in] ExtInfo The pointer to the option information to be filled. @retval EFI_SUCCESS Parse the multicast option successfully. @retval EFI_INVALID_PARAMETER There is one option is malformatted at least. @retval EFI_UNSUPPORTED There is one option is not supported at least. **/ EFI_STATUS Mtftp6ParseExtensionOption ( IN EFI_MTFTP6_OPTION *Options, IN UINT32 Count, IN BOOLEAN IsRequest, IN MTFTP6_EXT_OPTION_INFO *ExtInfo ) { EFI_STATUS Status; EFI_MTFTP6_OPTION *Opt; UINT32 Index; UINT32 Value; ExtInfo->BitMap = 0; for (Index = 0; Index < Count; Index++) { Opt = Options + Index; if (Opt->OptionStr == NULL || Opt->ValueStr == NULL) { return EFI_INVALID_PARAMETER; } if (AsciiStriCmp ((CHAR8 *) Opt->OptionStr, "blksize") == 0) { // // block size option, valid value is between [8, 65464] // Value = (UINT32) AsciiStrDecimalToUintn ((CHAR8 *) Opt->ValueStr); if ((Value < 8) || (Value > 65464)) { return EFI_INVALID_PARAMETER; } ExtInfo->BlkSize = (UINT16) Value; ExtInfo->BitMap |= MTFTP6_OPT_BLKSIZE_BIT; } else if (AsciiStriCmp ((CHAR8 *) Opt->OptionStr, "timeout") == 0) { // // timeout option, valid value is between [1, 255] // Value = (UINT32) AsciiStrDecimalToUintn ((CHAR8 *) Opt->ValueStr); if (Value < 1 || Value > 255) { return EFI_INVALID_PARAMETER; } ExtInfo->Timeout = (UINT8) Value; ExtInfo->BitMap |= MTFTP6_OPT_TIMEOUT_BIT; } else if (AsciiStriCmp ((CHAR8 *) Opt->OptionStr, "tsize") == 0) { // // tsize option, the biggest transfer supported is 4GB with block size option // ExtInfo->Tsize = (UINT32) AsciiStrDecimalToUintn ((CHAR8 *) Opt->ValueStr); ExtInfo->BitMap |= MTFTP6_OPT_TSIZE_BIT; } else if (AsciiStriCmp ((CHAR8 *) Opt->OptionStr, "multicast") == 0) { // // Multicast option, if it is a request, the value must be a zero string, // otherwise, it must be like "addr,port,mc" string, mc indicates master. // if (!IsRequest) { Status = Mtftp6ParseMcastOption (Opt->ValueStr, ExtInfo); if (EFI_ERROR (Status)) { return Status; } } else if (*(Opt->ValueStr) != '\0') { return EFI_INVALID_PARAMETER; } ExtInfo->BitMap |= MTFTP6_OPT_MCAST_BIT; } else if (IsRequest) { // // If it's a request, unsupported; else if it's a reply, ignore. // return EFI_UNSUPPORTED; } } return EFI_SUCCESS; }
/** Exit the EBL. If the command processor sees EFI_ABORTED return status it will exit the EBL. Argv[0] - "exit" @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_ABORTED **/ EFI_STATUS EFIAPI EblExitCmd ( IN UINTN Argc, IN CHAR8 **Argv ) { EFI_STATUS Status; UINTN MemoryMapSize; EFI_MEMORY_DESCRIPTOR *MemoryMap; UINTN MapKey; UINTN DescriptorSize; UINT32 DescriptorVersion; UINTN Pages; if (Argc > 1) { if (AsciiStriCmp (Argv[1], "efi") != 0) { return EFI_ABORTED; } } else if (Argc == 1) { return EFI_ABORTED; } MemoryMap = NULL; MemoryMapSize = 0; do { Status = gBS->GetMemoryMap ( &MemoryMapSize, MemoryMap, &MapKey, &DescriptorSize, &DescriptorVersion ); if (Status == EFI_BUFFER_TOO_SMALL) { Pages = EFI_SIZE_TO_PAGES (MemoryMapSize) + 1; MemoryMap = AllocatePages (Pages); // // Get System MemoryMap // Status = gBS->GetMemoryMap ( &MemoryMapSize, MemoryMap, &MapKey, &DescriptorSize, &DescriptorVersion ); // Don't do anything between the GetMemoryMap() and ExitBootServices() if (!EFI_ERROR (Status)) { Status = gBS->ExitBootServices (gImageHandle, MapKey); if (EFI_ERROR (Status)) { FreePages (MemoryMap, Pages); MemoryMap = NULL; MemoryMapSize = 0; } } } } while (EFI_ERROR (Status)); // // At this point it is very dangerous to do things EFI as most of EFI is now gone. // This command is useful if you are working with a debugger as it will shutdown // DMA and other things that could break a soft resets. // CpuDeadLoop (); // Should never get here, but makes the compiler happy return EFI_ABORTED; }
/** Parse Config data file to get the updated data array. @param DataBuffer Config raw file buffer. @param BufferSize Size of raw buffer. @param NumOfUpdates Pointer to the number of update data. @param UpdateArray Pointer to the config of update data. @retval EFI_NOT_FOUND No config data is found. @retval EFI_OUT_OF_RESOURCES No enough memory is allocated. @retval EFI_SUCCESS Parse the config file successfully. **/ EFI_STATUS ParseUpdateDataFile ( IN UINT8 *DataBuffer, IN UINTN BufferSize, IN OUT UINTN *NumOfUpdates, IN OUT UPDATE_CONFIG_DATA **UpdateArray ) { EFI_STATUS Status; CHAR8 *Value; CHAR8 *SectionName; CHAR8 Entry[MAX_LINE_LENGTH]; SECTION_ITEM *SectionHead; COMMENT_LINE *CommentHead; UINTN Num; UINTN Index; EFI_GUID FileGuid; SectionHead = NULL; CommentHead = NULL; // // First process the data buffer and get all sections and entries // Status = PreProcessDataFile ( DataBuffer, BufferSize, &SectionHead, &CommentHead ); if (EFI_ERROR (Status)) { FreeAllList (SectionHead, CommentHead); return Status; } // // Now get NumOfUpdate // Value = NULL; Status = UpdateGetProfileString ( SectionHead, (UINT8 *) "Head", (UINT8 *) "NumOfUpdate", (UINT8 **) &Value ); if (Value == NULL) { FreeAllList (SectionHead, CommentHead); return EFI_NOT_FOUND; } Num = UpdateAtoi((UINT8 *) Value); if (Num <= 0) { FreeAllList (SectionHead, CommentHead); return EFI_NOT_FOUND; } *NumOfUpdates = Num; *UpdateArray = AllocatePool ((sizeof (UPDATE_CONFIG_DATA) * Num)); if (*UpdateArray == NULL) { FreeAllList (SectionHead, CommentHead); return EFI_OUT_OF_RESOURCES; } for ( Index = 0 ; Index < *NumOfUpdates ; Index++) { // // Get the section name of each update // AsciiStrCpyS (Entry, MAX_LINE_LENGTH, "Update"); UpdateStrCatNumber ((UINT8 *) Entry, Index); Value = NULL; Status = UpdateGetProfileString ( SectionHead, (UINT8 *) "Head", (UINT8 *) Entry, (UINT8 **) &Value ); if (Value == NULL) { FreeAllList (SectionHead, CommentHead); return EFI_NOT_FOUND; } // // The section name of this update has been found. // Now looks for all the config data of this update // SectionName = Value; // // UpdateType // Value = NULL; Status = UpdateGetProfileString ( SectionHead, (UINT8 *) SectionName, (UINT8 *) "UpdateType", (UINT8 **) &Value ); if (Value == NULL) { FreeAllList (SectionHead, CommentHead); return EFI_NOT_FOUND; } Num = UpdateAtoi((UINT8 *) Value); if (( Num >= (UINTN) UpdateOperationMaximum)) { FreeAllList (SectionHead, CommentHead); return Status; } (*UpdateArray)[Index].Index = Index; (*UpdateArray)[Index].UpdateType = (UPDATE_OPERATION_TYPE) Num; // // FvBaseAddress // Value = NULL; Status = UpdateGetProfileString ( SectionHead, (UINT8 *) SectionName, (UINT8 *) "FvBaseAddress", (UINT8 **) &Value ); if (Value == NULL) { FreeAllList (SectionHead, CommentHead); return EFI_NOT_FOUND; } Num = AsciiStrHexToUintn ((CONST CHAR8 *) Value); (*UpdateArray)[Index].BaseAddress = (EFI_PHYSICAL_ADDRESS) Num; // // FileBuid // Value = NULL; Status = UpdateGetProfileString ( SectionHead, (UINT8 *) SectionName, (UINT8 *) "FileGuid", (UINT8 **) &Value ); if (Value == NULL) { FreeAllList (SectionHead, CommentHead); return EFI_NOT_FOUND; } Status = UpdateStringToGuid ((UINT8 *) Value, &FileGuid); if (EFI_ERROR (Status)) { FreeAllList (SectionHead, CommentHead); return Status; } CopyMem (&((*UpdateArray)[Index].FileGuid), &FileGuid, sizeof(EFI_GUID)); // // FaultTolerant // Default value is FALSE // Value = NULL; (*UpdateArray)[Index].FaultTolerant = FALSE; Status = UpdateGetProfileString ( SectionHead, (UINT8 *) SectionName, (UINT8 *) "FaultTolerant", (UINT8 **) &Value ); if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) { FreeAllList (SectionHead, CommentHead); return Status; } else if (Value != NULL) { if (AsciiStriCmp ((CONST CHAR8 *) Value, (CONST CHAR8 *) "TRUE") == 0) { (*UpdateArray)[Index].FaultTolerant = TRUE; } else if (AsciiStriCmp ((CONST CHAR8 *) Value, (CONST CHAR8 *) "FALSE") == 0) { (*UpdateArray)[Index].FaultTolerant = FALSE; } } if ((*UpdateArray)[Index].UpdateType == UpdateFvRange) { // // Length // Value = NULL; Status = UpdateGetProfileString ( SectionHead, (UINT8 *) SectionName, (UINT8 *) "Length", (UINT8 **) &Value ); if (Value == NULL) { FreeAllList (SectionHead, CommentHead); return EFI_NOT_FOUND; } Num = AsciiStrHexToUintn ((CONST CHAR8 *) Value); (*UpdateArray)[Index].Length = (UINTN) Num; } } // // Now all configuration data got. Free those temporary buffers // FreeAllList (SectionHead, CommentHead); return EFI_SUCCESS; }