/** Get PCD name. @param[in] OnlyTokenSpaceName If TRUE, only need to get the TokenSpaceCName. If FALSE, need to get the full PCD name. @param[in] Database PCD database. @param[in] TokenNumber The PCD token number. @return The TokenSpaceCName or full PCD name. **/ CHAR8 * GetPcdName ( IN BOOLEAN OnlyTokenSpaceName, IN PEI_PCD_DATABASE *Database, IN UINTN TokenNumber ) { UINT8 *StringTable; PCD_NAME_INDEX *PcdNameIndex; CHAR8 *TokenSpaceName; CHAR8 *PcdName; CHAR8 *Name; // // TokenNumber Zero is reserved as PCD_INVALID_TOKEN_NUMBER. // We have to decrement TokenNumber by 1 to make it usable // as the array index. // TokenNumber--; StringTable = (UINT8 *) Database + Database->StringTableOffset; // // Get the PCD name index. // PcdNameIndex = (PCD_NAME_INDEX *)((UINT8 *) Database + Database->PcdNameTableOffset) + TokenNumber; TokenSpaceName = (CHAR8 *)&StringTable[PcdNameIndex->TokenSpaceCNameIndex]; PcdName = (CHAR8 *)&StringTable[PcdNameIndex->PcdCNameIndex]; if (OnlyTokenSpaceName) { // // Only need to get the TokenSpaceCName. // Name = AllocateCopyPool (AsciiStrSize (TokenSpaceName), TokenSpaceName); } else { // // Need to get the full PCD name. // Name = AllocateZeroPool (AsciiStrSize (TokenSpaceName) + AsciiStrSize (PcdName)); ASSERT (Name != NULL); // // Catenate TokenSpaceCName and PcdCName with a '.' to form the full PCD name. // AsciiStrCat (Name, TokenSpaceName); Name[AsciiStrSize (TokenSpaceName) - sizeof (CHAR8)] = '.'; AsciiStrCat (Name, PcdName); } return Name; }
// // Returns parsed hex integer key. // Plist - kext pist // Key - key to find // WholePlist - _PrelinkInfoDictionary, used to find referenced values // // Searches for Key in Plist and it's value: // a) <integer ID="26" size="64">0x2b000</integer> // returns 0x2b000 // b) <integer IDREF="26"/> // searches for <integer ID="26"... from WholePlist // and returns value from that referenced field // // Whole function is here since we should avoid ParseXML() and it's // memory allocations during ExitBootServices(). And it seems that // ParseXML() does not support IDREF. // This func is hard to read and debug and probably not reliable, // but it seems it works. // UINT64 GetPlistHexValue ( CHAR8 *Plist, CHAR8 *Key, CHAR8 *WholePlist ) { CHAR8 *Value; CHAR8 *IntTag; UINT64 NumValue; CHAR8 *IDStart; CHAR8 *IDEnd; UINTN IDLen; CHAR8 Buffer[48]; NumValue = 0; // search for Key Value = AsciiStrStr (Plist, Key); if (Value == NULL) { return 0; } // search for <integer IntTag = AsciiStrStr (Value, "<integer"); if (IntTag == NULL) { return 0; } // find <integer end Value = AsciiStrStr (IntTag, ">"); if (Value == NULL) { return 0; } // normal case: value is here if (Value[-1] != '/') { NumValue = AsciiStrHexToUint64 (Value + 1); return NumValue; } // it might be a reference: IDREF="173"/> Value = AsciiStrStr (IntTag, "<integer IDREF=\""); if (Value != IntTag) { return 0; } // compose <integer ID="xxx" in the Buffer IDStart = AsciiStrStr (IntTag, "\"") + 1; IDEnd = AsciiStrStr (IDStart, "\""); IDLen = IDEnd - IDStart; if (IDLen > 8) { return 0; } AsciiStrCpy (Buffer, "<integer ID=\""); AsciiStrnCat (Buffer, IDStart, IDLen); AsciiStrCat (Buffer, "\""); // and search whole plist for ID IntTag = AsciiStrStr (WholePlist, Buffer); if (IntTag == NULL) { return 0; } // got it. find closing > Value = AsciiStrStr (IntTag, ">"); if (Value == NULL) { return 0; } if (Value[-1] == '/') { return 0; } // we should have value now NumValue = AsciiStrHexToUint64 (Value + 1); return NumValue; }
/** 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 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; }