Step to UEFI (67) —– zLib (上)

zlib 是一款开源的压缩解压库,在《UEFI原理与编程》第8章提到了他。我去书上提到的网站下载到了修改后的 zlib.inf 文件,然后尝试在AppPkg中重新编译之。

首先根据 zlib.inf 中[Sources]节给出的文件名提取出来需要用的文件。

[Sources]
#uefientry.c
adler32.c
crc32.c
deflate.c
infback.c
inffast.c
inflate.c
inftrees.c
trees.c
zutil.c
compress.c
uncompr.c
gzclose.c
gzlib.c
gzread.c
gzwrite.c

然后,把 zlib.inf 加入到 AppPkg.dsc 中。之后用 Build -a IA32 -p AppPkg\AppPkg.dsc 编译。编译过程中会出现很多错误,经过研究发现出现的都是一些 warning 而已,可以通过在文件头上加入编译开关来忽略掉。

#pragma warning(disable:4131)
#pragma warning(disable:4142)
#pragma warning(disable:4244)

 

* 很多 Warning 是因为老的语法格式导致的,所以不会对代码产生任何影响,比如下面这种,没有在函数名称中定义参数类型:

/* Open a gzip file either by name or file descriptor. */
local gzFile gz_open(path, fd, mode)
    const void *path;
    int fd;
    const char *mode;

 

此外,在 gzguts.h 中,需要删掉这一行。

#if defined(__TURBOC__) || defined(_MSC_VER) || defined(_WIN32)
  include <io.h>
#endif

 

完成上面的设置后,重新运行命令,可以正常编译:

zlibc

在 \Build\AppPkg\DEBUG_MYTOOLS\IA32\AppPkg\Applications\zsource\zlib\OUTPUT 下面看到 zlib.lib 文件

zlib

后续我们就可以在自己的程序中调用这个压缩库了。

本文修改后的 zlib zsource

修改之前的 zlib,版本是 1.2.8.0

zlib128

Step to UEFI (65) —– ShellWriteFile的使用

前面介绍过使用 ShellReadFile 读取文件的内容,这里介绍一下 ShellWriteFile 的使用。

例子是使用 ShellOpenFileByName 打开当前的 EFI Application,把内容读取到内存之后,创建一个名为 Test.efi 的文件,使用 ShellWriteFile 函数把内容写进去。

代码如下:

#include  <Uefi.h>
#include  <Library/UefiLib.h>
#include  <Library/ShellCEntryLib.h>
#include  <Library/ShellLib.h>
#include  <Library/MemoryAllocationLib.h>

extern EFI_BOOT_SERVICES         *gBS;
extern EFI_SYSTEM_TABLE			 *gST;
extern EFI_RUNTIME_SERVICES 	 *gRT;

int
EFIAPI
main (
  IN int Argc,
  IN CHAR16 **Argv
  )
{

  EFI_FILE_HANDLE   FileHandle;
  RETURN_STATUS     Status;
  EFI_FILE_INFO     *FileInfo = NULL;
  EFI_HANDLE        *HandleBuffer=NULL;
  UINTN  			ReadSize;
  
  //Open the file given by the parameter
  Status = ShellOpenFileByName(Argv[0], 
		(SHELL_FILE_HANDLE *)&
                FileHandle,
                EFI_FILE_MODE_READ , 0);

  if(Status != RETURN_SUCCESS) {
        Print(L"OpenFile failed!\n");
		return EFI_SUCCESS;
      }			

  //Get file size	  
  FileInfo = ShellGetFileInfo( (SHELL_FILE_HANDLE)FileHandle);	

  //Allocate a memory buffer
  HandleBuffer = AllocateZeroPool((UINTN) FileInfo-> FileSize);
  if (HandleBuffer == NULL) {
      return (SHELL_OUT_OF_RESOURCES);   }

  ReadSize=(UINTN) FileInfo-> FileSize;
  
  //Load the whole file to the buffer
  Status = ShellReadFile(FileHandle,&ReadSize,HandleBuffer);
  
  //Close the source file
  ShellCloseFile(&FileHandle);

  //Create a new file
  Status = ShellOpenFileByName(L"Test.efi", 
             (SHELL_FILE_HANDLE *)&FileHandle,
                               EFI_FILE_MODE_READ |
			       EFI_FILE_MODE_WRITE|
			       EFI_FILE_MODE_CREATE, 
			    0);  
  if(Status != RETURN_SUCCESS) {
        Print(L"CreatFile failed [%r]!\n",Status);
	    return EFI_SUCCESS;
      }	
  Status = ShellWriteFile(FileHandle,
			&ReadSize,
			HandleBuffer
			);
  //Close the source file
  ShellCloseFile(&FileHandle);
  
  return EFI_SUCCESS;
}

 

运行结果(运行结束之后我比较了一下生成文件和源文件是相同的):

ctf

特别注意:使用 ShellOpenFuleByName 创建一个文件时,要同时使用 EFI_FILE_MODE_READ ,EFI_FILE_MODE_WRITE 和 EFI_FILE_MODE_CREATE ,否则可能出现“Invalid Parameter”的错误【参考1】

完整代码下载
CreateFile

1.http://feishare.com/efimail/messages/20120331-0611-Re__edk2__Problems_creating_file_using_ShellOpenFileByName-_Bekefi__Stephen_C_.html

Step to UEFI (64) —– Print 直接输出错误信息

最近发现一个挺有意思的功能,Print 使用 %r 参数可以直接输出错误信息的含义。这样的话,我们可以直接取得错误信息,省去不少麻烦。例如,下面的代码

#include  <Uefi.h>
#include  <Library/UefiLib.h>
#include  <Library/ShellCEntryLib.h>


extern EFI_BOOT_SERVICES         *gBS;
extern EFI_SYSTEM_TABLE			 *gST;
extern EFI_RUNTIME_SERVICES 	 *gRT;

int
EFIAPI
main (
  IN int Argc,
  IN CHAR16 **Argv
  )
{
  Print(L"%r\n",EFI_SUCCESS);
  Print(L"%r\n",RETURN_WARN_WRITE_FAILURE);
  Print(L"%r\n",RETURN_COMPROMISED_DATA);
  
  return EFI_SUCCESS;
}

 

运行结果

printr

我们再仔细研究一下 %r 的具体实现。

查看 PrintR 编译生成的 printf.map ,可以看到 _Print 是链接到 UefiLibPrint.obj 中。用这个文件名,我们确定是在 \MdePkg\Library\UefiLib\UefiLibPrint.c 这个文件中

0001:000000ce _ShellCEntryLib 0000032e f UefiShellCEntryLib:UefiShellCEntryLib.obj
0001:00000140 _InternalPrint 000003a0 f UefiLib:UefiLibPrint.obj
0001:0000018b _Print 000003eb f UefiLib:UefiLibPrint.obj
0001:000001a8 _ShellFindSE2 00000408 f UefiShellLib:UefiShellLib.obj
0001:000002d8 _ShellLibConstructorWorker 00000538 f UefiShellLib:UefiShellLib.obj
0001:0000048d _ShellLibDestructor 000006ed f UefiShellLib:UefiShellLib.obj
0001:00000535 _ShellOpenFileByDevicePath 00000795 f UefiShellLib:UefiShellLib.obj

Print 函数:

/** 
  Prints a formatted Unicode string to the console output device specified by 
  ConOut defined in the EFI_SYSTEM_TABLE.

  This function prints a formatted Unicode string to the console output device 
  specified by ConOut in EFI_SYSTEM_TABLE and returns the number of Unicode 
  characters that printed to ConOut.  If the length of the formatted Unicode 
  string is greater than PcdUefiLibMaxPrintBufferSize, then only the first 
  PcdUefiLibMaxPrintBufferSize characters are sent to ConOut.
  If Format is NULL, then ASSERT().
  If Format is not aligned on a 16-bit boundary, then ASSERT().
  If gST->ConOut is NULL, then ASSERT().

  @param Format   A Null-terminated Unicode format string.
  @param ...      A Variable argument list whose contents are accessed based 
                  on the format string specified by Format.
  
  @return The number of Unicode characters printed to ConOut.

**/
UINTN
EFIAPI
Print (
  IN CONST CHAR16  *Format,
  ...
  )
{
  VA_LIST Marker;
  UINTN   Return;

  VA_START (Marker, Format);

  Return = InternalPrint (Format, gST->ConOut, Marker);

  VA_END (Marker);

  return Return;
}

 

InternalPrint 函数在同一个文件中

/**
  Internal function which prints a formatted Unicode string to the console output device
  specified by Console

  This function prints a formatted Unicode string to the console output device
  specified by Console and returns the number of Unicode characters that printed
  to it.  If the length of the formatted Unicode string is greater than PcdUefiLibMaxPrintBufferSize,
  then only the first PcdUefiLibMaxPrintBufferSize characters are sent to Console.
  If Format is NULL, then ASSERT().
  If Format is not aligned on a 16-bit boundary, then ASSERT().

  @param Format   A Null-terminated Unicode format string.
  @param Console  The output console.
  @param Marker   A VA_LIST marker for the variable argument list.

  @return The number of Unicode characters in the produced
          output buffer, not including the Null-terminator.
**/
UINTN
InternalPrint (
  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;
}

 

处理输出的核心是 UnicodeVSPrint 函数

/**
  Produces a Null-terminated Unicode string in an output buffer based on 
  a Null-terminated Unicode format string and a VA_LIST argument list
  
  Produces a Null-terminated Unicode string in the output buffer specified by StartOfBuffer
  and BufferSize.  
  The Unicode string is produced by parsing the format string specified by FormatString.  
  Arguments are pulled from the variable argument list specified by Marker based on the 
  contents of the format string.  
  The number of Unicode characters in the produced output buffer is returned not including
  the Null-terminator.
  If BufferSize is 0 or 1, then no output buffer is produced and 0 is returned.

  If BufferSize > 1 and StartOfBuffer is NULL, then ASSERT().
  If BufferSize > 1 and StartOfBuffer is not aligned on a 16-bit boundary, then ASSERT().
  If BufferSize > 1 and FormatString is NULL, then ASSERT().
  If BufferSize > 1 and FormatString is not aligned on a 16-bit boundary, then ASSERT().
  If PcdMaximumUnicodeStringLength is not zero, and FormatString contains more than 
  PcdMaximumUnicodeStringLength Unicode characters not including the Null-terminator, then
  ASSERT().
  If PcdMaximumUnicodeStringLength is not zero, and produced Null-terminated Unicode string
  contains more than PcdMaximumUnicodeStringLength Unicode characters not including the
  Null-terminator, then ASSERT().

  @param  StartOfBuffer   A pointer to the output buffer for the produced Null-terminated 
                          Unicode string.
  @param  BufferSize      The size, in bytes, of the output buffer specified by StartOfBuffer.
  @param  FormatString    A Null-terminated Unicode format string.
  @param  Marker          VA_LIST marker for the variable argument list.
  
  @return The number of Unicode characters in the produced output buffer not including the
          Null-terminator.

**/
UINTN
EFIAPI
UnicodeVSPrint (
  OUT CHAR16        *StartOfBuffer,
  IN  UINTN         BufferSize,
  IN  CONST CHAR16  *FormatString,
  IN  VA_LIST       Marker
  )
{
  ASSERT_UNICODE_BUFFER (StartOfBuffer);
  ASSERT_UNICODE_BUFFER (FormatString);
  return BasePrintLibSPrintMarker ((CHAR8 *)StartOfBuffer, BufferSize >> 1, FORMAT_UNICODE | OUTPUT_UNICODE, (CHAR8 *)FormatString, Marker, NULL);
}

 

BasePrintLibSPrintMarker 函数在 \MdePkg\Library\BasePrintLib\PrintLib.c

/**
  Worker function that produces a Null-terminated string in an output buffer 
  based on a Null-terminated format string and a VA_LIST argument list.

  VSPrint function to process format and place the results in Buffer. Since a 
  VA_LIST is used this routine allows the nesting of Vararg routines. Thus 
  this is the main print working routine.

  If COUNT_ONLY_NO_PRINT is set in Flags, Buffer will not be modified at all.

  @param[out] Buffer          The character buffer to print the results of the 
                              parsing of Format into.
  @param[in]  BufferSize      The maximum number of characters to put into 
                              buffer.
  @param[in]  Flags           Initial flags value.
                              Can only have FORMAT_UNICODE, OUTPUT_UNICODE, 
                              and COUNT_ONLY_NO_PRINT set.
  @param[in]  Format          A Null-terminated format string.
  @param[in]  VaListMarker    VA_LIST style variable argument list consumed by
                              processing Format.
  @param[in]  BaseListMarker  BASE_LIST style variable argument list consumed
                              by processing Format.

  @return The number of characters printed not including the Null-terminator.
          If COUNT_ONLY_NO_PRINT was set returns the same, but without any
          modification to Buffer.

**/
UINTN
BasePrintLibSPrintMarker (
  OUT CHAR8        *Buffer,
  IN  UINTN        BufferSize,
  IN  UINTN        Flags,
  IN  CONST CHAR8  *Format,
  IN  VA_LIST      VaListMarker,   OPTIONAL
  IN  BASE_LIST    BaseListMarker  OPTIONAL
  )

 

处理 %r 的代码如下

      case 'r':
        if (BaseListMarker == NULL) {
          Status = VA_ARG (VaListMarker, RETURN_STATUS);
        } else {
          Status = BASE_ARG (BaseListMarker, RETURN_STATUS);
        }
        ArgumentString = ValueBuffer;
        if (RETURN_ERROR (Status)) {
          //
          // Clear error bit
          //
          Index = Status & ~MAX_BIT;
          if (Index > 0 && Index <= ERROR_STATUS_NUMBER) {
            ArgumentString = mStatusString [Index + WARNING_STATUS_NUMBER];
          }
        } else {
          Index = Status;
          if (Index <= WARNING_STATUS_NUMBER) {
            ArgumentString = mStatusString [Index];
          }
        }
        if (ArgumentString == ValueBuffer) {
          BasePrintLibSPrint ((CHAR8 *) ValueBuffer, MAXIMUM_VALUE_CHARACTERS, 0, "%08X", Status);
        }
        break;

 

核心就是查 mStatusString 表,在 \MdePkg\Library\BasePrintLib\PrintLibInternal.c 中有定义


GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 *mStatusString[] = {
  "Success",                      //  RETURN_SUCCESS                = 0
  "Warning Unknown Glyph",        //  RETURN_WARN_UNKNOWN_GLYPH     = 1
  "Warning Delete Failure",       //  RETURN_WARN_DELETE_FAILURE    = 2
  "Warning Write Failure",        //  RETURN_WARN_WRITE_FAILURE     = 3
  "Warning Buffer Too Small",     //  RETURN_WARN_BUFFER_TOO_SMALL  = 4
  "Warning Stale Data",           //  RETURN_WARN_STALE_DATA        = 5
  "Load Error",                   //  RETURN_LOAD_ERROR             = 1  | MAX_BIT
  "Invalid Parameter",            //  RETURN_INVALID_PARAMETER      = 2  | MAX_BIT
  "Unsupported",                  //  RETURN_UNSUPPORTED            = 3  | MAX_BIT
  "Bad Buffer Size",              //  RETURN_BAD_BUFFER_SIZE        = 4  | MAX_BIT
  "Buffer Too Small",             //  RETURN_BUFFER_TOO_SMALL,      = 5  | MAX_BIT
  "Not Ready",                    //  RETURN_NOT_READY              = 6  | MAX_BIT
  "Device Error",                 //  RETURN_DEVICE_ERROR           = 7  | MAX_BIT
  "Write Protected",              //  RETURN_WRITE_PROTECTED        = 8  | MAX_BIT
  "Out of Resources",             //  RETURN_OUT_OF_RESOURCES       = 9  | MAX_BIT
  "Volume Corrupt",               //  RETURN_VOLUME_CORRUPTED       = 10 | MAX_BIT
  "Volume Full",                  //  RETURN_VOLUME_FULL            = 11 | MAX_BIT
  "No Media",                     //  RETURN_NO_MEDIA               = 12 | MAX_BIT
  "Media changed",                //  RETURN_MEDIA_CHANGED          = 13 | MAX_BIT
  "Not Found",                    //  RETURN_NOT_FOUND              = 14 | MAX_BIT
  "Access Denied",                //  RETURN_ACCESS_DENIED          = 15 | MAX_BIT
  "No Response",                  //  RETURN_NO_RESPONSE            = 16 | MAX_BIT
  "No mapping",                   //  RETURN_NO_MAPPING             = 17 | MAX_BIT
  "Time out",                     //  RETURN_TIMEOUT                = 18 | MAX_BIT
  "Not started",                  //  RETURN_NOT_STARTED            = 19 | MAX_BIT
  "Already started",              //  RETURN_ALREADY_STARTED        = 20 | MAX_BIT
  "Aborted",                      //  RETURN_ABORTED                = 21 | MAX_BIT
  "ICMP Error",                   //  RETURN_ICMP_ERROR             = 22 | MAX_BIT
  "TFTP Error",                   //  RETURN_TFTP_ERROR             = 23 | MAX_BIT
  "Protocol Error",               //  RETURN_PROTOCOL_ERROR         = 24 | MAX_BIT
  "Incompatible Version",         //  RETURN_INCOMPATIBLE_VERSION   = 25 | MAX_BIT
  "Security Violation",           //  RETURN_SECURITY_VIOLATION     = 26 | MAX_BIT
  "CRC Error",                    //  RETURN_CRC_ERROR              = 27 | MAX_BIT
  "End of Media",                 //  RETURN_END_OF_MEDIA           = 28 | MAX_BIT
  "Reserved (29)",                //  RESERVED                      = 29 | MAX_BIT
  "Reserved (30)",                //  RESERVED                      = 30 | MAX_BIT
  "End of File",                  //  RETURN_END_OF_FILE            = 31 | MAX_BIT
  "Invalid Language",             //  RETURN_INVALID_LANGUAGE       = 32 | MAX_BIT
  "Compromised Data"              //  RETURN_COMPROMISED_DATA       = 33 | MAX_BIT
};

 

具体的实现就是这样。

Step to UEFI (63) —– 常用的字符串函数(下)

继续介绍 EFI 下面的常用字符串函数

\MdePkg\Include\Library\BaseLib.h

1.StrStr 函数作用:在字符串中查找另外的字符串


/**
  Returns the first occurrence of a Null-terminated Unicode sub-string
  in a Null-terminated Unicode string.

  This function scans the contents of the Null-terminated Unicode string
  specified by String and returns the first occurrence of SearchString.
  If SearchString is not found in String, then NULL is returned.  If
  the length of SearchString is zero, then String is returned.

  If String is NULL, then ASSERT().
  If String is not aligned on a 16-bit boundary, then ASSERT().
  If SearchString is NULL, then ASSERT().
  If SearchString is not aligned on a 16-bit boundary, then ASSERT().

  If PcdMaximumUnicodeStringLength is not zero, and SearchString
  or String contains more than PcdMaximumUnicodeStringLength Unicode
  characters, not including the Null-terminator, then ASSERT().

  @param  String          The pointer to a Null-terminated Unicode string.
  @param  SearchString    The pointer to a Null-terminated Unicode string to search for.

  @retval NULL            If the SearchString does not appear in String.
  @return others          If there is a match.

**/
CHAR16 *
EFIAPI
StrStr (
  IN      CONST CHAR16              *String,
  IN      CONST CHAR16              *SearchString
  );

 

实例:

#include  <Uefi.h>
#include  <Library/UefiLib.h>
#include  <Library/ShellCEntryLib.h>


extern EFI_BOOT_SERVICES         *gBS;
extern EFI_SYSTEM_TABLE			 *gST;
extern EFI_RUNTIME_SERVICES 	 *gRT;

int
EFIAPI
main (
  IN int Argc,
  IN CHAR16 **Argv
  )
{
  CHAR16 *s1=L"WWW.";
  CHAR16 *s2=L"COM";  
  CHAR16 *s3=L"com";    
  CHAR16 s4[40]=L"LAB-Z.COM";
  CHAR16 *Result;
  
  Result=StrStr(s4,s1);
  Print(L"%s\n",Result);

  Result=StrStr(s4,s2);
  Print(L"%s\n",Result);

  Result=StrStr(s4,s3);
  Print(L"%s\n",Result);

  return EFI_SUCCESS;
}

 

运行结果

strtesta

2.StrDecimalToUintn 作用:把字符串转换为数字

/**
  Convert a Null-terminated Unicode decimal string to a value of
  type UINTN.

  This function returns a value of type UINTN by interpreting the contents
  of the Unicode string specified by String as a decimal number. The format
  of the input Unicode string String is:

                  [spaces] [decimal digits].

  The valid decimal digit character is in the range [0-9]. The
  function will ignore the pad space, which includes spaces or
  tab characters, before [decimal digits]. The running zero in the
  beginning of [decimal digits] will be ignored. Then, the function
  stops at the first character that is a not a valid decimal character
  or a Null-terminator, whichever one comes first.

  If String is NULL, then ASSERT().
  If String is not aligned in a 16-bit boundary, then ASSERT().
  If String has only pad spaces, then 0 is returned.
  If String has no pad spaces or valid decimal digits,
  then 0 is returned.
  If the number represented by String overflows according
  to the range defined by UINTN, then ASSERT().

  If PcdMaximumUnicodeStringLength is not zero, and String contains
  more than PcdMaximumUnicodeStringLength Unicode characters not including
  the Null-terminator, then ASSERT().

  @param  String      The pointer to a Null-terminated Unicode string.

  @retval Value translated from String.

**/
UINTN
EFIAPI
StrDecimalToUintn (
  IN      CONST CHAR16              *String
  );

 

实例代码:

#include  <Uefi.h>
#include  <Library/UefiLib.h>
#include  <Library/ShellCEntryLib.h>


extern EFI_BOOT_SERVICES         *gBS;
extern EFI_SYSTEM_TABLE			 *gST;
extern EFI_RUNTIME_SERVICES 	 *gRT;

int
EFIAPI
main (
  IN int Argc,
  IN CHAR16 **Argv
  )
{
  CHAR16 *s1=L"100";
  CHAR16 *s2=L"77F";  
  CHAR16 *s3=L"77f";    
  CHAR16 *s4=L"77z";      
  UINTN Result;
  
  Result=StrDecimalToUintn(s1);
  Print(L"%d\n",Result);

  Result=StrDecimalToUintn(s2);
  Print(L"%d\n",Result);

  Result=StrDecimalToUintn(s3);
  Print(L"%d\n",Result);

  Result=StrDecimalToUintn(s4);
  Print(L"%d\n",Result);
  
  return EFI_SUCCESS;
}

 

运行结果:

strtestb

具体实现的代码可以在下面找到:

\MdePkg\Library\BaseLib\String.c

 while (InternalIsDecimalDigitCharacter (*String)) {
    //
    // If the number represented by String overflows according 
    // to the range defined by UINTN, then ASSERT().
    //
    ASSERT (Result <= ((((UINTN) ~0) - (*String - L'0')) / 10));

    Result = Result * 10 + (*String - L'0');
    String++;
  }


/**
  Check if a Unicode character is a decimal character.

  This internal function checks if a Unicode character is a 
  decimal character. The valid decimal character is from
  L'0' to L'9'.

  @param  Char  The character to check against.

  @retval TRUE  If the Char is a decmial character.
  @retval FALSE If the Char is not a decmial character.

**/
BOOLEAN
EFIAPI
InternalIsDecimalDigitCharacter (
  IN      CHAR16                    Char
  )
{
  return (BOOLEAN) (Char >= L'0' && Char <= L'9');
}

 

从上面可以看到:最后一个字符会被忽略,所以你写 77f 或者 77z都能得到同样的结果

再测试一下具体取值的大小

#include  <Uefi.h>
#include  <Library/UefiLib.h>
#include  <Library/ShellCEntryLib.h>


extern EFI_BOOT_SERVICES         *gBS;
extern EFI_SYSTEM_TABLE			 *gST;
extern EFI_RUNTIME_SERVICES 	 *gRT;

int
EFIAPI
main (
  IN int Argc,
  IN CHAR16 **Argv
  )
{
  CHAR16 *s1=L"100000000";
  CHAR16 *s2=L"987654321Z";  
  CHAR16 *s3=L"2147483647";   // == 7FFFFFFF
  CHAR16 *s4=L"2147483648";   // == 80000000
  CHAR16 *s5=L"-1";    
  UINTN Result;
  
  Result=StrDecimalToUintn(s1);
  Print(L"%d\n",Result);

  Result=StrDecimalToUintn(s2);
  Print(L"%d\n",Result);

  Result=StrDecimalToUintn(s3);
  Print(L"%d\n",Result);

  Result=StrDecimalToUintn(s4);
  Print(L"%d\n",Result);
  Result=StrDecimalToUintn(s5);
  Print(L"%d\n",Result);
  
  return EFI_SUCCESS;
}

 

运行结果

strtestc

3.StrDecimalToUint64 函数用途:将字符串转换为数值,和前面的函数相比,可用范围更大

/**
  Convert a Null-terminated Unicode decimal string to a value of
  type UINT64.

  This function returns a value of type UINT64 by interpreting the contents
  of the Unicode string specified by String as a decimal number. The format
  of the input Unicode string String is:

                  [spaces] [decimal digits].

  The valid decimal digit character is in the range [0-9]. The
  function will ignore the pad space, which includes spaces or
  tab characters, before [decimal digits]. The running zero in the
  beginning of [decimal digits] will be ignored. Then, the function
  stops at the first character that is a not a valid decimal character
  or a Null-terminator, whichever one comes first.

  If String is NULL, then ASSERT().
  If String is not aligned in a 16-bit boundary, then ASSERT().
  If String has only pad spaces, then 0 is returned.
  If String has no pad spaces or valid decimal digits,
  then 0 is returned.
  If the number represented by String overflows according
  to the range defined by UINT64, then ASSERT().

  If PcdMaximumUnicodeStringLength is not zero, and String contains
  more than PcdMaximumUnicodeStringLength Unicode characters not including
  the Null-terminator, then ASSERT().

  @param  String          The pointer to a Null-terminated Unicode string.

  @retval Value translated from String.

**/
UINT64
EFIAPI
StrDecimalToUint64 (
  IN      CONST CHAR16              *String
  );

 

实例代码:

#include  <Uefi.h>
#include  <Library/UefiLib.h>
#include  <Library/ShellCEntryLib.h>


extern EFI_BOOT_SERVICES         *gBS;
extern EFI_SYSTEM_TABLE			 *gST;
extern EFI_RUNTIME_SERVICES 	 *gRT;

int
EFIAPI
main (
  IN int Argc,
  IN CHAR16 **Argv
  )
{
  CHAR16 *s1=L"100000000";
  CHAR16 *s2=L"9876543210000Z";  
  CHAR16 *s3=L"2147483647";   // == 7FFFFFFF
  CHAR16 *s4=L"2147483648";   // == 80000000
  CHAR16 *s5=L"-1";    
  UINT64 Result;
  
  Result=StrDecimalToUint64(s1);
  Print(L"%ld\n",Result);

  Result=StrDecimalToUint64(s2);
  Print(L"\n%Ld\n",Result);
  Result=StrDecimalToUint64(s2);
  Print(L"%LX\n\n",Result);

  
  Result=StrDecimalToUint64(s3);
  Print(L"%Ld\n",Result);

  Result=StrDecimalToUint64(s4);
  Print(L"%Ld\n",Result);
  
  Result=StrDecimalToUint64(s5);
  Print(L"%Ld\n",Result);
  
  return EFI_SUCCESS;
}

 

运行结果:
strtestd

4.StrHexToUintn 函数作用:将字符串按照十六进制处理转换为数值

/**
  Convert a Null-terminated Unicode hexadecimal string to a value of type UINTN.

  This function returns a value of type UINTN by interpreting the contents
  of the Unicode string specified by String as a hexadecimal number.
  The format of the input Unicode string String is:

                  [spaces][zeros][x][hexadecimal digits].

  The valid hexadecimal digit character is in the range [0-9], [a-f] and [A-F].
  The prefix "0x" is optional. Both "x" and "X" is allowed in "0x" prefix.
  If "x" appears in the input string, it must be prefixed with at least one 0.
  The function will ignore the pad space, which includes spaces or tab characters,
  before [zeros], [x] or [hexadecimal digit]. The running zero before [x] or
  [hexadecimal digit] will be ignored. Then, the decoding starts after [x] or the
  first valid hexadecimal digit. Then, the function stops at the first character 
  that is a not a valid hexadecimal character or NULL, whichever one comes first.

  If String is NULL, then ASSERT().
  If String is not aligned in a 16-bit boundary, then ASSERT().
  If String has only pad spaces, then zero is returned.
  If String has no leading pad spaces, leading zeros or valid hexadecimal digits,
  then zero is returned.
  If the number represented by String overflows according to the range defined by
  UINTN, then ASSERT().

  If PcdMaximumUnicodeStringLength is not zero, and String contains more than
  PcdMaximumUnicodeStringLength Unicode characters not including the Null-terminator,
  then ASSERT().

  @param  String          The pointer to a Null-terminated Unicode string.

  @retval Value translated from String.

**/
UINTN
EFIAPI
StrHexToUintn (
  IN      CONST CHAR16              *String
  );

 

示例代码:

#include  <Uefi.h>
#include  <Library/UefiLib.h>
#include  <Library/ShellCEntryLib.h>


extern EFI_BOOT_SERVICES         *gBS;
extern EFI_SYSTEM_TABLE			 *gST;
extern EFI_RUNTIME_SERVICES 	 *gRT;

int
EFIAPI
main (
  IN int Argc,
  IN CHAR16 **Argv
  )
{
  CHAR16 *s1=L"0x234";
  CHAR16 *s2=L"1024";  
  UINTN Result;
  
  Result=StrHexToUintn(s1);
  Print(L"%d\n",Result);

  Result=StrHexToUintn(s2);
  Print(L"%d\n",Result);
  
  return EFI_SUCCESS;
}

 

运行结果
strteste

5.StrHexToUint64 函数作用:把字符串按照十六进制处理转化为数值

/**
  Convert a Null-terminated Unicode hexadecimal string to a value of type UINT64.

  This function returns a value of type UINT64 by interpreting the contents
  of the Unicode string specified by String as a hexadecimal number.
  The format of the input Unicode string String is

                  [spaces][zeros][x][hexadecimal digits].

  The valid hexadecimal digit character is in the range [0-9], [a-f] and [A-F].
  The prefix "0x" is optional. Both "x" and "X" is allowed in "0x" prefix.
  If "x" appears in the input string, it must be prefixed with at least one 0.
  The function will ignore the pad space, which includes spaces or tab characters,
  before [zeros], [x] or [hexadecimal digit]. The running zero before [x] or
  [hexadecimal digit] will be ignored. Then, the decoding starts after [x] or the
  first valid hexadecimal digit. Then, the function stops at the first character that is
  a not a valid hexadecimal character or NULL, whichever one comes first.

  If String is NULL, then ASSERT().
  If String is not aligned in a 16-bit boundary, then ASSERT().
  If String has only pad spaces, then zero is returned.
  If String has no leading pad spaces, leading zeros or valid hexadecimal digits,
  then zero is returned.
  If the number represented by String overflows according to the range defined by
  UINT64, then ASSERT().

  If PcdMaximumUnicodeStringLength is not zero, and String contains more than
  PcdMaximumUnicodeStringLength Unicode characters not including the Null-terminator,
  then ASSERT().

  @param  String          The pointer to a Null-terminated Unicode string.

  @retval Value translated from String.

**/
UINT64
EFIAPI
StrHexToUint64 (
  IN      CONST CHAR16             *String
  );

 

示例代码:

#include  <Uefi.h>
#include  <Library/UefiLib.h>
#include  <Library/ShellCEntryLib.h>


extern EFI_BOOT_SERVICES         *gBS;
extern EFI_SYSTEM_TABLE			 *gST;
extern EFI_RUNTIME_SERVICES 	 *gRT;

int
EFIAPI
main (
  IN int Argc,
  IN CHAR16 **Argv
  )
{
  CHAR16 *s1=L"0x234";
  CHAR16 *s2=L"0xFFFFFFFFFFFFFFFF";  
  UINT64 Result;
  
  Result=StrHexToUint64(s1);
  Print(L"%ld\n",Result);

  Result=StrHexToUint64(s2);
  Print(L"%ld\n",Result);
  
  return EFI_SUCCESS;
}

 

运行结果:

strtestf

6.UnicodeStrToAsciiStr 函数作用:将Unicode的字符串转换为 ASCII的字符串

/**
  Convert a Null-terminated Unicode string to a Null-terminated
  ASCII string and returns the ASCII string.

  This function converts the content of the Unicode string Source
  to the ASCII string Destination by copying the lower 8 bits of
  each Unicode character. It returns Destination.

  The caller is responsible to make sure Destination points to a buffer with size
  equal or greater than ((StrLen (Source) + 1) * sizeof (CHAR8)) in bytes.

  If any Unicode characters in Source contain non-zero value in
  the upper 8 bits, then ASSERT().

  If Destination is NULL, then ASSERT().
  If Source is NULL, then ASSERT().
  If Source is not aligned on a 16-bit boundary, then ASSERT().
  If Source and Destination overlap, then ASSERT().

  If PcdMaximumUnicodeStringLength is not zero, and Source contains
  more than PcdMaximumUnicodeStringLength Unicode characters not including
  the Null-terminator, then ASSERT().

  If PcdMaximumAsciiStringLength is not zero, and Source contains more
  than PcdMaximumAsciiStringLength Unicode characters not including the
  Null-terminator, then ASSERT().

  @param  Source        The pointer to a Null-terminated Unicode string.
  @param  Destination   The pointer to a Null-terminated ASCII string.

  @return Destination.

**/
CHAR8 *
EFIAPI
UnicodeStrToAsciiStr (
  IN      CONST CHAR16              *Source,
  OUT     CHAR8                     *Destination
  );

 

示例代码

#include  <Uefi.h>
#include  <Library/UefiLib.h>
#include  <Library/ShellCEntryLib.h>


extern EFI_BOOT_SERVICES         *gBS;
extern EFI_SYSTEM_TABLE			 *gST;
extern EFI_RUNTIME_SERVICES 	 *gRT;

int
EFIAPI
main (
  IN int Argc,
  IN CHAR16 **Argv
  )
{
  CHAR16 *s1=L"www.lab-z.com";
  CHAR8  *s2="              ";  
  CHAR8 *Result;
  
  Result=UnicodeStrToAsciiStr(s1,s2);
  Print(L"%a\n",s2);
  Print(L"%a\n",Result);
  
  return EFI_SUCCESS;
}

 

运行结果

strtestg

7.AsciiStrToUnicodeStr 函数作用:将 ASCII的字符串转换为 Unicode的字符串

/**
  Convert one Null-terminated ASCII string to a Null-terminated
  Unicode string and returns the Unicode string.

  This function converts the contents of the ASCII string Source to the Unicode
  string Destination, and returns Destination.  The function terminates the
  Unicode string Destination by appending a Null-terminator character at the end.
  The caller is responsible to make sure Destination points to a buffer with size
  equal or greater than ((AsciiStrLen (Source) + 1) * sizeof (CHAR16)) in bytes.

  If Destination is NULL, then ASSERT().
  If Destination is not aligned on a 16-bit boundary, then ASSERT().
  If Source is NULL, then ASSERT().
  If Source and Destination overlap, then ASSERT().
  If PcdMaximumAsciiStringLength is not zero, and Source contains more than
  PcdMaximumAsciiStringLength ASCII characters not including the Null-terminator,
  then ASSERT().
  If PcdMaximumUnicodeStringLength is not zero, and Source contains more than
  PcdMaximumUnicodeStringLength ASCII characters not including the
  Null-terminator, then ASSERT().

  @param  Source        The pointer to a Null-terminated ASCII string.
  @param  Destination   The pointer to a Null-terminated Unicode string.

  @return Destination.

**/
CHAR16 *
EFIAPI
AsciiStrToUnicodeStr (
  IN      CONST CHAR8               *Source,
  OUT     CHAR16                    *Destination
  );

 

示例代码:

#include  <Uefi.h>
#include  <Library/UefiLib.h>
#include  <Library/ShellCEntryLib.h>


extern EFI_BOOT_SERVICES         *gBS;
extern EFI_SYSTEM_TABLE			 *gST;
extern EFI_RUNTIME_SERVICES 	 *gRT;

int
EFIAPI
main (
  IN int Argc,
  IN CHAR16 **Argv
  )
{
  CHAR8  *s1="www.lab-z.com";
  CHAR16 *s2=L"             ";  
  CHAR16 *Result;
  
  Result=AsciiStrToUnicodeStr (s1,s2);
  Print(L"%s\n",s2);
  Print(L"%s\n",Result);
  
  return EFI_SUCCESS;
}

 

运行结果和前面的相同。

Step to UEFI (62) —– 常用的字符串函数(上)

这里介绍一下常用的处理字符串的函数。这篇介绍 StrCpy/StrnCpy StrSize StrLen StrCmp/StrnCmp StrCat/StrnCat 。这些函数都是给 Unicode16 字符串设计的( CHAR16 定义的, 或者 L“www.lab-z.com” 这样定义的)。同样还有一组带有 Ascii 前缀的函数是给普通的字符串使用的。

函数定义原型可以在 \MdePkg\Include\Library\BaseLib.h 这个文件中找到

1.StrCpy (D<-S) 作用:将 Source 定义的字符串拷贝到 Destination 定义的字符串中(覆盖之)

//
// String Services
//

/**
  Copies one Null-terminated Unicode string to another Null-terminated Unicode
  string and returns the new Unicode string.

  This function copies the contents of the Unicode string Source to the Unicode
  string Destination, and returns Destination. If Source and Destination
  overlap, then the results are undefined.

  If Destination is NULL, then ASSERT().
  If Destination is not aligned on a 16-bit boundary, then ASSERT().
  If Source is NULL, then ASSERT().
  If Source is not aligned on a 16-bit boundary, then ASSERT().
  If Source and Destination overlap, then ASSERT().
  If PcdMaximumUnicodeStringLength is not zero, and Source contains more than
  PcdMaximumUnicodeStringLength Unicode characters not including the
  Null-terminator, then ASSERT().

  @param  Destination The pointer to a Null-terminated Unicode string.
  @param  Source      The pointer to a Null-terminated Unicode string.

  @return Destination.

**/
CHAR16 *
EFIAPI
StrCpy (
  OUT     CHAR16                    *Destination,
  IN      CONST CHAR16              *Source
  );

 

实例:

#include  <Uefi.h>
#include  <Library/UefiLib.h>
#include  <Library/ShellCEntryLib.h>


extern EFI_BOOT_SERVICES         *gBS;
extern EFI_SYSTEM_TABLE			 *gST;
extern EFI_RUNTIME_SERVICES 	 *gRT;

int
EFIAPI
main (
  IN int Argc,
  IN CHAR16 **Argv
  )
{

  CHAR16 *s1=L"WWW.";
  CHAR16 *s2=L".LAB-Z.COM";
  CHAR16 *Result;
  
  Result=StrCpy(s1,s2);
  Print(L"%s\n",s1);  
  Print(L"%s\n",Result);

  return EFI_SUCCESS;
}

 

strtest1

换一种字符串定义方式

#include  <Uefi.h>
#include  <Library/UefiLib.h>
#include  <Library/ShellCEntryLib.h>


extern EFI_BOOT_SERVICES         *gBS;
extern EFI_SYSTEM_TABLE			 *gST;
extern EFI_RUNTIME_SERVICES 	 *gRT;

int
EFIAPI
main (
  IN int Argc,
  IN CHAR16 **Argv
  )
{

  CHAR16 s1[20]=L"WWW.";
  CHAR16 s2[20]=L".LAB-Z.COM";
  CHAR16 *Result;
  
  Result=StrCpy(s1,s2);
  Print(L"%s\n",s1);  
  Print(L"%s\n",Result);

  return EFI_SUCCESS;
}

 

运行结果和上面的相同。

2.StrnCpy 作用:将 Source 定义的字符串中,前n个拷贝到 Destination 定义的字符串中(覆盖之)

/**
  Copies up to a specified length from one Null-terminated Unicode string to 
  another Null-terminated Unicode string and returns the new Unicode string.

  This function copies the contents of the Unicode string Source to the Unicode
  string Destination, and returns Destination. At most, Length Unicode
  characters are copied from Source to Destination. If Length is 0, then
  Destination is returned unmodified. If Length is greater that the number of
  Unicode characters in Source, then Destination is padded with Null Unicode
  characters. If Source and Destination overlap, then the results are
  undefined.

  If Length > 0 and Destination is NULL, then ASSERT().
  If Length > 0 and Destination is not aligned on a 16-bit boundary, then ASSERT().
  If Length > 0 and Source is NULL, then ASSERT().
  If Length > 0 and Source is not aligned on a 16-bit boundary, then ASSERT().
  If Source and Destination overlap, then ASSERT().
  If PcdMaximumUnicodeStringLength is not zero, and Length is greater than 
  PcdMaximumUnicodeStringLength, then ASSERT().
  If PcdMaximumUnicodeStringLength is not zero, and Source contains more than
  PcdMaximumUnicodeStringLength Unicode characters, not including the Null-terminator,
  then ASSERT().

  @param  Destination The pointer to a Null-terminated Unicode string.
  @param  Source      The pointer to a Null-terminated Unicode string.
  @param  Length      The maximum number of Unicode characters to copy.

  @return Destination.

**/
CHAR16 *
EFIAPI
StrnCpy (
  OUT     CHAR16                    *Destination,
  IN      CONST CHAR16              *Source,
  IN      UINTN                     Length
  );

 

实例:

#include  <Uefi.h>
#include  <Library/UefiLib.h>
#include  <Library/ShellCEntryLib.h>


extern EFI_BOOT_SERVICES         *gBS;
extern EFI_SYSTEM_TABLE			 *gST;
extern EFI_RUNTIME_SERVICES 	 *gRT;

int
EFIAPI
main (
  IN int Argc,
  IN CHAR16 **Argv
  )
{
  CHAR16 *s1=L"WWW.";
  CHAR16 *s2=L".LAB-Z.COM";
  CHAR16 *Result;
  
  Result=StrnCpy(s1,s2,4);
  Print(L"%s\n",s1);  
  Print(L"%s\n",Result);

  return EFI_SUCCESS;
}

 

strtest2

3.StrLen 作用:返回字符串中字符的个数,注意:数量不包括结尾的 NULL。

/**
  Returns the length of a Null-terminated Unicode string.

  This function returns the number of Unicode characters in the Null-terminated
  Unicode string specified by String.

  If String is NULL, then ASSERT().
  If String is not aligned on a 16-bit boundary, then ASSERT().
  If PcdMaximumUnicodeStringLength is not zero, and String contains more than
  PcdMaximumUnicodeStringLength Unicode characters not including the
  Null-terminator, then ASSERT().

  @param  String  Pointer to a Null-terminated Unicode string.

  @return The length of String.

**/
UINTN
EFIAPI
StrLen (
  IN      CONST CHAR16              *String
  );

 

实例:

#include  <Uefi.h>
#include  <Library/UefiLib.h>
#include  <Library/ShellCEntryLib.h>


extern EFI_BOOT_SERVICES         *gBS;
extern EFI_SYSTEM_TABLE			 *gST;
extern EFI_RUNTIME_SERVICES 	 *gRT;

int
EFIAPI
main (
  IN int Argc,
  IN CHAR16 **Argv
  )
{
  CHAR16 *s1=L"WWW.";
  CHAR16 s2[20]=L".LAB-Z.COM";
  UINTN Result;
  
  Result=StrLen(s1);
  Print(L"%d\n",Result);

  Result=StrLen(s2);
  Print(L"%d\n",Result);
  
  return EFI_SUCCESS;
}

 

运行结果

strtest3

4. StrSize 作用:返回字符串占用的内存字节数,注意:包括 NULL。

/**
  Returns the size of a Null-terminated Unicode string in bytes, including the
  Null terminator.

  This function returns the size, in bytes, of the Null-terminated Unicode string 
  specified by String.

  If String is NULL, then ASSERT().
  If String is not aligned on a 16-bit boundary, then ASSERT().
  If PcdMaximumUnicodeStringLength is not zero, and String contains more than
  PcdMaximumUnicodeStringLength Unicode characters not including the
  Null-terminator, then ASSERT().

  @param  String  The pointer to a Null-terminated Unicode string.

  @return The size of String.

**/
UINTN
EFIAPI
StrSize (
  IN      CONST CHAR16              *String
  );

 

实例:

#include  <Uefi.h>
#include  <Library/UefiLib.h>
#include  <Library/ShellCEntryLib.h>


extern EFI_BOOT_SERVICES         *gBS;
extern EFI_SYSTEM_TABLE		 *gST;
extern EFI_RUNTIME_SERVICES 	 *gRT;

int
EFIAPI
main (
  IN int Argc,
  IN CHAR16 **Argv
  )
{
  CHAR16 *s1=L"WWW";
  CHAR16 s2[40]=L"LAB-Z.COM";
  UINTN Result;
  
  Result=StrSize(s1);
  Print(L"%d\n",Result);

  Result=StrSize(s2);
  Print(L"%d\n",Result);
  
  return EFI_SUCCESS;
}

 

运行结果

strtest4

定义的字符串实际上是: “www\0” ,每个字符都是 CHAR16, 算下来需要占用 8个字节。

5. StrCmp 作用:比较字符串是否相同。相同的话返回 0

/**
  Compares two Null-terminated Unicode strings, and returns the difference
  between the first mismatched Unicode characters.

  This function compares the Null-terminated Unicode string FirstString to the
  Null-terminated Unicode string SecondString. If FirstString is identical to
  SecondString, then 0 is returned. Otherwise, the value returned is the first
  mismatched Unicode character in SecondString subtracted from the first
  mismatched Unicode character in FirstString.

  If FirstString is NULL, then ASSERT().
  If FirstString is not aligned on a 16-bit boundary, then ASSERT().
  If SecondString is NULL, then ASSERT().
  If SecondString is not aligned on a 16-bit boundary, then ASSERT().
  If PcdMaximumUnicodeStringLength is not zero, and FirstString contains more
  than PcdMaximumUnicodeStringLength Unicode characters not including the
  Null-terminator, then ASSERT().
  If PcdMaximumUnicodeStringLength is not zero, and SecondString contains more
  than PcdMaximumUnicodeStringLength Unicode characters, not including the
  Null-terminator, then ASSERT().

  @param  FirstString   The pointer to a Null-terminated Unicode string.
  @param  SecondString  The pointer to a Null-terminated Unicode string.

  @retval 0      FirstString is identical to SecondString.
  @return others FirstString is not identical to SecondString.

**/
INTN
EFIAPI
StrCmp (
  IN      CONST CHAR16              *FirstString,
  IN      CONST CHAR16              *SecondString
  );

 

实例代码:

#include  <Uefi.h>
#include  <Library/UefiLib.h>
#include  <Library/ShellCEntryLib.h>


extern EFI_BOOT_SERVICES         *gBS;
extern EFI_SYSTEM_TABLE			 *gST;
extern EFI_RUNTIME_SERVICES 	 *gRT;

int
EFIAPI
main (
  IN int Argc,
  IN CHAR16 **Argv
  )
{
  CHAR16 *s1=L"WWW";
  CHAR16 s2[40]=L"LAB-Z.COM";
  CHAR16 s3[40]=L"LAB-Z";
  CHAR16 s4[40]=L"MAB-Z";  
  UINTN Result;
  
  Result=StrCmp(s1,s2);
  Print(L"%d\n",Result);

  Result=StrCmp(s2,s3);
  Print(L"%d\n",Result);

  Result=StrCmp(s3,s4);
  Print(L"%d\n",Result);
  
  return EFI_SUCCESS;
}

 

运行结果:

strtest5

6. StrnCmp 作用:和上面的比较函数类似,只是这个函数只比较指定的前n个字符

/**
  Compares up to a specified length the contents of two Null-terminated Unicode strings,
  and returns the difference between the first mismatched Unicode characters.
  
  This function compares the Null-terminated Unicode string FirstString to the
  Null-terminated Unicode string SecondString. At most, Length Unicode
  characters will be compared. If Length is 0, then 0 is returned. If
  FirstString is identical to SecondString, then 0 is returned. Otherwise, the
  value returned is the first mismatched Unicode character in SecondString
  subtracted from the first mismatched Unicode character in FirstString.

  If Length > 0 and FirstString is NULL, then ASSERT().
  If Length > 0 and FirstString is not aligned on a 16-bit boundary, then ASSERT().
  If Length > 0 and SecondString is NULL, then ASSERT().
  If Length > 0 and SecondString is not aligned on a 16-bit boundary, then ASSERT().
  If PcdMaximumUnicodeStringLength is not zero, and Length is greater than
  PcdMaximumUnicodeStringLength, then ASSERT().
  If PcdMaximumUnicodeStringLength is not zero, and FirstString contains more than
  PcdMaximumUnicodeStringLength Unicode characters, not including the Null-terminator,
  then ASSERT().
  If PcdMaximumUnicodeStringLength is not zero, and SecondString contains more than
  PcdMaximumUnicodeStringLength Unicode characters, not including the Null-terminator,
  then ASSERT().

  @param  FirstString   The pointer to a Null-terminated Unicode string.
  @param  SecondString  The pointer to a Null-terminated Unicode string.
  @param  Length        The maximum number of Unicode characters to compare.

  @retval 0      FirstString is identical to SecondString.
  @return others FirstString is not identical to SecondString.

**/
INTN
EFIAPI
StrnCmp (
  IN      CONST CHAR16              *FirstString,
  IN      CONST CHAR16              *SecondString,
  IN      UINTN                     Length
  );

 

实例:

#include  <Uefi.h>
#include  <Library/UefiLib.h>
#include  <Library/ShellCEntryLib.h>


extern EFI_BOOT_SERVICES         *gBS;
extern EFI_SYSTEM_TABLE			 *gST;
extern EFI_RUNTIME_SERVICES 	 *gRT;

int
EFIAPI
main (
  IN int Argc,
  IN CHAR16 **Argv
  )
{
  CHAR16 *s1=L"WWW";
  CHAR16 s2[40]=L"LAB-Z.COM";
  CHAR16 s3[40]=L"LAB-Z";
  CHAR16 s4[40]=L"MAB-Z";  
  
  Result=StrnCmp(s1,s2,7);
  Print(L"%d\n",Result);

  Result=StrnCmp(s2,s3,5);
  Print(L"%d\n",Result);

  Result=StrnCmp(s3,s4,5);
  Print(L"%d\n",Result);
  
  return EFI_SUCCESS;
}

 

运行结果

strtest6

7. StrCat 作用:将 Source 字符串的内容拼接到 Destination 字符串上。

/**
  Concatenates one Null-terminated Unicode string to another Null-terminated
  Unicode string, and returns the concatenated Unicode string.

  This function concatenates two Null-terminated Unicode strings. The contents
  of Null-terminated Unicode string Source are concatenated to the end of
  Null-terminated Unicode string Destination. The Null-terminated concatenated
  Unicode String is returned. If Source and Destination overlap, then the
  results are undefined.

  If Destination is NULL, then ASSERT().
  If Destination is not aligned on a 16-bit boundary, then ASSERT().
  If Source is NULL, then ASSERT().
  If Source is not aligned on a 16-bit boundary, then ASSERT().
  If Source and Destination overlap, then ASSERT().
  If PcdMaximumUnicodeStringLength is not zero, and Destination contains more
  than PcdMaximumUnicodeStringLength Unicode characters, not including the
  Null-terminator, then ASSERT().
  If PcdMaximumUnicodeStringLength is not zero, and Source contains more than
  PcdMaximumUnicodeStringLength Unicode characters, not including the
  Null-terminator, then ASSERT().
  If PcdMaximumUnicodeStringLength is not zero, and concatenating Destination
  and Source results in a Unicode string with more than
  PcdMaximumUnicodeStringLength Unicode characters, not including the
  Null-terminator, then ASSERT().

  @param  Destination The pointer to a Null-terminated Unicode string.
  @param  Source      The pointer to a Null-terminated Unicode string.

  @return Destination.

**/
CHAR16 *
EFIAPI
StrCat (
  IN OUT  CHAR16                    *Destination,
  IN      CONST CHAR16              *Source
  );

 

实例:

#include  <Uefi.h>
#include  <Library/UefiLib.h>
#include  <Library/ShellCEntryLib.h>


extern EFI_BOOT_SERVICES         *gBS;
extern EFI_SYSTEM_TABLE			 *gST;
extern EFI_RUNTIME_SERVICES 	 *gRT;

int
EFIAPI
main (
  IN int Argc,
  IN CHAR16 **Argv
  )
{
  CHAR16 *s1=L"WWW.";
  CHAR16 s2[40]=L"LAB-Z.COM";
  CHAR16 *Result;
  
  Result=StrCat(s1,s2);
  Print(L"%s\n",Result);
  
  return EFI_SUCCESS;
}

 

运行结果

strtest7

8.StrnCat 作用:将 Source 字符串前面n个字符的内容拼接到 Destination 字符串上。

/**
  Concatenates up to a specified length one Null-terminated Unicode to the end 
  of another Null-terminated Unicode string, and returns the concatenated 
  Unicode string.

  This function concatenates two Null-terminated Unicode strings. The contents
  of Null-terminated Unicode string Source are concatenated to the end of
  Null-terminated Unicode string Destination, and Destination is returned. At
  most, Length Unicode characters are concatenated from Source to the end of
  Destination, and Destination is always Null-terminated. If Length is 0, then
  Destination is returned unmodified. If Source and Destination overlap, then
  the results are undefined.

  If Destination is NULL, then ASSERT().
  If Length > 0 and Destination is not aligned on a 16-bit boundary, then ASSERT().
  If Length > 0 and Source is NULL, then ASSERT().
  If Length > 0 and Source is not aligned on a 16-bit boundary, then ASSERT().
  If Source and Destination overlap, then ASSERT().
  If PcdMaximumUnicodeStringLength is not zero, and Length is greater than 
  PcdMaximumUnicodeStringLength, then ASSERT().
  If PcdMaximumUnicodeStringLength is not zero, and Destination contains more
  than PcdMaximumUnicodeStringLength Unicode characters, not including the
  Null-terminator, then ASSERT().
  If PcdMaximumUnicodeStringLength is not zero, and Source contains more than
  PcdMaximumUnicodeStringLength Unicode characters, not including the
  Null-terminator, then ASSERT().
  If PcdMaximumUnicodeStringLength is not zero, and concatenating Destination
  and Source results in a Unicode string with more than PcdMaximumUnicodeStringLength
  Unicode characters, not including the Null-terminator, then ASSERT().

  @param  Destination The pointer to a Null-terminated Unicode string.
  @param  Source      The pointer to a Null-terminated Unicode string.
  @param  Length      The maximum number of Unicode characters to concatenate from
                      Source.

  @return Destination.

**/
CHAR16 *
EFIAPI
StrnCat (
  IN OUT  CHAR16                    *Destination,
  IN      CONST CHAR16              *Source,
  IN      UINTN                     Length
  );

 

实例:

#include  <Uefi.h>
#include  <Library/UefiLib.h>
#include  <Library/ShellCEntryLib.h>


extern EFI_BOOT_SERVICES         *gBS;
extern EFI_SYSTEM_TABLE			 *gST;
extern EFI_RUNTIME_SERVICES 	 *gRT;

int
EFIAPI
main (
  IN int Argc,
  IN CHAR16 **Argv
  )
{
  CHAR16 *s1=L"WWW.";
  CHAR16 s2[40]=L"LAB-Z.COM";
  CHAR16 *Result;
  
  Result=StrnCat(s1,s2,3);
  Print(L"%s\n",Result);
  
  return EFI_SUCCESS;
}

 

运行结果

strtest9

本文参考 《UEFI 原理与编程》。

Step to UEFI (61) —– SHA-1的实现

前面介绍了 MD5 的实现,这里介绍一下 SHA-1 算法的实现。具体代码来自【参考1】。

和之前 MD5 程序有一些差别在于这个程序不是一次性将所有文件都放入内存中,而是放入一部分,计算一部分,再用中间结果继续计算下一部分。这样,再大的文件也可以正常处理。

#include  <Uefi.h>
#include  <Library/UefiLib.h>
#include  <Library/ShellCEntryLib.h>

#include  <stdio.h>
#include  <stdlib.h>
#include  <wchar.h>

#include <Protocol/EfiShell.h>
#include <Library/ShellLib.h>
#include <Library/MemoryAllocationLib.h>

#include "sha1.h"

#define BUFFERSIZE 2048

extern EFI_BOOT_SERVICES         *gBS;
extern EFI_SYSTEM_TABLE			 *gST;
extern EFI_RUNTIME_SERVICES 	 *gRT;

extern EFI_SHELL_PROTOCOL        *gEfiShellProtocol;

int
EFIAPI
main (
  IN int Argc,
  IN CHAR16 **Argv
  )
{
  EFI_FILE_HANDLE   FileHandle;
  RETURN_STATUS     Status;
  EFI_FILE_INFO     *FileInfo = NULL;
  EFI_HANDLE        *HandleBuffer=NULL;
  UINTN  			ReadSize=BUFFERSIZE;
  SHA1Context 		sha;
  
  //Check if there is a parameter
  if (Argc == 1) {
	Print(L"Usage: crctest [filename]\n");
	return 0;
  }
  
  //Open the file given by the parameter
  Status = ShellOpenFileByName(Argv[1], (SHELL_FILE_HANDLE *)&FileHandle,
                               EFI_FILE_MODE_READ , 0);

  if(Status != RETURN_SUCCESS) {
        Print(L"OpenFile failed!\n");
		return EFI_SUCCESS;
      }			

  //Get file size	  
  FileInfo = ShellGetFileInfo( (SHELL_FILE_HANDLE)FileHandle);	

  /*
   *  Reset the SHA-1 context and process input
  */
  SHA1Reset(&sha);
		
  //Allocate a memory buffer
  HandleBuffer = AllocateZeroPool(BUFFERSIZE);
  if (HandleBuffer == NULL) {
      return (SHELL_OUT_OF_RESOURCES);   }

	while (BUFFERSIZE == ReadSize)		
    {
		ReadSize=BUFFERSIZE;
		//Load the whole file to the buffer
		Status = ShellReadFile(FileHandle,&ReadSize,HandleBuffer);
		SHA1Input(&sha,(unsigned char *)  HandleBuffer, ReadSize);
   } 
  
  //Output
  Print(L"File Name: %s\n",Argv[1]);
  Print(L"File Size: %d\n",(UINTN)FileInfo-> FileSize);

  if (!SHA1Result(&sha))
        {
            Print(L"sha: could not compute message digest\n");
        }
  else
        {
            Print(L"%08X %08X %08X %08X %08X\n",
                    sha.Message_Digest[0],
                    sha.Message_Digest[1],
                    sha.Message_Digest[2],
                    sha.Message_Digest[3],
                    sha.Message_Digest[4]);
        }
  
  FreePool(HandleBuffer);	
  return EFI_SUCCESS;
}

 

运行结果:

sha-1

完整的代码下载:

sha1test

参考:

1.https://www.packetizer.com/

Step to UEFI (60) —– GUID和UUID

了解了一下 UUID 和 GUID , 资料上来看,这两个是同一个东西。GUID 是 MS 定义的 UUID 的一种实现方法. 两者在写法上稍微有些差别【参考1】【参考2】:

GUID:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx (8-4-4-4-12)

UUID:xxxxxxxx-xxxx-xxxx-xxxxxxxxxxxxxxxx (8-4-4-16)

在 UEFI 中,我们经常看到类似下面的定义

“cf8e16a5-c1e8-4e25-b712-4f54a96702c8”

#define EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID \
{ \
0x964e5b22, 0x6459, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \
}

UUID PadFileGuid;

对于 GUID ,可以在 \MdePkg\Include\Base.h 看到下面的定义

///
/// 128 bit buffer containing a unique identifier value.
/// Unless otherwise specified, aligned on a 64 bit boundary.
///
typedef struct {
  UINT32  Data1;
  UINT16  Data2;
  UINT16  Data3;
  UINT8   Data4[8];
} GUID;

 

同时,在 \MdePkg\Include\Uefi\UefiBaseType.h 有下面的定义

///
/// 128-bit buffer containing a unique identifier value.
///
typedef GUID                      EFI_GUID;

 

在 \BaseTools\Source\C\Common\CommonLib.c 有一个打印输出的例子可以直接拿出来用


EFI_STATUS
PrintGuid (
  IN EFI_GUID *Guid
  )
/*++

Routine Description:

  This function prints a GUID to STDOUT.

Arguments:

  Guid    Pointer to a GUID to print.

Returns:

  EFI_SUCCESS             The GUID was printed.
  EFI_INVALID_PARAMETER   The input was NULL.

--*/
{
  if (Guid == NULL) {
    Error (NULL, 0, 2000, "Invalid parameter", "PrintGuidToBuffer() called with a NULL value");
    return EFI_INVALID_PARAMETER;
  }

  printf (
    "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
    (unsigned) Guid->Data1,
    Guid->Data2,
    Guid->Data3,
    Guid->Data4[0],
    Guid->Data4[1],
    Guid->Data4[2],
    Guid->Data4[3],
    Guid->Data4[4],
    Guid->Data4[5],
    Guid->Data4[6],
    Guid->Data4[7]
    );
  return EFI_SUCCESS;
}

 

最后,写一个输出的例子

#include  <Uefi.h>
#include  <Library/UefiLib.h>
#include  <Library/ShellCEntryLib.h>

#include  <stdio.h>
#include  <stdlib.h>
#include  <wchar.h>

#include <Protocol/EfiShell.h>
#include <Library/ShellLib.h>


extern EFI_BOOT_SERVICES         *gBS;
extern EFI_SYSTEM_TABLE			 *gST;
extern EFI_RUNTIME_SERVICES 	 *gRT;

#define GUID1 \
  { \
    0x964e5b22, 0x6459, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \
  }

#define GUID2 \
  { \
    0x33221100, 0x5544, 0x7766, {0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF } \
  }
  
EFI_STATUS
PrintGuid (
  IN EFI_GUID *Guid
  )
  
/*++

Routine Description:

  This function prints a GUID to STDOUT.

Arguments:

  Guid    Pointer to a GUID to print.

Returns:

  EFI_SUCCESS             The GUID was printed.
  EFI_INVALID_PARAMETER   The input was NULL.

--*/
{
  if (Guid == NULL) {
	printf("Parameter error!\n");
    return EFI_INVALID_PARAMETER;
  }

  printf (
    "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
    (unsigned) Guid->Data1,
    Guid->Data2,
    Guid->Data3,
    Guid->Data4[0],
    Guid->Data4[1],
    Guid->Data4[2],
    Guid->Data4[3],
    Guid->Data4[4],
    Guid->Data4[5],
    Guid->Data4[6],
    Guid->Data4[7]
    );
  return EFI_SUCCESS;
}

int
EFIAPI
main (
  IN int Argc,
  IN CHAR16 **Argv
  )
{
  EFI_GUID T1=GUID1;
  EFI_GUID T2=GUID2;
  
  PrintGuid(&T1);
  PrintGuid(&T2);
  
  return EFI_SUCCESS;
}

 

运行结果

guid

完整代码下载

GUIDTest

参考:
1.http://baike.baidu.com/view/1052579.htm UUID
2.http://blog.csdn.net/forlong401/article/details/7580147 UUID 和 GUID 的区别
3.https://en.wikipedia.org/wiki/Globally_unique_identifier Globally unique identifier
4.https://en.wikipedia.org/wiki/Universally_unique_identifier Universally unique identifier

Step to UEFI (59) —– BMP 放在EFI文件中(上)

前面介绍了如何 Load 一幅 BMP 图片然后显示出来,然后就有一个问题:如何把这个图片也放在 EFI 文件中? 毕竟放在一起会显得更加专业。在【参考1】上,也有朋友问了同样的问题,博主的建议是“写个脚本直接把图片变成像素数组,直接弄,这样很简单”。下面就来实验一下。

首先,需要找一个将图片转为 C Header的工具。我找到的是 Bin2C 这个工具【参考2】. 用下面的命令即可完成转换,生成 show.h

bin2c -o show.h Untitled.bmp

转换之后 show.h 大概就是下面这个样子

showbmp2

然后,修改之前显示 BMP 的那个程序,用 include 来引用用到的 BMP 数据, 去掉 Load 文件的过程,直接使用内存地址。

#include  <Uefi.h>
#include  <Library/UefiLib.h>
#include  <Library/ShellCEntryLib.h>

#include  <stdio.h>
#include  <stdlib.h>
#include  <wchar.h>
#include  <time.h>
#include <Protocol/EfiShell.h>
#include <Library/ShellLib.h>

#include <Protocol/SimpleFileSystem.h>
#include <Protocol/BlockIo.h>
#include <Library/DevicePathLib.h>
#include <Library/HandleParsingLib.h>
#include <Library/SortLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/BaseMemoryLib.h>

#include <Protocol/LoadedImage.h>

#define MAX_FILE_SIZE (1024*1024*1024)

extern EFI_BOOT_SERVICES         *gBS;
extern EFI_SYSTEM_TABLE			 *gST;
extern EFI_RUNTIME_SERVICES 	 *gRT;

extern EFI_SHELL_ENVIRONMENT2    *mEfiShellEnvironment2;
extern EFI_HANDLE				 gImageHandle;

static EFI_GUID GraphicsOutputProtocolGuid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
static EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput = NULL;

#pragma pack(1)

//Copied from  C\MdePkg\Include\Protocol\UgaDraw.h
typedef struct {
  UINT8 Blue;
  UINT8 Green;
  UINT8 Red;
  UINT8 Reserved;
} EFI_UGA_PIXEL;

/* This should be compatible with EFI_UGA_PIXEL */
typedef struct {
    UINT8 b, g, r, a;
} EG_PIXEL;

typedef struct {
    CHAR8         CharB;
    CHAR8         CharM;
    UINT32        Size;
    UINT16        Reserved[2];
    UINT32        ImageOffset;
    UINT32        HeaderSize;
    UINT32        PixelWidth;
    UINT32        PixelHeight;
    UINT16        Planes;       // Must be 1
    UINT16        BitPerPixel;  // 1, 4, 8, or 24
    UINT32        CompressionType;
    UINT32        ImageSize;    // Compressed image size in bytes
    UINT32        XPixelsPerMeter;
    UINT32        YPixelsPerMeter;
    UINT32        NumberOfColors;
    UINT32        ImportantColors;
} BMP_IMAGE_HEADER;

typedef struct {
    UINTN       Width;
    UINTN       Height;
    BOOLEAN     HasAlpha;
    EG_PIXEL    *PixelData;
} EG_IMAGE;
#pragma pack()

//const unsigned char Untitled_bmp[289654] 
#include "show.h"

VOID egFreeImage(IN EG_IMAGE *Image)
{
    if (Image != NULL) {
        if (Image->PixelData != NULL)
            FreePool(Image->PixelData);
        FreePool(Image);
    }
}

//
// Basic image handling
//

EG_IMAGE * egCreateImage(IN UINTN Width, IN UINTN Height, IN BOOLEAN HasAlpha)
{
    EG_IMAGE        *NewImage;
    
    NewImage = (EG_IMAGE *) AllocatePool(sizeof(EG_IMAGE));
    if (NewImage == NULL)
        return NULL;
    NewImage->PixelData = (EG_PIXEL *) AllocatePool(
								Width * Height * sizeof(EG_PIXEL));
    if (NewImage->PixelData == NULL) {
        FreePool(NewImage);
        return NULL;
    }

    NewImage->Width = Width;
    NewImage->Height = Height;
    NewImage->HasAlpha = HasAlpha;
    return NewImage;
}

//
// Load BMP image
//

EG_IMAGE * egDecodeBMP
	(
		IN UINT8 *FileData, 
		IN UINTN FileDataLength, 
		IN BOOLEAN WantAlpha)
{
    EG_IMAGE            *NewImage;
    BMP_IMAGE_HEADER    *BmpHeader;
    EFI_UGA_PIXEL       *BmpColorMap;
    UINTN               x, y;
    UINT8               *ImagePtr;
    UINT8               *ImagePtrBase;
    UINTN               ImageLineOffset;
    UINT8               ImageValue=0, AlphaValue;
    EG_PIXEL            *PixelPtr;
    UINTN               Index, BitIndex;

    // read and check header
    if (FileDataLength < sizeof(BMP_IMAGE_HEADER) || FileData == NULL)
        return NULL;

    BmpHeader = (BMP_IMAGE_HEADER *) FileData;
    if (BmpHeader->CharB != 'B' || BmpHeader->CharM != 'M')
        return NULL;

    if (BmpHeader->CompressionType != 0)
        return NULL;

    if (BmpHeader->BitPerPixel != 1 && BmpHeader->BitPerPixel != 4 &&
        BmpHeader->BitPerPixel != 8 && BmpHeader->BitPerPixel != 24)
        return NULL;

    // calculate parameters
    ImageLineOffset = BmpHeader->PixelWidth;
    if (BmpHeader->BitPerPixel == 24)
        ImageLineOffset *= 3;
    else if (BmpHeader->BitPerPixel == 1)
        ImageLineOffset = (ImageLineOffset + 7) >> 3;
    else if (BmpHeader->BitPerPixel == 4)
        ImageLineOffset = (ImageLineOffset + 1) >> 1;
    if ((ImageLineOffset % 4) != 0)
        ImageLineOffset = ImageLineOffset + (4 - (ImageLineOffset % 4));
    // check bounds
    if (BmpHeader->ImageOffset + 
			ImageLineOffset * BmpHeader->PixelHeight > FileDataLength)
        return NULL;
    
    // allocate image structure and buffer
    NewImage = egCreateImage(BmpHeader->PixelWidth, 
								BmpHeader->PixelHeight, WantAlpha);
    if (NewImage == NULL)
        return NULL;
    AlphaValue = WantAlpha ? 255 : 0;
    
    // convert image
    BmpColorMap = (EFI_UGA_PIXEL *)(FileData + sizeof(BMP_IMAGE_HEADER));
    ImagePtrBase = FileData + BmpHeader->ImageOffset;
    for (y = 0; y < BmpHeader->PixelHeight; y++) {
        ImagePtr = ImagePtrBase;
        ImagePtrBase += ImageLineOffset;
        PixelPtr = NewImage->PixelData + 
				(BmpHeader->PixelHeight - 1 - y) * BmpHeader->PixelWidth;
        
        switch (BmpHeader->BitPerPixel) {
            
            case 1:
                for (x = 0; x < BmpHeader->PixelWidth; x++) {
                    BitIndex = x & 0x07;
                    if (BitIndex == 0)
                        ImageValue = *ImagePtr++;
                    
                    Index = (ImageValue >> (7 - BitIndex)) & 0x01;
                    PixelPtr->b = BmpColorMap[Index].Blue;
                    PixelPtr->g = BmpColorMap[Index].Green;
                    PixelPtr->r = BmpColorMap[Index].Red;
                    PixelPtr->a = AlphaValue;
                    PixelPtr++;
                }
                break;
            
            case 4:
                for (x = 0; x <= BmpHeader->PixelWidth - 2; x += 2) {
                    ImageValue = *ImagePtr++;
                    
                    Index = ImageValue >> 4;
                    PixelPtr->b = BmpColorMap[Index].Blue;
                    PixelPtr->g = BmpColorMap[Index].Green;
                    PixelPtr->r = BmpColorMap[Index].Red;
                    PixelPtr->a = AlphaValue;
                    PixelPtr++;
                    
                    Index = ImageValue & 0x0f;
                    PixelPtr->b = BmpColorMap[Index].Blue;
                    PixelPtr->g = BmpColorMap[Index].Green;
                    PixelPtr->r = BmpColorMap[Index].Red;
                    PixelPtr->a = AlphaValue;
                    PixelPtr++;
                }
                if (x < BmpHeader->PixelWidth) {
                    ImageValue = *ImagePtr++;
                    
                    Index = ImageValue >> 4;
                    PixelPtr->b = BmpColorMap[Index].Blue;
                    PixelPtr->g = BmpColorMap[Index].Green;
                    PixelPtr->r = BmpColorMap[Index].Red;
                    PixelPtr->a = AlphaValue;
                    PixelPtr++;
                }
                break;
            
            case 8:
                for (x = 0; x < BmpHeader->PixelWidth; x++) {
                    Index = *ImagePtr++;
                    PixelPtr->b = BmpColorMap[Index].Blue;
                    PixelPtr->g = BmpColorMap[Index].Green;
                    PixelPtr->r = BmpColorMap[Index].Red;
                    PixelPtr->a = AlphaValue;
                    PixelPtr++;
                }
                break;
            
            case 24:
                for (x = 0; x < BmpHeader->PixelWidth; x++) {
                    PixelPtr->b = *ImagePtr++;
                    PixelPtr->g = *ImagePtr++;
                    PixelPtr->r = *ImagePtr++;
                    PixelPtr->a = AlphaValue;
                    PixelPtr++;
                }
                break;
            
        }
    }
    
    return NewImage;
}


int
EFIAPI
main (                                         
  IN int Argc,
  IN char **Argv
  )
{
    EFI_STATUS    Status;
    EG_IMAGE        *Image;	

	
    Status = gBS->LocateProtocol(&GraphicsOutputProtocolGuid, 
						NULL, (VOID **) &GraphicsOutput);
    if (EFI_ERROR(Status)) {
        GraphicsOutput = NULL;
		Print(L"Loading Graphics_Output_Protocol error!\n");
		return EFI_SUCCESS;
	}	
	
    Image=egDecodeBMP((UINT8 *)&Untitled_bmp, Untitled_bmp_size, FALSE);

    Print(L"Image height [%d]:width[%d]",
					Image->Height,
					Image->Width);

	GraphicsOutput->Blt(
				GraphicsOutput, 
				(EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) Image->PixelData,
				EfiBltBufferToVideo,
                0, 
				0 , 
				0x100, 
				0x20, 
				Image->Width, 
				Image->Height, 0); 					
	
  return EFI_SUCCESS;
  
}

 

运行结果:

showbmp2a

Bin2C 下载(内含原始图片)

bin2c

源代码下载

GFXTest7

参考:

1.http://www.cppblog.com/djxzh/archive/2015/02/08/209766.html 补充《UEFI原理与编程》中关于Edk2的调试

2. http://sourceforge.net/projects/bin2c/

Step to UEFI (58) —– 计算MD5

MD5 是目前常用的Hash算法,可以用来校验文件的完整性,或者比对密码等等。本文介绍如何在UEFI下实现计算一个文件MD5的方法。具体算法来自【参考1】,在编译过程中修正了几个关于类型转换的 Warning 。

程序结构很简单,和前一篇关于CRC32的没有多大差别。

#include  <Uefi.h>
#include  <Library/UefiLib.h>
#include  <Library/ShellCEntryLib.h>

#include  <stdio.h>
#include  <stdlib.h>
#include  <wchar.h>

#include <Protocol/EfiShell.h>
#include <Library/ShellLib.h>
#include <Library/MemoryAllocationLib.h>

#include "md5.h"

extern EFI_BOOT_SERVICES         *gBS;
extern EFI_SYSTEM_TABLE			 *gST;
extern EFI_RUNTIME_SERVICES 	 *gRT;

extern EFI_SHELL_PROTOCOL        *gEfiShellProtocol;

int
EFIAPI
main (
  IN int Argc,
  IN CHAR16 **Argv
  )
{
  EFI_FILE_HANDLE   FileHandle;
  RETURN_STATUS     Status;
  EFI_FILE_INFO     *FileInfo = NULL;
  EFI_HANDLE        *HandleBuffer=NULL;
  UINTN  			ReadSize;
  MD5_CTX			ctx;
  char				R[16];
  
  //Check if there is a parameter
  if (Argc == 1) {
	Print(L"Usage: crctest [filename]\n");
	return 0;
  }
  
  //Open the file given by the parameter
  Status = ShellOpenFileByName(Argv[1], (SHELL_FILE_HANDLE *)&FileHandle,
                               EFI_FILE_MODE_READ , 0);

  if(Status != RETURN_SUCCESS) {
        Print(L"OpenFile failed!\n");
		return EFI_SUCCESS;
      }			

  //Get file size	  
  FileInfo = ShellGetFileInfo( (SHELL_FILE_HANDLE)FileHandle);	

  //Allocate a memory buffer
  HandleBuffer = AllocateZeroPool((UINTN) FileInfo-> FileSize);
  if (HandleBuffer == NULL) {
      return (SHELL_OUT_OF_RESOURCES);   }

  ReadSize=(UINTN) FileInfo-> FileSize;
  
  //Load the whole file to the buffer
  Status = ShellReadFile(FileHandle,&ReadSize,HandleBuffer);
  
  MD5_Init(&ctx);
  MD5_Update(&ctx, HandleBuffer, ReadSize);
  MD5_Final((unsigned char *)&R, &ctx);
  
  //Output
  Print(L"File Name: %s\n",Argv[1]);
  Print(L"File Size: %d\n",ReadSize);
  Print(L"File Size: %d\n",ReadSize);
  Print(L"MD5      : %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X\n",
					R[0]&0xFF  ,R[1]&0xFF  ,R[2]&0xFF  ,R[3]&0xFF  ,
					R[4]&0xFF  ,R[5]&0xFF  ,R[6]&0xFF  ,R[7]&0xFF  ,
					R[8]&0xFF  ,R[9]&0xFF  ,R[0xA]&0xFF,R[0xB]&0xFF,
					R[0xC]&0xFF,R[0xD]&0xFF,R[0xE]&0xFF,R[0xF]&0xFF);
  
  FreePool(HandleBuffer);	
  return EFI_SUCCESS;
}

 

运行结果

md51

可以看到,上面的例子能够在Shell下工作正常,但是需要特别注意,我没有验证过 X64 是否正常,如果你有这个需求,请自行验证。

完整的代码下载:

MD5Test

参考:

1.http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5 A portable, fast, and free implementation of the MD5 Message-Digest Algorithm (RFC 1321)

Step to UEFI (57.5) —– 计算CRC32

这里介绍如何编写一个计算CRC32的工具。在EDK的代码中,BaseTools\Source\Common 中有Crc32的例子,这里直接引用了 CRC32.h 和 CRC32.C。

代码中有很多注释,因此不做解释了。

#include  <Uefi.h>
#include  <Library/UefiLib.h>
#include  <Library/ShellCEntryLib.h>

#include  <stdio.h>
#include  <stdlib.h>
#include  <wchar.h>

#include <Protocol/EfiShell.h>
#include <Library/ShellLib.h>
#include <Library/MemoryAllocationLib.h>

#include "Crc32.h"

extern EFI_BOOT_SERVICES         *gBS;
extern EFI_SYSTEM_TABLE			 *gST;
extern EFI_RUNTIME_SERVICES 	 *gRT;

extern EFI_SHELL_PROTOCOL        *gEfiShellProtocol;

int
EFIAPI
main (
  IN int Argc,
  IN CHAR16 **Argv
  )
{
  EFI_FILE_HANDLE   FileHandle;
  RETURN_STATUS     Status;
  EFI_FILE_INFO     *FileInfo = NULL;
  EFI_HANDLE        *HandleBuffer=NULL;
  UINTN  			ReadSize;
  UINT32			CrcOut=0;
  
  //Check if there is a parameter
  if (Argc == 1) {
	Print(L"Usage: crctest [filename]\n");
	return 0;
  }
  
  //Open the file given by the parameter
  Status = ShellOpenFileByName(Argv[1], (SHELL_FILE_HANDLE *)&FileHandle,
                               EFI_FILE_MODE_READ , 0);

  if(Status != RETURN_SUCCESS) {
        Print(L"OpenFile failed!\n");
		return EFI_SUCCESS;
      }			

  //Get file size	  
  FileInfo = ShellGetFileInfo( (SHELL_FILE_HANDLE)FileHandle);	

  //Allocate a memory buffer
  HandleBuffer = AllocateZeroPool((UINTN) FileInfo-> FileSize);
  if (HandleBuffer == NULL) {
      return (SHELL_OUT_OF_RESOURCES);   }

  ReadSize=(UINTN) FileInfo-> FileSize;
  
  //Load the whole file to the buffer
  Status = ShellReadFile(FileHandle,&ReadSize,HandleBuffer);
  
  //Calculate the CRC32
  CalculateCrc32 ((UINT8*)HandleBuffer,ReadSize,&CrcOut);
  
  //Output
  Print(L"File Name: %s\n",Argv[1]);
  Print(L"File Size: %d\n",ReadSize);
  Print(L"CRC32    : %x\n",CrcOut);
  
  FreePool(HandleBuffer);	
  return EFI_SUCCESS;
}

 

运行结果 (计算自己的CRC32)

crc

为了保证正确,下载了一个CRC计算工具,可以看出,计算结果和上面的相同。

compare

完整代码下载

CRCTest

实际上除了上面的方法之外,还有更加简单的方法:直接使用 Boot Services 中的 CalculateCrc32 功能:

Capture

就是这样。