/*++ Copyright (c) 1998 Intel Corporation Module Name: print.c Abstract: Revision History --*/ #include "lib.h" #include "internal/print.h" #include "internal/va_print.h" /* VA types/functions can be used if used internally so we can use default va_list always here */ // // Declare runtime functions // #ifdef RUNTIME_CODE #ifndef __GNUC__ #pragma RUNTIME_CODE(DbgPrint) // For debugging.. /* #pragma RUNTIME_CODE(ValueToHex) #pragma RUNTIME_CODE(ValueToString) #pragma RUNTIME_CODE(TimeToString) */ #endif /* !defined(__GNUC__) */ #endif // // // INTN DbgPrint ( IN INTN mask, IN CONST CHAR8 *fmt, ... ) /*++ Routine Description: Prints a formatted unicode string to the default StandardError console Arguments: mask - Bit mask of debug string. If a bit is set in the mask that is also set in EFIDebug the string is printed; otherwise, the string is not printed fmt - Format string Returns: Length of string printed to the StandardError console --*/ { SIMPLE_TEXT_OUTPUT_INTERFACE *DbgOut; PRINT_STATE ps; va_list args; UINTN back; UINTN attr; UINTN SavedAttribute; if (!(EFIDebug & mask)) { return 0; } va_start (args, fmt); ZeroMem (&ps, sizeof(ps)); ps.Output = _DbgOut; ps.fmt.Ascii = TRUE; ps.fmt.pc = fmt; va_copy(ps.args, args); ps.Attr = EFI_TEXT_ATTR(EFI_LIGHTGRAY, EFI_RED); DbgOut = LibRuntimeDebugOut; if (!DbgOut) { DbgOut = ST->StdErr; } if (DbgOut) { ps.Attr = DbgOut->Mode->Attribute; ps.Context = DbgOut; ps.SetAttr = (INTN (EFIAPI *)(VOID *, UINTN)) DbgOut->SetAttribute; } SavedAttribute = ps.Attr; back = (ps.Attr >> 4) & 0xf; ps.AttrNorm = EFI_TEXT_ATTR(EFI_LIGHTGRAY, back); ps.AttrHighlight = EFI_TEXT_ATTR(EFI_WHITE, back); ps.AttrError = EFI_TEXT_ATTR(EFI_YELLOW, back); attr = ps.AttrNorm; if (mask & D_WARN) { attr = ps.AttrHighlight; } if (mask & D_ERROR) { attr = ps.AttrError; } if (ps.SetAttr) { ps.Attr = attr; uefi_call_wrapper(ps.SetAttr, 2, ps.Context, attr); } _Print (&ps); va_end (ps.args); va_end (args); // // Restore original attributes // if (ps.SetAttr) { uefi_call_wrapper(ps.SetAttr, 2, ps.Context, SavedAttribute); } return 0; } INTN EFIAPI _DbgOut ( IN VOID *Context, IN CHAR16 *Buffer ) // Append string worker for DbgPrint { SIMPLE_TEXT_OUTPUT_INTERFACE *DbgOut; DbgOut = Context; // if (!DbgOut && ST && ST->ConOut) { // DbgOut = ST->ConOut; // } if (DbgOut) { if (IsLocalPrint(DbgOut->OutputString)) DbgOut->OutputString(DbgOut, Buffer); else uefi_call_wrapper(DbgOut->OutputString, 2, DbgOut, Buffer); } return 0; } INTN EFIAPI _SPrint ( IN VOID *Context, IN CHAR16 *Buffer ) // Append string worker for UnicodeSPrint, PoolPrint and CatPrint { UINTN len; POOL_PRINT *spc; spc = Context; len = StrLen(Buffer); // // Is the string is over the max truncate it // if (spc->len + len > spc->maxlen) { len = spc->maxlen - spc->len; } // // Append the new text // CopyMem (spc->str + spc->len, Buffer, len * sizeof(CHAR16)); spc->len += len; // // Null terminate it // if (spc->len < spc->maxlen) { spc->str[spc->len] = 0; } else if (spc->maxlen) { spc->str[spc->maxlen] = 0; } return 0; } INTN EFIAPI _PoolPrint ( IN VOID *Context, IN CHAR16 *Buffer ) // Append string worker for PoolPrint and CatPrint { UINTN newlen; POOL_PRINT *spc; spc = Context; newlen = spc->len + StrLen(Buffer) + 1; // // Is the string is over the max, grow the buffer // if (newlen > spc->maxlen) { // // Grow the pool buffer // newlen += PRINT_STRING_LEN; spc->maxlen = newlen; spc->str = ReallocatePool ( spc->len * sizeof(CHAR16), spc->maxlen * sizeof(CHAR16), spc->str ); if (!spc->str) { spc->len = 0; spc->maxlen = 0; } } // // Append the new text // return _SPrint (Context, Buffer); } UINTN UnicodeSPrint ( OUT CHAR16 *Str, IN UINTN StrSize, IN CONST CHAR16 *fmt, ... ) /*++ Routine Description: Prints a formatted unicode string to a buffer Arguments: Str - Output buffer to print the formatted string into StrSize - Size of Str. String is truncated to this size. A size of 0 means there is no limit fmt - The format string Returns: String length returned in buffer --*/ { va_list args; UINTN len; va_start (args, fmt); len = UnicodeVSPrint(Str, StrSize, fmt, args); va_end (args); return len; } UINTN AsciiSPrint ( OUT CHAR8 *Str, IN UINTN StrSize, IN CONST CHAR8 *fmt, ... ) /*++ Routine Description: Prints a formatted unicode string to a buffer Arguments: Str - Output buffer to print the formatted string into StrSize - Size of Str. String is truncated to this size. A size of 0 means there is no limit fmt - The format string Returns: String length returned in buffer --*/ { va_list args; UINTN len; va_start (args, fmt); len = AsciiVSPrint(Str, StrSize, fmt, args); va_end (args); return len; } CHAR16 * PoolPrint ( IN CONST CHAR16 *fmt, ... ) /*++ Routine Description: Prints a formatted unicode string to allocated pool. The caller must free the resulting buffer. Arguments: fmt - The format string Returns: Allocated buffer with the formatted string printed in it. The caller must free the allocated buffer. The buffer allocation is not packed. --*/ { va_list args; CHAR16 *pool; va_start (args, fmt); pool = VPoolPrint(fmt, args); va_end (args); return pool; } CHAR16 * CatPrint ( IN OUT POOL_PRINT *Str, IN CONST CHAR16 *fmt, ... ) /*++ Routine Description: Concatenates a formatted unicode string to allocated pool. The caller must free the resulting buffer. Arguments: Str - Tracks the allocated pool, size in use, and amount of pool allocated. fmt - The format string Returns: Allocated buffer with the formatted string printed in it. The caller must free the allocated buffer. The buffer allocation is not packed. --*/ { va_list args; va_start (args, fmt); _PoolCatPrint (fmt, args, Str, _PoolPrint); va_end (args); return Str->str; } UINTN Print ( IN CONST CHAR16 *fmt, ... ) /*++ Routine Description: Prints a formatted unicode string to the default console Arguments: fmt - Format string Returns: Length of string printed to the console --*/ { va_list args; UINTN back; va_start (args, fmt); back = _IPrint ((UINTN) -1, (UINTN) -1, ST->ConOut, fmt, NULL, args); va_end (args); return back; } UINTN PrintAt ( IN UINTN Column, IN UINTN Row, IN CONST CHAR16 *fmt, ... ) /*++ Routine Description: Prints a formatted unicode string to the default console, at the supplied cursor position Arguments: Column, Row - The cursor position to print the string at fmt - Format string Returns: Length of string printed to the console --*/ { va_list args; UINTN back; va_start (args, fmt); back = _IPrint (Column, Row, ST->ConOut, fmt, NULL, args); va_end (args); return back; } UINTN IPrint ( IN SIMPLE_TEXT_OUTPUT_INTERFACE *Out, IN CONST CHAR16 *fmt, ... ) /*++ Routine Description: Prints a formatted unicode string to the specified console Arguments: Out - The console to print the string too fmt - Format string Returns: Length of string printed to the console --*/ { va_list args; UINTN back; va_start (args, fmt); back = _IPrint ((UINTN) -1, (UINTN) -1, Out, fmt, NULL, args); va_end (args); return back; } UINTN IPrintAt ( IN SIMPLE_TEXT_OUTPUT_INTERFACE *Out, IN UINTN Column, IN UINTN Row, IN CONST CHAR16 *fmt, ... ) /*++ Routine Description: Prints a formatted unicode string to the specified console, at the supplied cursor position Arguments: Out - The console to print the string to Column, Row - The cursor position to print the string at fmt - Format string Returns: Length of string printed to the console --*/ { va_list args; UINTN back; va_start (args, fmt); back = _IPrint (Column, Row, Out, fmt, NULL, args); va_end (args); return back; } UINTN AsciiPrint ( IN CONST CHAR8 *fmt, ... ) /*++ Routine Description: For those whom really can't deal with unicode, a print function that takes an ascii format string Arguments: fmt - ascii format string Returns: Length of string printed to the console --*/ { va_list args; UINTN back; va_start (args, fmt); back = _IPrint ((UINTN) -1, (UINTN) -1, ST->ConOut, NULL, fmt, args); va_end (args); return back; } STATIC CHAR8 Hex[] = {'0','1','2','3','4','5','6','7', '8','9','A','B','C','D','E','F'}; VOID ValueToHex ( IN CHAR16 *Buffer, IN UINT64 v ) { CHAR8 str[30], *p1; CHAR16 *p2; if (!v) { Buffer[0] = '0'; Buffer[1] = 0; return ; } p1 = str; p2 = Buffer; while (v) { // Without the cast, the MSVC compiler may insert a reference to __allmull *(p1++) = Hex[(UINTN)(v & 0xf)]; v = RShiftU64 (v, 4); } while (p1 != str) { *(p2++) = *(--p1); } *p2 = 0; } VOID ValueToString ( IN CHAR16 *Buffer, IN BOOLEAN Comma, IN INT64 v ) { STATIC CHAR8 ca[] = { 3, 1, 2 }; CHAR8 str[40], *p1; CHAR16 *p2; UINTN c, r; if (!v) { Buffer[0] = '0'; Buffer[1] = 0; return ; } p1 = str; p2 = Buffer; if (v < 0) { *(p2++) = '-'; v = -v; } while (v) { v = (INT64)DivU64x32 ((UINT64)v, 10, &r); *(p1++) = (CHAR8)r + '0'; } c = (UINTN) (Comma ? ca[(p1 - str) % 3] : 999) + 1; while (p1 != str) { c -= 1; if (!c) { *(p2++) = ','; c = 3; } *(p2++) = *(--p1); } *p2 = 0; } // Having this call inlined by VS2022 on Release builds produces an // "Undefined OpCode Exception" on ARM32 whenever Print() is invoked, // even when no part of the code below is actually being executed... // For safety, add an explicit clause to prevent inlining on all platforms. EFI_NOINLINE VOID FloatToString ( IN CHAR16 *Buffer, IN BOOLEAN Comma, IN double v ) { /* * Integer part. */ INTN i = (INTN)v; ValueToString(Buffer, Comma, i); /* * Decimal point. */ UINTN x = StrLen(Buffer); Buffer[x] = u'.'; x++; /* * Keep fractional part. */ float f = (float)(v - i); if (f < 0) f = -f; /* * Leading fractional zeroes. */ f *= 10.0; while ( (f != 0) && ((INTN)f == 0)) { Buffer[x] = u'0'; x++; f *= 10.0; } /* * Fractional digits. */ while ((float)(INTN)f != f) { f *= 10; } ValueToString(Buffer + x, FALSE, (INTN)f); return; } VOID TimeToString ( OUT CHAR16 *Buffer, IN EFI_TIME *Time ) { UINTN Hour, Year; CHAR16 AmPm; AmPm = 'a'; Hour = Time->Hour; if (Time->Hour == 0) { Hour = 12; } else if (Time->Hour >= 12) { AmPm = 'p'; if (Time->Hour >= 13) { Hour -= 12; } } Year = Time->Year % 100; // bugbug: for now just print it any old way UnicodeSPrint (Buffer, 0, u"%02d/%02d/%02d %02d:%02d%c", Time->Month, Time->Day, Year, Hour, Time->Minute, AmPm ); } VOID DumpHex ( IN UINTN Indent, IN UINTN Offset, IN UINTN DataSize, IN VOID *UserData ) { CHAR8 *Data, Val[50], Str[20], c; UINTN Size, Index; UINTN ScreenCount; UINTN TempColumn; UINTN ScreenSize; CHAR16 ReturnStr[1]; uefi_call_wrapper(ST->ConOut->QueryMode, 4, ST->ConOut, ST->ConOut->Mode->Mode, &TempColumn, &ScreenSize); ScreenCount = 0; ScreenSize -= 2; Data = UserData; while (DataSize) { Size = 16; if (Size > DataSize) { Size = DataSize; } for (Index=0; Index < Size; Index += 1) { c = Data[Index]; Val[Index*3+0] = Hex[c>>4]; Val[Index*3+1] = Hex[c&0xF]; Val[Index*3+2] = (Index == 7)?'-':' '; Str[Index] = (c < ' ' || c > 'z') ? '.' : c; } Val[Index*3] = 0; Str[Index] = 0; Print (u"%*a%X: %-.48a *%a*\n", Indent, "", Offset, Val, Str); Data += Size; Offset += Size; DataSize -= Size; ScreenCount++; if (ScreenCount >= ScreenSize && ScreenSize != 0) { // // If ScreenSize == 0 we have the console redirected so don't // block updates // ScreenCount = 0; Print (u"Press Enter to continue :"); Input (u"", ReturnStr, sizeof(ReturnStr)/sizeof(CHAR16)); Print (u"\n"); } } }