Home | History | Annotate | Download | only in Print
      1 /*++
      2 
      3 Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.<BR>
      4 This program and the accompanying materials
      5 are licensed and made available under the terms and conditions of the BSD License
      6 which accompanies this distribution.  The full text of the license may be found at
      7 http://opensource.org/licenses/bsd-license.php
      8 
      9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     11 
     12 Module Name:
     13 
     14   Print.c
     15 
     16 Abstract:
     17 
     18   Basic Ascii AvSPrintf() function named AvSPrint(). AvSPrint() enables very
     19   simple implemenation of debug prints.
     20 
     21   You can not Print more than PEI_LIB_MAX_PRINT_BUFFER characters at a
     22   time. This makes the implementation very simple.
     23 
     24   AvSPrint format specification has the follwoing form
     25 
     26   %[flags][width]type
     27 
     28   flags:
     29     '-' - Left justify
     30     '+' - Prefix a sign
     31     ' ' - Prefix a blank
     32     ',' - Place commas in numberss
     33     '0' - Prefix for width with zeros
     34     'l' - UINT64
     35     'L' - UINT64
     36 
     37   width:
     38     '*' - Get width from a UINTN argumnet from the argument list
     39     Decimal number that represents width of print
     40 
     41   type:
     42     'p' - arugment is VOID *; printed as hex number
     43     'X' - argument is a UINTN hex number, prefix '0'
     44     'x' - argument is a hex number
     45     'd' - argument is a decimal number
     46     'a' - argument is an ascii string
     47     'S', 's' - argument is an Unicode string
     48     'g' - argument is a pointer to an EFI_GUID
     49     't' - argument is a pointer to an EFI_TIME structure
     50     'c' - argument is an ascii character
     51     'r' - argument is EFI_STATUS
     52     '%' - Print a %
     53 
     54 --*/
     55 
     56 #include "Tiano.h"
     57 #include "Pei.h"
     58 #include "PeiLib.h"
     59 #include "Print.h"
     60 
     61 
     62 STATIC
     63 UINTN
     64 ValueToString (
     65   IN  OUT CHAR8   *Buffer,
     66   IN  INT64       Value,
     67   IN  UINTN       Flags,
     68   IN  UINTN       Width
     69   );
     70 
     71 STATIC
     72 UINTN
     73 ValueTomHexStr (
     74   IN  OUT CHAR8   *Buffer,
     75   IN  UINT64      Value,
     76   IN  UINTN       Flags,
     77   IN  UINTN       Width
     78   );
     79 
     80 STATIC
     81 UINTN
     82 GuidToString (
     83   IN  EFI_GUID  *Guid,
     84   IN OUT CHAR8  *Buffer,
     85   IN  UINTN     BufferSize
     86   );
     87 
     88 STATIC
     89 UINTN
     90 TimeToString (
     91   IN  EFI_TIME  *Time,
     92   IN OUT CHAR8  *Buffer,
     93   IN  UINTN     BufferSize
     94   );
     95 
     96 STATIC
     97 UINTN
     98 EfiStatusToString (
     99   IN EFI_STATUS   Status,
    100   OUT CHAR8       *Buffer,
    101   IN  UINTN       BufferSize
    102   );
    103 
    104 
    105 UINTN
    106 ASPrint (
    107   OUT CHAR8         *Buffer,
    108   IN  UINTN         BufferSize,
    109   IN  CONST CHAR8   *Format,
    110   ...
    111   )
    112 /*++
    113 
    114 Routine Description:
    115 
    116   ASPrint function to process format and place the results in Buffer.
    117 
    118 Arguments:
    119 
    120   Buffer     - Ascii buffer to print the results of the parsing of Format into.
    121 
    122   BufferSize - Maximum number of characters to put into buffer. Zero means no
    123                limit.
    124 
    125   Format - Ascii format string see file header for more details.
    126 
    127   ...    - Vararg list consumed by processing Format.
    128 
    129 Returns:
    130 
    131   Number of characters printed.
    132 
    133 --*/
    134 {
    135   UINTN   Return;
    136   VA_LIST Marker;
    137 
    138   VA_START(Marker, Format);
    139   Return = AvSPrint(Buffer, BufferSize, Format, Marker);
    140   VA_END (Marker);
    141 
    142   return Return;
    143 }
    144 
    145 
    146 UINTN
    147 AvSPrint (
    148   OUT CHAR8         *StartOfBuffer,
    149   IN  UINTN         BufferSize,
    150   IN  CONST CHAR8   *FormatString,
    151   IN  VA_LIST       Marker
    152   )
    153 /*++
    154 
    155 Routine Description:
    156 
    157   AvSPrint function to process format and place the results in Buffer. Since a
    158   VA_LIST is used this rountine allows the nesting of Vararg routines. Thus
    159   this is the main print working routine
    160 
    161 Arguments:
    162 
    163   StartOfBuffer - Ascii buffer to print the results of the parsing of Format into.
    164 
    165   BufferSize    - Maximum number of characters to put into buffer. Zero means
    166                   no limit.
    167 
    168   FormatString  - Ascii format string see file header for more details.
    169 
    170   Marker        - Vararg list consumed by processing Format.
    171 
    172 Returns:
    173 
    174   Number of characters printed.
    175 
    176 --*/
    177 {
    178   CHAR8     TempBuffer[CHARACTER_NUMBER_FOR_VALUE];
    179   CHAR8     *Buffer;
    180   CHAR8     *AsciiStr;
    181   CHAR16    *UnicodeStr;
    182   CHAR8     *Format;
    183   UINTN     Index;
    184   UINTN     Flags;
    185   UINTN     Width;
    186   UINTN     Count;
    187   UINTN     BufferLeft;
    188   UINT64    Value;
    189   EFI_GUID  *TmpGUID;
    190   BOOLEAN   Done;
    191 
    192   //
    193   // Process the format string. Stop if Buffer is over run.
    194   //
    195   Buffer              = StartOfBuffer;
    196   Format              = (CHAR8 *) FormatString;
    197   BufferLeft          = BufferSize;
    198   for (Index = 0; (*Format != '\0') && (Index < BufferSize - 1); Format++) {
    199     if (*Format != '%') {
    200       if ((*Format == '\n') && (Index < BufferSize - 2)) {
    201         //
    202         // If carage return add line feed
    203         //
    204         Buffer[Index++] = '\r';
    205         BufferLeft -= sizeof (CHAR8);
    206       }
    207 
    208       Buffer[Index++] = *Format;
    209       BufferLeft -= sizeof (CHAR8);
    210     } else {
    211 
    212       //
    213       // Now it's time to parse what follows after %
    214       //
    215       Flags = 0;
    216       Width = 0;
    217       for (Done = FALSE; !Done; ) {
    218         Format++;
    219 
    220         switch (*Format) {
    221 
    222         case '-': Flags |= LEFT_JUSTIFY; break;
    223         case '+': Flags |= PREFIX_SIGN;  break;
    224         case ' ': Flags |= PREFIX_BLANK; break;
    225         case ',': Flags |= COMMA_TYPE;   break;
    226         case 'L':
    227         case 'l': Flags |= LONG_TYPE;    break;
    228 
    229         case '*':
    230           Width = VA_ARG (Marker, UINTN);
    231           break;
    232 
    233         case '0':
    234           Flags |= PREFIX_ZERO;
    235         case '1':
    236         case '2':
    237         case '3':
    238         case '4':
    239         case '5':
    240         case '6':
    241         case '7':
    242         case '8':
    243         case '9':
    244           Count = 0;
    245           do {
    246             Count = (Count * 10) + *Format - '0';
    247             Format++;
    248           } while ((*Format >= '0')  &&  (*Format <= '9'));
    249           Format--;
    250           Width = Count;
    251           break;
    252 
    253         default:
    254           Done = TRUE;
    255         }
    256       }
    257 
    258       switch (*Format) {
    259       case 'p':
    260         //
    261         // Flag space, +, 0, L & l are invalid for type p.
    262         //
    263         Flags &= ~(PREFIX_BLANK| PREFIX_SIGN | LONG_TYPE);
    264         if (sizeof (VOID *) > 4) {
    265           Flags |= LONG_TYPE;
    266           Value = VA_ARG (Marker, UINT64);
    267         } else {
    268           Value = VA_ARG (Marker, UINTN);
    269         }
    270         Flags |= PREFIX_ZERO;
    271 
    272         ValueTomHexStr (TempBuffer, Value, Flags, Width);
    273         AsciiStr = TempBuffer;
    274 
    275         for (; (*AsciiStr != '\0') && (Index < BufferSize - 1); AsciiStr++) {
    276           Buffer[Index++] = *AsciiStr;
    277         }
    278         break;
    279       case 'X':
    280         Flags |= PREFIX_ZERO;
    281         Width = sizeof (UINT64) * 2;
    282 
    283       //
    284       // break skiped on purpose
    285       //
    286       case 'x':
    287         if ((Flags & LONG_TYPE) == LONG_TYPE) {
    288           Value = VA_ARG (Marker, UINT64);
    289         } else {
    290           Value = VA_ARG (Marker, UINTN);
    291         }
    292 
    293         ValueTomHexStr (TempBuffer, Value, Flags, Width);
    294         AsciiStr = TempBuffer;
    295 
    296         for (; (*AsciiStr != '\0') && (Index < BufferSize - 1); AsciiStr++) {
    297           Buffer[Index++] = *AsciiStr;
    298         }
    299         break;
    300 
    301       case 'd':
    302         if ((Flags & LONG_TYPE) == LONG_TYPE) {
    303           Value = VA_ARG (Marker, UINT64);
    304         } else {
    305           Value = (UINTN) VA_ARG (Marker, UINTN);
    306         }
    307 
    308         ValueToString (TempBuffer, Value, Flags, Width);
    309         AsciiStr = TempBuffer;
    310 
    311         for (; (*AsciiStr != '\0') && (Index < BufferSize - 1); AsciiStr++) {
    312           Buffer[Index++] = *AsciiStr;
    313         }
    314         break;
    315 
    316       case 's':
    317       case 'S':
    318         UnicodeStr = (CHAR16 *) VA_ARG (Marker, CHAR8 *);
    319         if (UnicodeStr == NULL) {
    320           UnicodeStr = L"<null string>";
    321         }
    322 
    323         for (Count = 0; (*UnicodeStr != '\0') && (Index < BufferSize - 1); UnicodeStr++, Count++) {
    324           Buffer[Index++] = (CHAR8) *UnicodeStr;
    325         }
    326         //
    327         // Add padding if needed
    328         //
    329         for (; (Count < Width) && (Index < BufferSize - 1); Count++) {
    330           Buffer[Index++] = ' ';
    331         }
    332 
    333         break;
    334 
    335       case 'a':
    336         AsciiStr = (CHAR8 *) VA_ARG (Marker, CHAR8 *);
    337         if (AsciiStr == NULL) {
    338           AsciiStr = "<null string>";
    339         }
    340 
    341         for (Count = 0; (*AsciiStr != '\0') && (Index < BufferSize - 1); AsciiStr++, Count++) {
    342           Buffer[Index++] = *AsciiStr;
    343         }
    344         //
    345         // Add padding if needed
    346         //
    347         for (; (Count < Width) && (Index < BufferSize - 1); Count++) {
    348           Buffer[Index++] = ' ';
    349         }
    350         break;
    351 
    352       case 'c':
    353         Buffer[Index++] = (CHAR8) VA_ARG (Marker, UINTN);
    354         break;
    355 
    356       case 'g':
    357         TmpGUID = VA_ARG (Marker, EFI_GUID *);
    358         if (TmpGUID != NULL) {
    359           Index += GuidToString (
    360                     TmpGUID,
    361                     &Buffer[Index],
    362                     BufferLeft
    363                     );
    364         }
    365         break;
    366 
    367       case 't':
    368         Index += TimeToString (
    369                   VA_ARG (Marker, EFI_TIME *),
    370                   &Buffer[Index],
    371                   BufferLeft
    372                   );
    373         break;
    374 
    375       case 'r':
    376         Index += EfiStatusToString (
    377                   VA_ARG (Marker, EFI_STATUS),
    378                   &Buffer[Index],
    379                   BufferLeft
    380                   );
    381         break;
    382 
    383       case '%':
    384         Buffer[Index++] = *Format;
    385         break;
    386 
    387       default:
    388         //
    389         // if the type is unknown print it to the screen
    390         //
    391         Buffer[Index++] = *Format;
    392       }
    393 
    394       BufferLeft = BufferSize - Index;
    395     }
    396   }
    397 
    398   Buffer[Index++] = '\0';
    399 
    400   return &Buffer[Index] - StartOfBuffer;
    401 }
    402 
    403 
    404 
    405 static CHAR8 mHexStr[] = { '0','1','2','3','4','5','6','7',
    406                           '8','9','A','B','C','D','E','F' };
    407 
    408 STATIC
    409 UINTN
    410 ValueTomHexStr (
    411   IN  OUT CHAR8   *Buffer,
    412   IN  UINT64      Value,
    413   IN  UINTN       Flags,
    414   IN  UINTN       Width
    415   )
    416 /*++
    417 
    418 Routine Description:
    419 
    420   AvSPrint worker function that prints a Value as a hex number in Buffer
    421 
    422 Arguments:
    423 
    424   Buffer - Location to place ascii hex string of Value.
    425 
    426   Value  - Hex value to convert to a string in Buffer.
    427 
    428   Flags  - Flags to use in printing Hex string, see file header for details.
    429 
    430   Width  - Width of hex value.
    431 
    432 Returns:
    433 
    434   Number of characters printed.
    435 
    436 --*/
    437 {
    438   CHAR8   TempBuffer[CHARACTER_NUMBER_FOR_VALUE];
    439   CHAR8   *TempStr;
    440   CHAR8   Prefix;
    441   CHAR8   *BufferPtr;
    442   UINTN   Count;
    443   UINTN   Index;
    444 
    445   TempStr = TempBuffer;
    446   BufferPtr = Buffer;
    447 
    448   //
    449   // Count starts at one since we will null terminate. Each iteration of the
    450   // loop picks off one nibble. Oh yea TempStr ends up backwards
    451   //
    452   Count = 0;
    453   do {
    454     *(TempStr++) = mHexStr[Value & 0x0f];
    455     Value = RShiftU64 (Value, 4);
    456     Count++;
    457   } while (Value != 0);
    458 
    459   if (Flags & PREFIX_ZERO) {
    460     Prefix = '0';
    461   } else if (!(Flags & LEFT_JUSTIFY)) {
    462     Prefix = ' ';
    463   } else {
    464     Prefix = 0x00;
    465   }
    466   for (Index = Count; Index < Width; Index++) {
    467     *(TempStr++) = Prefix;
    468   }
    469 
    470   //
    471   // Reverse temp string into Buffer.
    472   //
    473   if (Width > 0 && (UINTN) (TempStr - TempBuffer) > Width) {
    474     TempStr = TempBuffer + Width;
    475   }
    476   Index = 0;
    477   while (TempStr != TempBuffer) {
    478     *(BufferPtr++) = *(--TempStr);
    479     Index++;
    480   }
    481 
    482   *BufferPtr = 0;
    483   return Index;
    484 }
    485 
    486 STATIC
    487 UINTN
    488 ValueToString (
    489   IN  OUT CHAR8   *Buffer,
    490   IN  INT64       Value,
    491   IN  UINTN       Flags,
    492   IN  UINTN       Width
    493   )
    494 /*++
    495 
    496 Routine Description:
    497 
    498   AvSPrint worker function that prints a Value as a decimal number in Buffer
    499 
    500 Arguments:
    501 
    502   Buffer - Location to place ascii decimal number string of Value.
    503 
    504   Value  - Decimal value to convert to a string in Buffer.
    505 
    506   Flags  - Flags to use in printing decimal string, see file header for details.
    507 
    508   Width  - Width of hex value.
    509 
    510 Returns:
    511 
    512   Number of characters printed.
    513 
    514 --*/
    515 {
    516   CHAR8   TempBuffer[CHARACTER_NUMBER_FOR_VALUE];
    517   CHAR8   *TempStr;
    518   CHAR8   *BufferPtr;
    519   UINTN   Count;
    520   UINTN   NumberCount;
    521   UINTN   Remainder;
    522   BOOLEAN Negative;
    523   UINTN   Index;
    524 
    525   Negative    = FALSE;
    526   TempStr     = TempBuffer;
    527   BufferPtr   = Buffer;
    528   Count       = 0;
    529   NumberCount = 0;
    530   Remainder   = 0;
    531 
    532   if (Value < 0) {
    533     Negative = TRUE;
    534     Value    = -Value;
    535   }
    536 
    537   do {
    538     Value = (INT64)DivU64x32 ((UINT64)Value, 10, &Remainder);
    539     *(TempStr++) = (CHAR8)(Remainder + '0');
    540     Count++;
    541     NumberCount++;
    542     if ((Flags & COMMA_TYPE) == COMMA_TYPE) {
    543       if (NumberCount % 3 == 0 && Value != 0) {
    544         *(TempStr++) = ',';
    545         Count++;
    546       }
    547     }
    548   } while (Value != 0);
    549 
    550   if (Negative) {
    551     *(BufferPtr++) = '-';
    552     Count++;
    553   }
    554 
    555   //
    556   // Reverse temp string into Buffer.
    557   //
    558   if (Width > 0 && (UINTN) (TempStr - TempBuffer) > Width) {
    559     TempStr = TempBuffer + Width;
    560   }
    561   Index = 0;
    562   while (TempStr != TempBuffer) {
    563     *(BufferPtr++) = *(--TempStr);
    564   }
    565 
    566   *BufferPtr = 0;
    567   return Index;
    568 }
    569 
    570 STATIC
    571 UINTN
    572 GuidToString (
    573   IN  EFI_GUID  *Guid,
    574   IN  CHAR8     *Buffer,
    575   IN  UINTN     BufferSize
    576   )
    577 /*++
    578 
    579 Routine Description:
    580 
    581   AvSPrint worker function that prints an EFI_GUID.
    582 
    583 Arguments:
    584 
    585   Guid       - Pointer to GUID to print.
    586 
    587   Buffer     - Buffe to print Guid into.
    588 
    589   BufferSize - Size of Buffer.
    590 
    591 Returns:
    592 
    593   Number of characters printed.
    594 
    595 --*/
    596 {
    597   UINTN Size;
    598 
    599   Size = ASPrint (
    600             Buffer,
    601             BufferSize,
    602             "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
    603             (UINTN)Guid->Data1,
    604             (UINTN)Guid->Data2,
    605             (UINTN)Guid->Data3,
    606             (UINTN)Guid->Data4[0],
    607             (UINTN)Guid->Data4[1],
    608             (UINTN)Guid->Data4[2],
    609             (UINTN)Guid->Data4[3],
    610             (UINTN)Guid->Data4[4],
    611             (UINTN)Guid->Data4[5],
    612             (UINTN)Guid->Data4[6],
    613             (UINTN)Guid->Data4[7]
    614             );
    615 
    616   //
    617   // ASPrint will null terminate the string. The -1 skips the null
    618   //
    619   return Size - 1;
    620 }
    621 
    622 
    623 STATIC
    624 UINTN
    625 TimeToString (
    626   IN EFI_TIME   *Time,
    627   OUT CHAR8     *Buffer,
    628   IN  UINTN     BufferSize
    629   )
    630 /*++
    631 
    632 Routine Description:
    633 
    634   AvSPrint worker function that prints EFI_TIME.
    635 
    636 Arguments:
    637 
    638   Time       - Pointer to EFI_TIME sturcture to print.
    639 
    640   Buffer     - Buffer to print Time into.
    641 
    642   BufferSize - Size of Buffer.
    643 
    644 Returns:
    645 
    646   Number of characters printed.
    647 
    648 --*/
    649 {
    650   UINTN Size;
    651 
    652   Size = ASPrint (
    653             Buffer,
    654             BufferSize,
    655             "%02d/%02d/%04d  %02d:%02d",
    656             (UINTN)Time->Month,
    657             (UINTN)Time->Day,
    658             (UINTN)Time->Year,
    659             (UINTN)Time->Hour,
    660             (UINTN)Time->Minute
    661             );
    662 
    663   //
    664   // ASPrint will null terminate the string. The -1 skips the null
    665   //
    666   return Size - 1;
    667 }
    668 
    669 STATIC
    670 UINTN
    671 EfiStatusToString (
    672   IN EFI_STATUS   Status,
    673   OUT CHAR8       *Buffer,
    674   IN  UINTN       BufferSize
    675   )
    676 /*++
    677 
    678 Routine Description:
    679 
    680   AvSPrint worker function that prints EFI_STATUS as a string. If string is
    681   not known a hex value will be printed.
    682 
    683 Arguments:
    684 
    685   Status     -  EFI_STATUS sturcture to print.
    686 
    687   Buffer     - Buffer to print EFI_STATUS message string into.
    688 
    689   BufferSize - Size of Buffer.
    690 
    691 Returns:
    692 
    693   Number of characters printed.
    694 
    695 --*/
    696 {
    697   UINTN   Size;
    698   CHAR8   *Desc;
    699 
    700   if (Status == EFI_SUCCESS) {
    701     Desc = "Success";
    702   } else if (Status == EFI_LOAD_ERROR) {
    703     Desc = "Load Error";
    704   } else if (Status == EFI_INVALID_PARAMETER) {
    705     Desc = "Invalid Parameter";
    706   } else if (Status == EFI_UNSUPPORTED) {
    707     Desc = "Unsupported";
    708   } else if (Status == EFI_BAD_BUFFER_SIZE) {
    709     Desc = "Bad Buffer Size";
    710   } else if (Status == EFI_BUFFER_TOO_SMALL) {
    711     Desc = "Buffer Too Small";
    712   } else if (Status == EFI_NOT_READY) {
    713     Desc = "Not Ready";
    714   } else if (Status == EFI_DEVICE_ERROR) {
    715     Desc = "Device Error";
    716   } else if (Status == EFI_WRITE_PROTECTED) {
    717     Desc = "Write Protected";
    718   } else if (Status == EFI_OUT_OF_RESOURCES) {
    719     Desc = "Out of Resources";
    720   } else if (Status == EFI_VOLUME_CORRUPTED) {
    721     Desc = "Volume Corrupt";
    722   } else if (Status == EFI_VOLUME_FULL) {
    723     Desc = "Volume Full";
    724   } else if (Status == EFI_NO_MEDIA) {
    725     Desc = "No Media";
    726   } else if (Status == EFI_MEDIA_CHANGED) {
    727     Desc = "Media changed";
    728   } else if (Status == EFI_NOT_FOUND) {
    729     Desc = "Not Found";
    730   } else if (Status == EFI_ACCESS_DENIED) {
    731     Desc = "Access Denied";
    732   } else if (Status == EFI_NO_RESPONSE) {
    733     Desc = "No Response";
    734   } else if (Status == EFI_NO_MAPPING) {
    735     Desc = "No mapping";
    736   } else if (Status == EFI_TIMEOUT) {
    737     Desc = "Time out";
    738   } else if (Status == EFI_NOT_STARTED) {
    739     Desc = "Not started";
    740   } else if (Status == EFI_ALREADY_STARTED) {
    741     Desc = "Already started";
    742   } else if (Status == EFI_ABORTED) {
    743     Desc = "Aborted";
    744   } else if (Status == EFI_ICMP_ERROR) {
    745     Desc = "ICMP Error";
    746   } else if (Status == EFI_TFTP_ERROR) {
    747     Desc = "TFTP Error";
    748   } else if (Status == EFI_PROTOCOL_ERROR) {
    749     Desc = "Protocol Error";
    750   } else if (Status == EFI_WARN_UNKNOWN_GLYPH) {
    751     Desc = "Warning Unknown Glyph";
    752   } else if (Status == EFI_WARN_DELETE_FAILURE) {
    753     Desc = "Warning Delete Failure";
    754   } else if (Status == EFI_WARN_WRITE_FAILURE) {
    755     Desc = "Warning Write Failure";
    756   } else if (Status == EFI_WARN_BUFFER_TOO_SMALL) {
    757     Desc = "Warning Buffer Too Small";
    758   } else {
    759     Desc = NULL;
    760   }
    761   //
    762   // If we found a match, copy the message to the user's buffer. Otherwise
    763   // sprint the hex status code to their buffer.
    764   //
    765   if (Desc != NULL) {
    766     Size = ASPrint (Buffer, BufferSize, "%a", Desc);
    767   } else {
    768     Size = ASPrint (Buffer, BufferSize, "%X", Status);
    769   }
    770   return Size - 1;
    771 }
    772