/** @file Copyright (c) 2007 - 2017, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License that accompanies this distribution. The full text of the license may be found at http://opensource.org/licenses/bsd-license.php. THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. **/ #include "FirmwareUpdate.h" EFI_HII_HANDLE HiiHandle; /* MinnowBoard 3 Flash Layout Start (hex) End (hex) Length (hex) Area Name ----------- --------- ------------ --------- 00000000 007FFFFF 00800000 Full Flash Image 00000014 00000017 00000004 FLMAP0 - Flash Map 0 Register 00000018 0000001B 00000004 FLMAP1 - Flash Map 1 Register 0000001C 0000001F 00000004 FLMAP2 - Flash Map 2 Register 00000030 0000003B 0000000C FCBA - Flash Component Registers 00000040 00000043 00000004 FLREG0 - Flash Region 0 (Flash Descriptor) Register 00000044 00000047 00000004 FLREG1 - Flash Region 1 (IFWI) Register 00000048 0000004B 00000004 FLREG2 - Flash Region 2 (Intel(R) TXE) Register 00000050 00000053 00000004 FLREG4 - Flash Region 4 (Platform Data) Register 00000054 00000057 00000004 FLREG5 - Flash Region 5 (Device Expansion) Register 00000060 00000063 00000004 FLREG8 - Flash Region 8 (Embedded Controller) Register 00000080 00000083 00000004 FLMSTR1 - Flash Master 1 (Host CPU/BIOS) 00000084 00000087 00000004 FLMSTR2 - Flash Master 2 (Intel(R) TXE) 00000100 000002FF 00000200 FPSBA - SoC Straps (Including Padding) 000003EC 0000046B 00000080 FPSBA - SoC Straps (Including Padding) 00000DF0 00000EFF 00000110 VSCC Table 00000DF0 00000DF7 00000008 VsccEntry0 00001000 00241FFF 00241000 Boot Partition 1 00001000 000F9FFF 000F9000 Primary Boot Partition 00001200 0000120F 00000010 IFP Overrides Partition 00001210 00001317 00000108 Unified Emulation Partition (UEP) 00002000 00005FFF 00004000 OEM SMIP Partition 00006000 0000FFFF 0000A000 CSE RBE Partition 00010000 0001FFFF 00010000 PMCP 00020000 0007BFFF 0005C000 CSE BUP Partition 0007C000 0007FFFF 00004000 uCode Partition 00080000 000F7FFF 00078000 IBB Partition 000F8000 000F9FFF 00002000 Debug Token Partition 000FA000 00241FFF 00148000 Secondary Boot Partition 000FB000 0013AFFF 00040000 ISHC Partition 0013B000 0023FFFF 00105000 CSE Main Partition 00240000 00241FFF 00002000 IUnit Partition 00242000 0065BFFF 0041A000 Secondary Boot Partition 00242000 0065BFFF 0041A000 Boot Partition 2 00381000 0065BFFF 002DB000 OBB Partition 0065C000 006FF000 000A3001 TXE Data Region */ FV_REGION_INFO mRegionInfo[] = { {0xFF800000, 0x00001000, TRUE}, {0xFF801000, 0x0037F000, TRUE}, {0xFFB80000, 0x0037F000, TRUE}, {0xFFEFF000, 0x00100000, TRUE}, }; UINTN mRegionInfoCount = sizeof (mRegionInfo) / sizeof (mRegionInfo[0]); FV_INPUT_DATA mInputData = {0}; SC_SPI_PROTOCOL *mSpiProtocol; EFI_STATUS GetRegionIndex ( IN EFI_PHYSICAL_ADDRESS Address, OUT UINTN *RegionIndex ) { UINTN Index; for (Index = 0; Index < mRegionInfoCount; Index++) { if (Address >= mRegionInfo[Index].Base && Address < (mRegionInfo[Index].Base + mRegionInfo[Index].Size) ) { break; } } *RegionIndex = Index; if (Index >= mRegionInfoCount) { return EFI_NOT_FOUND; } return EFI_SUCCESS; } BOOLEAN UpdateBlock ( IN EFI_PHYSICAL_ADDRESS Address ) { EFI_STATUS Status; UINTN Index; if (mInputData.FullFlashUpdate) { // // Apollo Lake Workaround: 0xFFFFF000 - 0xFFFFFFFF region (Top 4KB bwlow 4G) could not be access by SPI protocol. // if (Address >= 0xFFFFF000) { return FALSE; } return TRUE; } Status = GetRegionIndex (Address, &Index); if ((!EFI_ERROR(Status)) && mRegionInfo[Index].Update) { return TRUE; } return FALSE; } EFI_STATUS MarkRegionState ( IN EFI_PHYSICAL_ADDRESS Address, IN BOOLEAN Update ) { EFI_STATUS Status; UINTN Index; Status = GetRegionIndex (Address, &Index); if (!EFI_ERROR(Status)) { mRegionInfo[Index].Update = Update; } return Status; } UINTN InternalPrintToken ( IN CONST CHAR16 *Format, IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *Console, IN VA_LIST Marker ) { EFI_STATUS Status; UINTN Return; CHAR16 *Buffer; UINTN BufferSize; ASSERT (Format != NULL); ASSERT (((UINTN) Format & BIT0) == 0); ASSERT (Console != NULL); BufferSize = (PcdGet32 (PcdUefiLibMaxPrintBufferSize) + 1) * sizeof (CHAR16); Buffer = (CHAR16 *) AllocatePool(BufferSize); ASSERT (Buffer != NULL); Return = UnicodeVSPrint (Buffer, BufferSize, Format, Marker); if (Console != NULL && Return > 0) { // // To be extra safe make sure Console has been initialized. // Status = Console->OutputString (Console, Buffer); if (EFI_ERROR (Status)) { Return = 0; } } FreePool (Buffer); return Return; } UINTN EFIAPI PrintToken ( IN UINT16 Token, IN EFI_HII_HANDLE Handle, ... ) { VA_LIST Marker; UINTN Return; CHAR16 *Format; VA_START (Marker, Handle); Format = HiiGetString (Handle, Token, NULL); ASSERT (Format != NULL); Return = InternalPrintToken (Format, gST->ConOut, Marker); FreePool (Format); VA_END (Marker); return Return; } EFI_STATUS ParseCommandLine ( IN UINTN Argc, IN CHAR16 **Argv ) { EFI_STATUS Status; UINTN Index; // // Check to make sure that the command line has enough arguments for minimal // operation. The minimum is just the file name. // if (Argc < 2 || Argc > 4) { return EFI_INVALID_PARAMETER; } // // Loop through command line arguments. // for (Index = 1; Index < Argc; Index++) { // // Make sure the string is valid. // if (StrLen (Argv[Index]) == 0) {; PrintToken (STRING_TOKEN (STR_FWUPDATE_ZEROLENGTH_ARG), HiiHandle); return EFI_INVALID_PARAMETER; } // // Check to see if this is an option or the file name. // if ((Argv[Index])[0] == L'-' || (Argv[Index])[0] == L'/') { // // Parse the arguments. // if ((StrCmp (Argv[Index], L"-h") == 0) || (StrCmp (Argv[Index], L"--help") == 0) || (StrCmp (Argv[Index], L"/?") == 0) || (StrCmp (Argv[Index], L"/h") == 0)) { // // Print Help Information. // return EFI_INVALID_PARAMETER; } else if (StrCmp (Argv[Index], L"-m") == 0) { // // Parse the MAC address here. // Status = ConvertMac(Argv[Index+1]); if (EFI_ERROR(Status)) { PrintToken (STRING_TOKEN (STR_FWUPDATE_INVAILD_MAC), HiiHandle); return Status; } // // Save the MAC address to mInputData.MacValue. // mInputData.UpdateMac= TRUE; Index++; } else { // // Invalid option was provided. // return EFI_INVALID_PARAMETER; } } if ((Index == Argc - 1) && (StrCmp (Argv[Index - 1], L"-m") != 0)) { // // The only parameter that is not an option is the firmware image. Check // to make sure that the file exists. // Status = ShellIsFile (Argv[Index]); if (EFI_ERROR (Status)) { PrintToken (STRING_TOKEN (STR_FWUPDATE_FILE_NOT_FOUND_ERROR), HiiHandle, Argv[Index]); return EFI_INVALID_PARAMETER; } if (StrLen (Argv[Index]) > INPUT_STRING_LEN) { PrintToken (STRING_TOKEN (STR_FWUPDATE_PATH_ERROR), HiiHandle, Argv[Index]); return EFI_INVALID_PARAMETER; } StrCpy (mInputData.FileName, Argv[Index]); mInputData.UpdateFromFile = TRUE; } } return EFI_SUCCESS; } INTN EFIAPI ShellAppMain ( IN UINTN Argc, IN CHAR16 **Argv ) { EFI_STATUS Status; UINTN Index; UINT32 FileSize; UINT32 BufferSize; UINT8 *FileBuffer; UINT8 *Buffer; EFI_PHYSICAL_ADDRESS Address; UINTN CountOfBlocks; EFI_TPL OldTpl; BOOLEAN ResetRequired; BOOLEAN FlashError; Index = 0; FileSize = 0; BufferSize = 0; FileBuffer = NULL; Buffer = NULL; Address = 0; CountOfBlocks = 0; ResetRequired = FALSE; FlashError = FALSE; Status = EFI_SUCCESS; mInputData.FullFlashUpdate = TRUE; // // Publish our HII data. // HiiHandle = HiiAddPackages ( &gEfiCallerIdGuid, NULL, FirmwareUpdateStrings, NULL ); if (HiiHandle == NULL) { Status = EFI_OUT_OF_RESOURCES; goto Done; } // // Locate the SPI protocol. // Status = gBS->LocateProtocol ( &gScSpiProtocolGuid, NULL, (VOID **)&mSpiProtocol ); if (EFI_ERROR (Status)) { PrintToken (STRING_TOKEN (STR_SPI_NOT_FOUND), HiiHandle); return EFI_DEVICE_ERROR; } // // Parse the command line. // Status = ParseCommandLine (Argc, Argv); if (EFI_ERROR (Status)) { PrintHelpInfo (); Status = EFI_SUCCESS; goto Done; } // // Display sign-on information. // PrintToken (STRING_TOKEN (STR_FWUPDATE_FIRMWARE_VOL_UPDATE), HiiHandle); PrintToken (STRING_TOKEN (STR_FWUPDATE_VERSION), HiiHandle); PrintToken (STRING_TOKEN (STR_FWUPDATE_COPYRIGHT), HiiHandle); // // Test to see if the firmware needs to be updated. // if (mInputData.UpdateFromFile) { // // Get the file to use in the update. // PrintToken (STRING_TOKEN (STR_FWUPDATE_READ_FILE), HiiHandle, mInputData.FileName); Status = ReadFileData (mInputData.FileName, &FileBuffer, &FileSize); if (EFI_ERROR (Status)) { PrintToken (STRING_TOKEN (STR_FWUPDATE_READ_FILE_ERROR), HiiHandle, mInputData.FileName); goto Done; } // // Check that the file and flash sizes match. // if (FileSize != PcdGet32 (PcdFlashAreaSize)) { PrintToken (STRING_TOKEN (STR_FWUPDATE_SIZE), HiiHandle); Status = EFI_UNSUPPORTED; goto Done; } // // Display flash update information. // PrintToken (STRING_TOKEN (STR_FWUPDATE_UPDATING_FIRMWARE), HiiHandle); // // Update it. // Buffer = FileBuffer; BufferSize = FileSize; Address = PcdGet32 (PcdFlashAreaBaseAddress); CountOfBlocks = (UINTN) (BufferSize / BLOCK_SIZE); // // Raise TPL to TPL_NOTIFY to block any event handler, // while still allowing RaiseTPL(TPL_NOTIFY) within // output driver during Print(). // OldTpl = gBS->RaiseTPL (TPL_NOTIFY); for (Index = 0; Index < CountOfBlocks; Index++) { // // Handle block based on address and contents. // if (!UpdateBlock (Address)) { DEBUG((EFI_D_INFO, "Skipping block at 0x%lx\n", Address)); } else if (!EFI_ERROR (InternalCompareBlock (Address, Buffer))) { DEBUG((EFI_D_INFO, "Skipping block at 0x%lx (already programmed)\n", Address)); } else { // // Display a dot for each block being updated. // Print (L"."); // // Flag that the flash image will be changed and the system must be rebooted // to use the change. // ResetRequired = TRUE; // // Make updating process uninterruptable, // so that the flash memory area is not accessed by other entities // which may interfere with the updating process. // Status = InternalEraseBlock (Address); ASSERT_EFI_ERROR(Status); if (EFI_ERROR (Status)) { gBS->RestoreTPL (OldTpl); FlashError = TRUE; goto Done; } Status = InternalWriteBlock ( Address, Buffer, (BufferSize > BLOCK_SIZE ? BLOCK_SIZE : BufferSize) ); if (EFI_ERROR (Status)) { gBS->RestoreTPL (OldTpl); FlashError = TRUE; goto Done; } } // // Move to next block to update. // Address += BLOCK_SIZE; Buffer += BLOCK_SIZE; if (BufferSize > BLOCK_SIZE) { BufferSize -= BLOCK_SIZE; } else { BufferSize = 0; } } gBS->RestoreTPL (OldTpl); // // Print result of update. // if (!FlashError) { if (ResetRequired) { Print (L"\n"); PrintToken (STRING_TOKEN (STR_FWUPDATE_UPDATE_SUCCESS), HiiHandle); } else { PrintToken (STRING_TOKEN (STR_FWUPDATE_NO_RESET), HiiHandle); } } else { goto Done; } } // // All flash updates are done so see if the system needs to be reset. // if (ResetRequired && !FlashError) { // // Update successful. // for (Index = 5; Index > 0; Index--) { PrintToken (STRING_TOKEN (STR_FWUPDATE_SHUTDOWN), HiiHandle, Index); gBS->Stall (1000000); } gRT->ResetSystem (EfiResetShutdown, EFI_SUCCESS, 0, NULL); PrintToken (STRING_TOKEN (STR_FWUPDATE_MANUAL_RESET), HiiHandle); CpuDeadLoop (); } Done: // // Print flash update failure message if error is detected. // if (FlashError) { PrintToken (STRING_TOKEN (STR_FWUPDATE_UPDATE_FAILED), HiiHandle, Index); } // // Do cleanup. // if (HiiHandle != NULL) { HiiRemovePackages (HiiHandle); } if (FileBuffer) { gBS->FreePool (FileBuffer); } return Status; } /*++ Erase the whole block. @param[in] BaseAddress Base address of the block to be erased. @retval EFI_SUCCESS The command completed successfully. @retval Other Device error or wirte-locked, operation failed. --*/ STATIC EFI_STATUS InternalEraseBlock ( IN EFI_PHYSICAL_ADDRESS BaseAddress ) { EFI_STATUS Status; UINTN NumBytes; NumBytes = BLOCK_SIZE; Status = SpiFlashBlockErase ((UINTN) BaseAddress, &NumBytes); return Status; } STATIC EFI_STATUS InternalCompareBlock ( IN EFI_PHYSICAL_ADDRESS BaseAddress, IN UINT8 *Buffer ) { EFI_STATUS Status; VOID *CompareBuffer; UINT32 NumBytes; INTN CompareResult; NumBytes = BLOCK_SIZE; CompareBuffer = AllocatePool (NumBytes); if (CompareBuffer == NULL) { Status = EFI_OUT_OF_RESOURCES; goto Done; } Status = SpiFlashRead ((UINTN) BaseAddress, &NumBytes, CompareBuffer); if (EFI_ERROR (Status)) { goto Done; } CompareResult = CompareMem (CompareBuffer, Buffer, BLOCK_SIZE); if (CompareResult != 0) { Status = EFI_VOLUME_CORRUPTED; } Done: if (CompareBuffer != NULL) { FreePool (CompareBuffer); } return Status; } /*++ Write a block of data. @param[in] BaseAddress Base address of the block. @param[in] Buffer Data buffer. @param[in] BufferSize Size of the buffer. @retval EFI_SUCCESS The command completed successfully. @retval EFI_INVALID_PARAMETER Invalid parameter, can not proceed. @retval Other Device error or wirte-locked, operation failed. --*/ STATIC EFI_STATUS InternalWriteBlock ( IN EFI_PHYSICAL_ADDRESS BaseAddress, IN UINT8 *Buffer, IN UINT32 BufferSize ) { EFI_STATUS Status; Status = SpiFlashWrite ((UINTN) BaseAddress, &BufferSize, Buffer); ASSERT_EFI_ERROR(Status); if (EFI_ERROR (Status)) { DEBUG((EFI_D_ERROR, "\nFlash write error.")); return Status; } //Workaround: WriteBackInvalidateDataCacheRange ((VOID *) (UINTN) BaseAddress, BLOCK_SIZE); Status = InternalCompareBlock (BaseAddress, Buffer); if (EFI_ERROR (Status)) { DEBUG((EFI_D_ERROR, "\nError when writing to BaseAddress %lx with different at offset %x.", BaseAddress, Status)); } else { DEBUG((EFI_D_INFO, "\nVerified data written to Block at %lx is correct.", BaseAddress)); } return Status; } STATIC EFI_STATUS ReadFileData ( IN CHAR16 *FileName, OUT UINT8 **Buffer, OUT UINT32 *BufferSize ) { EFI_STATUS Status; SHELL_FILE_HANDLE FileHandle; UINT64 Size; VOID *NewBuffer; UINTN ReadSize; FileHandle = NULL; NewBuffer = NULL; Size = 0; Status = ShellOpenFileByName (FileName, &FileHandle, EFI_FILE_MODE_READ, 0); if (EFI_ERROR (Status)) { goto Done; } Status = FileHandleIsDirectory (FileHandle); if (!EFI_ERROR (Status)) { Status = EFI_NOT_FOUND; goto Done; } Status = FileHandleGetSize (FileHandle, &Size); if (EFI_ERROR (Status)) { goto Done; } NewBuffer = AllocatePool ((UINTN) Size); ReadSize = (UINTN) Size; Status = FileHandleRead (FileHandle, &ReadSize, NewBuffer); if (EFI_ERROR (Status)) { goto Done; } else if (ReadSize != (UINTN) Size) { Status = EFI_INVALID_PARAMETER; goto Done; } Done: if (FileHandle != NULL) { ShellCloseFile (&FileHandle); } if (EFI_ERROR (Status)) { if (NewBuffer != NULL) { FreePool (NewBuffer); } } else { *Buffer = NewBuffer; *BufferSize = (UINT32) Size; } return Status; } STATIC VOID PrintHelpInfo ( VOID ) { PrintToken (STRING_TOKEN (STR_FWUPDATE_FIRMWARE_VOL_UPDATE), HiiHandle); PrintToken (STRING_TOKEN (STR_FWUPDATE_VERSION), HiiHandle); PrintToken (STRING_TOKEN (STR_FWUPDATE_COPYRIGHT), HiiHandle); Print (L"\n"); PrintToken (STRING_TOKEN (STR_FWUPDATE_USAGE), HiiHandle); PrintToken (STRING_TOKEN (STR_FWUPDATE_USAGE_1), HiiHandle); PrintToken (STRING_TOKEN (STR_FWUPDATE_USAGE_2), HiiHandle); PrintToken (STRING_TOKEN (STR_FWUPDATE_USAGE_3), HiiHandle); PrintToken (STRING_TOKEN (STR_FWUPDATE_USAGE_4), HiiHandle); Print (L"\n"); } /** Read NumBytes bytes of data from the address specified by PAddress into Buffer. @param[in] Address The starting physical address of the read. @param[in,out] NumBytes On input, the number of bytes to read. On output, the number of bytes actually read. @param[out] Buffer The destination data buffer for the read. @retval EFI_SUCCESS Opertion is successful. @retval EFI_DEVICE_ERROR If there is any device errors. **/ EFI_STATUS EFIAPI SpiFlashRead ( IN UINTN Address, IN OUT UINT32 *NumBytes, OUT UINT8 *Buffer ) { EFI_STATUS Status = EFI_SUCCESS; UINT32 SectorSize; UINT32 Offset; UINT8 TempBuffer[SIZE_4KB]; UINTN Count = 0; UINT32 Length; Offset = (UINT32)Address - PcdGet32 (PcdFlashAreaBaseAddress); SectorSize = SIZE_4KB; Length = *NumBytes; while (Count < Length) { Status = mSpiProtocol ->FlashRead ( mSpiProtocol, FlashRegionAll, Offset, SIZE_4KB, TempBuffer ); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "Read SPI ROM Failed [%08x]\n", Offset)); break; } CopyMem ((Buffer + Count), (VOID *)TempBuffer, SectorSize); Offset += SectorSize; Count += SectorSize; } return Status; } /** Write NumBytes bytes of data from Buffer to the address specified by PAddresss. @param[in] Address The starting physical address of the write. @param[in,out] NumBytes On input, the number of bytes to write. On output, the actual number of bytes written. @param[in] Buffer The source data buffer for the write. @retval EFI_SUCCESS Opertion is successful. @retval EFI_DEVICE_ERROR If there is any device errors. **/ EFI_STATUS EFIAPI SpiFlashWrite ( IN UINTN Address, IN OUT UINT32 *NumBytes, IN UINT8 *Buffer ) { EFI_STATUS Status; UINT32 Offset; UINT32 Length; UINT32 RemainingBytes; ASSERT ((NumBytes != NULL) && (Buffer != NULL)); ASSERT (Address >= (UINTN)PcdGet32 (PcdFlashAreaBaseAddress)); Offset = (UINT32)Address - PcdGet32 (PcdFlashAreaBaseAddress); ASSERT ((*NumBytes + Offset) <= (UINTN)PcdGet32 (PcdFlashAreaSize)); Status = EFI_SUCCESS; RemainingBytes = *NumBytes; while (RemainingBytes > 0) { DEBUG ((EFI_D_ERROR, "SpiFlashWrite RemainingBytes 0x%x\n", RemainingBytes)); if (RemainingBytes > SIZE_4KB) { Length = SIZE_4KB; } else { Length = RemainingBytes; } Status = mSpiProtocol->FlashWrite( mSpiProtocol, FlashRegionAll, Offset, Length, Buffer ); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "SPI Wirte failed. Status: %r.\n", Status)); break; } RemainingBytes -= Length; Offset += Length; Buffer += Length; } // // Actual number of bytes written. // *NumBytes -= RemainingBytes; return Status; } /** Erase the block starting at Address. @param[in] Address The starting physical address of the block to be erased. This library assume that caller garantee that the PAddress is at the starting address of this block. @param[in] NumBytes On input, the number of bytes of the logical block to be erased. On output, the actual number of bytes erased. @retval EFI_SUCCESS. Opertion is successful. @retval EFI_DEVICE_ERROR If there is any device errors. **/ EFI_STATUS EFIAPI SpiFlashBlockErase ( IN UINTN Address, IN UINTN *NumBytes ) { EFI_STATUS Status; UINT32 Offset; UINTN RemainingBytes; ASSERT (NumBytes != NULL); ASSERT (Address >= (UINTN)PcdGet32 (PcdFlashAreaBaseAddress)); Offset = (UINT32)Address - PcdGet32 (PcdFlashAreaBaseAddress); ASSERT ((*NumBytes % SIZE_4KB) == 0); ASSERT ((*NumBytes + Offset) <= (UINTN)PcdGet32 (PcdFlashAreaSize)); Status = EFI_SUCCESS; RemainingBytes = *NumBytes; while (RemainingBytes > 0) { Status = mSpiProtocol->FlashErase ( mSpiProtocol, FlashRegionAll, Offset, SIZE_4KB ); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "Erase failed. Status: %r Offset = 0x%x\n", Status, Offset)); break; } RemainingBytes -= SIZE_4KB; Offset += SIZE_4KB; } return Status; } EFI_STATUS EFIAPI ConvertMac ( CHAR16 *Str ) { UINTN Index; UINT8 Temp[MAC_ADD_STR_LEN]; if (Str == NULL) return EFI_INVALID_PARAMETER; if (StrLen(Str) != MAC_ADD_STR_LEN) return EFI_INVALID_PARAMETER; for (Index = 0; Index < MAC_ADD_STR_LEN; Index++) { if (Str[Index] >= 0x30 && Str[Index] <= 0x39) { Temp[Index] = (UINT8)Str[Index] - 0x30; } else if (Str[Index] >= 0x41 && Str[Index] <= 0x46) { Temp[Index] = (UINT8)Str[Index] - 0x37; } else if (Str[Index] >= 0x61 && Str[Index] <= 0x66) { Temp[Index] = (UINT8)Str[Index] - 0x57; } else { return EFI_INVALID_PARAMETER; } } for (Index = 0; Index < MAC_ADD_BYTE_COUNT; Index++) { mInputData.MacValue[Index] = (Temp[2 * Index] << 4) + Temp[2 * Index + 1]; } return EFI_SUCCESS; }