最近发现一个挺有意思的功能,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; }
运行结果
我们再仔细研究一下 %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 };
具体的实现就是这样。
請問具體要如何使用?
有沒有.efi檔可以引導?
謝謝
这个是进入 Shell 后才能执行的,你的问题是需要 Shell 吗?