1/*++
2
3Copyright (c) 2004 - 2012, Intel Corporation. All rights reserved.<BR>
4This program and the accompanying materials
5are licensed and made available under the terms and conditions of the BSD License
6which accompanies this distribution.  The full text of the license may be found at
7http://opensource.org/licenses/bsd-license.php
8
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12Module Name:
13
14  Print.c
15
16Abstract:
17
18  Basic Ascii AvSPrintf() function named VSPrint(). VSPrint() enables very
19  simple implemenation of SPrint() and Print() to support debug.
20
21  You can not Print more than EFI_DRIVER_LIB_MAX_PRINT_BUFFER characters at a
22  time. This makes the implementation very simple.
23
24  VSPrint, Print, SPrint 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    'X' - argument is a UINTN hex number, prefix '0'
43    'x' - argument is a hex number
44    'd' - argument is a decimal number
45    'a' - argument is an ascii string
46    'S','s' - argument is an Unicode string
47    'g' - argument is a pointer to an EFI_GUID
48    't' - argument is a pointer to an EFI_TIME structure
49    'c' - argument is an ascii character
50    'r' - argument is EFI_STATUS
51    '%' - Print a %
52
53--*/
54
55#include "Tiano.h"
56#include "EfiDriverLib.h"
57#include "TianoCommon.h"
58#include "EfiCommonLib.h"
59#include "PrintWidth.h"
60#include "EfiPrintLib.h"
61#include "Print.h"
62#if (EFI_SPECIFICATION_VERSION >= 0x0002000A)
63#include EFI_PROTOCOL_DEFINITION (HiiFont)
64#else
65#include EFI_PROTOCOL_DEFINITION (Hii)
66#endif
67
68
69STATIC
70UINTN
71GuidToString (
72  IN  EFI_GUID  *Guid,
73  IN OUT CHAR_W *Buffer,
74  IN  UINTN     BufferSize
75  );
76
77STATIC
78UINTN
79TimeToString (
80  IN  EFI_TIME  *Time,
81  IN OUT CHAR_W *Buffer,
82  IN  UINTN     BufferSize
83  );
84
85STATIC
86UINTN
87EfiStatusToString (
88  IN EFI_STATUS   Status,
89  OUT CHAR_W      *Buffer,
90  IN  UINTN       BufferSize
91  );
92
93static EFI_GRAPHICS_OUTPUT_BLT_PIXEL  mEfiColors[16] = {
94  {0x00, 0x00, 0x00, 0x00},
95  {0x98, 0x00, 0x00, 0x00},
96  {0x00, 0x98, 0x00, 0x00},
97  {0x98, 0x98, 0x00, 0x00},
98  {0x00, 0x00, 0x98, 0x00},
99  {0x98, 0x00, 0x98, 0x00},
100  {0x00, 0x98, 0x98, 0x00},
101  {0x98, 0x98, 0x98, 0x00},
102  {0x10, 0x10, 0x10, 0x00},
103  {0xff, 0x10, 0x10, 0x00},
104  {0x10, 0xff, 0x10, 0x00},
105  {0xff, 0xff, 0x10, 0x00},
106  {0x10, 0x10, 0xff, 0x00},
107  {0xf0, 0x10, 0xff, 0x00},
108  {0x10, 0xff, 0xff, 0x00},
109  {0xff, 0xff, 0xff, 0x00},
110};
111
112
113UINTN
114_IPrint (
115  IN EFI_GRAPHICS_OUTPUT_PROTOCOL     *GraphicsOutput,
116  IN EFI_UGA_DRAW_PROTOCOL            *UgaDraw,
117  IN EFI_SIMPLE_TEXT_OUT_PROTOCOL     *Sto,
118  IN UINTN                            X,
119  IN UINTN                            Y,
120  IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL    *Foreground,
121  IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL    *Background,
122  IN CHAR16                           *fmt,
123  IN VA_LIST                          args
124  )
125/*++
126
127Routine Description:
128
129  Display string worker for: Print, PrintAt, IPrint, IPrintAt
130
131Arguments:
132
133  GraphicsOutput  - Graphics output protocol interface
134
135  UgaDraw         - UGA draw protocol interface
136
137  Sto             - Simple text out protocol interface
138
139  X               - X coordinate to start printing
140
141  Y               - Y coordinate to start printing
142
143  Foreground      - Foreground color
144
145  Background      - Background color
146
147  fmt             - Format string
148
149  args            - Print arguments
150
151Returns:
152
153  Length of string printed to the console
154
155--*/
156{
157  VOID                           *Buffer;
158  EFI_STATUS                     Status;
159  UINTN                          Index;
160  CHAR16                         *UnicodeWeight;
161  UINT32                         HorizontalResolution;
162  UINT32                         VerticalResolution;
163  UINT32                         ColorDepth;
164  UINT32                         RefreshRate;
165  UINTN                          BufferLen;
166  UINTN                          LineBufferLen;
167#if (EFI_SPECIFICATION_VERSION >= 0x0002000A)
168  EFI_HII_FONT_PROTOCOL          *HiiFont;
169  EFI_IMAGE_OUTPUT               *Blt;
170  EFI_FONT_DISPLAY_INFO          *FontInfo;
171#else
172  EFI_HII_PROTOCOL               *Hii;
173  UINT16                         GlyphWidth;
174  UINT32                         GlyphStatus;
175  UINT16                         StringIndex;
176  EFI_NARROW_GLYPH               *Glyph;
177  EFI_GRAPHICS_OUTPUT_BLT_PIXEL  *LineBuffer;
178#endif
179
180  //
181  // For now, allocate an arbitrarily long buffer
182  //
183  BufferLen = 0;
184  Buffer = EfiLibAllocateZeroPool (0x10000);
185  if (Buffer == NULL) {
186    return 0;
187  }
188
189  if (GraphicsOutput != NULL) {
190    HorizontalResolution = GraphicsOutput->Mode->Info->HorizontalResolution;
191    VerticalResolution = GraphicsOutput->Mode->Info->VerticalResolution;
192  } else {
193    UgaDraw->GetMode (UgaDraw, &HorizontalResolution, &VerticalResolution, &ColorDepth, &RefreshRate);
194  }
195  ASSERT ((HorizontalResolution != 0) && (VerticalResolution !=0));
196
197#if (EFI_SPECIFICATION_VERSION >= 0x0002000A)
198  Blt      = NULL;
199  FontInfo = NULL;
200  ASSERT (GraphicsOutput != NULL);
201  Status = gBS->LocateProtocol (&gEfiHiiFontProtocolGuid, NULL, (VOID **) &HiiFont);
202  if (EFI_ERROR (Status)) {
203    goto Error;
204  }
205#else
206  LineBuffer = NULL;
207  Status = gBS->LocateProtocol (&gEfiHiiProtocolGuid, NULL, (VOID**)&Hii);
208  if (EFI_ERROR (Status)) {
209    goto Error;
210  }
211  LineBufferLen = sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) * HorizontalResolution * GLYPH_HEIGHT;
212  LineBuffer = EfiLibAllocatePool (LineBufferLen);
213  if (LineBuffer == NULL) {
214    Status = EFI_OUT_OF_RESOURCES;
215    goto Error;
216  }
217#endif
218
219  VSPrint (Buffer, 0x10000, fmt, args);
220
221  UnicodeWeight = (CHAR16 *) Buffer;
222
223  for (Index = 0; UnicodeWeight[Index] != 0; Index++) {
224    if (UnicodeWeight[Index] == CHAR_BACKSPACE ||
225        UnicodeWeight[Index] == CHAR_LINEFEED  ||
226        UnicodeWeight[Index] == CHAR_CARRIAGE_RETURN) {
227      UnicodeWeight[Index] = 0;
228    }
229  }
230
231  BufferLen = EfiStrLen (Buffer);
232
233
234#if (EFI_SPECIFICATION_VERSION >= 0x0002000A)
235  LineBufferLen = sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) * HorizontalResolution * EFI_GLYPH_HEIGHT;
236  if (EFI_GLYPH_WIDTH * EFI_GLYPH_HEIGHT * sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL) * BufferLen > LineBufferLen) {
237     Status = EFI_INVALID_PARAMETER;
238     goto Error;
239  }
240
241  Blt = (EFI_IMAGE_OUTPUT *) EfiLibAllocateZeroPool (sizeof (EFI_IMAGE_OUTPUT));
242  if (Blt == NULL) {
243    Status = EFI_OUT_OF_RESOURCES;
244    goto Error;
245  }
246
247  Blt->Width        = (UINT16) (HorizontalResolution);
248  Blt->Height       = (UINT16) (VerticalResolution);
249  Blt->Image.Screen = GraphicsOutput;
250
251  FontInfo = (EFI_FONT_DISPLAY_INFO *) EfiLibAllocateZeroPool (sizeof (EFI_FONT_DISPLAY_INFO));
252  if (FontInfo == NULL) {
253    Status = EFI_OUT_OF_RESOURCES;
254    goto Error;
255  }
256  if (Foreground != NULL) {
257    EfiCopyMem (&FontInfo->ForegroundColor, Foreground, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
258  } else {
259    EfiCopyMem (
260      &FontInfo->ForegroundColor,
261      &mEfiColors[Sto->Mode->Attribute & 0x0f],
262      sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
263      );
264  }
265  if (Background != NULL) {
266    EfiCopyMem (&FontInfo->BackgroundColor, Background, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
267  } else {
268    EfiCopyMem (
269      &FontInfo->BackgroundColor,
270      &mEfiColors[Sto->Mode->Attribute >> 4],
271      sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
272      );
273  }
274
275  Status = HiiFont->StringToImage (
276                       HiiFont,
277                       EFI_HII_IGNORE_IF_NO_GLYPH | EFI_HII_DIRECT_TO_SCREEN,
278                       Buffer,
279                       FontInfo,
280                       &Blt,
281                       X,
282                       Y,
283                       NULL,
284                       NULL,
285                       NULL
286                       );
287
288#else
289  GlyphStatus = 0;
290
291  if (GLYPH_WIDTH * GLYPH_HEIGHT * sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL) * BufferLen > LineBufferLen) {
292     Status = EFI_INVALID_PARAMETER;
293     goto Error;
294  }
295
296  for (Index = 0; Index < BufferLen; Index++) {
297    StringIndex = (UINT16) Index;
298    Status      = Hii->GetGlyph (Hii, UnicodeWeight, &StringIndex, (UINT8 **) &Glyph, &GlyphWidth, &GlyphStatus);
299    if (EFI_ERROR (Status)) {
300      goto Error;
301    }
302
303    if (Foreground == NULL || Background == NULL) {
304      Status = Hii->GlyphToBlt (
305                      Hii,
306                      (UINT8 *) Glyph,
307                      mEfiColors[Sto->Mode->Attribute & 0x0f],
308                      mEfiColors[Sto->Mode->Attribute >> 4],
309                      BufferLen,
310                      GlyphWidth,
311                      GLYPH_HEIGHT,
312                      &LineBuffer[Index * GLYPH_WIDTH]
313                      );
314    } else {
315      Status = Hii->GlyphToBlt (
316                      Hii,
317                      (UINT8 *) Glyph,
318                      *Foreground,
319                      *Background,
320                      BufferLen,
321                      GlyphWidth,
322                      GLYPH_HEIGHT,
323                      &LineBuffer[Index * GLYPH_WIDTH]
324                      );
325    }
326  }
327
328  //
329  // Blt a character to the screen
330  //
331  if (GraphicsOutput != NULL) {
332    Status = GraphicsOutput->Blt (
333                        GraphicsOutput,
334                        LineBuffer,
335                        EfiBltBufferToVideo,
336                        0,
337                        0,
338                        X,
339                        Y,
340                        GLYPH_WIDTH * BufferLen,
341                        GLYPH_HEIGHT,
342                        GLYPH_WIDTH * BufferLen * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
343                        );
344  } else {
345    Status = UgaDraw->Blt (
346                        UgaDraw,
347                        (EFI_UGA_PIXEL *) LineBuffer,
348                        EfiUgaBltBufferToVideo,
349                        0,
350                        0,
351                        X,
352                        Y,
353                        GLYPH_WIDTH * BufferLen,
354                        GLYPH_HEIGHT,
355                        GLYPH_WIDTH * BufferLen * sizeof (EFI_UGA_PIXEL)
356                        );
357  }
358
359#endif
360
361Error:
362#if (EFI_SPECIFICATION_VERSION >= 0x0002000A)
363  EfiLibSafeFreePool (Blt);
364  EfiLibSafeFreePool (FontInfo);
365#else
366  EfiLibSafeFreePool (LineBuffer);
367#endif
368  gBS->FreePool (Buffer);
369
370  if (EFI_ERROR (Status)) {
371    return 0;
372  }
373
374  return BufferLen;
375}
376
377
378UINTN
379PrintXY (
380  IN UINTN                            X,
381  IN UINTN                            Y,
382  IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL    *ForeGround, OPTIONAL
383  IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL    *BackGround, OPTIONAL
384  IN CHAR_W                           *Fmt,
385  ...
386  )
387/*++
388
389Routine Description:
390
391    Prints a formatted unicode string to the default console
392
393Arguments:
394
395    X           - X coordinate to start printing
396
397    Y           - Y coordinate to start printing
398
399    ForeGround  - Foreground color
400
401    BackGround  - Background color
402
403    Fmt         - Format string
404
405    ...         - Print arguments
406
407Returns:
408
409    Length of string printed to the console
410
411--*/
412{
413  EFI_HANDLE                    Handle;
414  EFI_GRAPHICS_OUTPUT_PROTOCOL  *GraphicsOutput;
415  EFI_UGA_DRAW_PROTOCOL         *UgaDraw;
416  EFI_SIMPLE_TEXT_OUT_PROTOCOL  *Sto;
417  EFI_STATUS                    Status;
418  VA_LIST                       Args;
419  UINTN                         LengthOfPrinted;
420
421  Handle = gST->ConsoleOutHandle;
422
423  GraphicsOutput = NULL;
424  UgaDraw        = NULL;
425  Status = gBS->HandleProtocol (
426                  Handle,
427                  &gEfiGraphicsOutputProtocolGuid,
428                  (VOID**)&GraphicsOutput
429                  );
430
431  if (EFI_ERROR (Status) || (GraphicsOutput == NULL)) {
432    GraphicsOutput = NULL;
433
434    Status = gBS->HandleProtocol (
435                    Handle,
436                    &gEfiUgaDrawProtocolGuid,
437                    (VOID**)&UgaDraw
438                    );
439
440    if (EFI_ERROR (Status) || (UgaDraw == NULL)) {
441      return 0;
442    }
443  }
444
445  Sto = NULL;
446  Status = gBS->HandleProtocol (
447                  Handle,
448                  &gEfiSimpleTextOutProtocolGuid,
449                  (VOID**)&Sto
450                  );
451
452  if (EFI_ERROR (Status) || (Sto == NULL)) {
453    return 0;
454  }
455
456  VA_START (Args, Fmt);
457  LengthOfPrinted = _IPrint (GraphicsOutput, UgaDraw, Sto, X, Y, ForeGround, BackGround, Fmt, Args);
458  VA_END (Args);
459  return LengthOfPrinted;
460}
461
462
463UINTN
464SPrint (
465  OUT CHAR_W        *Buffer,
466  IN  UINTN         BufferSize,
467  IN  CONST CHAR_W  *Format,
468  ...
469  )
470/*++
471
472Routine Description:
473
474  SPrint function to process format and place the results in Buffer.
475
476Arguments:
477
478  Buffer     - Wide char buffer to print the results of the parsing of Format into.
479
480  BufferSize - Maximum number of characters to put into buffer. Zero means no
481               limit.
482
483  Format - Format string see file header for more details.
484
485  ...    - Vararg list consumed by processing Format.
486
487Returns:
488
489  Number of characters printed.
490
491--*/
492{
493  UINTN   Return;
494  VA_LIST Marker;
495
496  VA_START (Marker, Format);
497  Return = VSPrint (Buffer, BufferSize, Format, Marker);
498  VA_END (Marker);
499
500  return Return;
501}
502
503UINTN
504EFIAPI
505VSPrint (
506  OUT CHAR_W        *StartOfBuffer,
507  IN  UINTN         BufferSize,
508  IN  CONST CHAR_W  *FormatString,
509  IN  VA_LIST       Marker
510  )
511/*++
512
513Routine Description:
514
515  VSPrint function to process format and place the results in Buffer. Since a
516  VA_LIST is used this rountine allows the nesting of Vararg routines. Thus
517  this is the main print working routine
518
519Arguments:
520
521  StartOfBuffer - Unicode buffer to print the results of the parsing of Format into.
522
523  BufferSize    - Maximum number of characters to put into buffer. Zero means
524                  no limit.
525
526  FormatString  - Unicode format string see file header for more details.
527
528  Marker        - Vararg list consumed by processing Format.
529
530Returns:
531
532  Number of characters printed.
533
534--*/
535{
536  CHAR16    TempBuffer[CHARACTER_NUMBER_FOR_VALUE];
537  CHAR_W    *Buffer;
538  CHAR8     *AsciiStr;
539  CHAR16    *UnicodeStr;
540  CHAR_W    *Format;
541  UINTN     Index;
542  UINTN     Flags;
543  UINTN     Width;
544  UINTN     Count;
545  UINTN     NumberOfCharacters;
546  UINTN     BufferLeft;
547  UINT64    Value;
548  EFI_GUID  *TmpGUID;
549  BOOLEAN   Done;
550
551  //
552  // Process the format string. Stop if Buffer is over run.
553  //
554
555  Buffer              = StartOfBuffer;
556  Format              = (CHAR_W *) FormatString;
557  NumberOfCharacters  = BufferSize / sizeof (CHAR_W);
558  BufferLeft          = BufferSize;
559  for (Index = 0; (*Format != '\0') && (Index < NumberOfCharacters - 1); Format++) {
560    if (*Format != '%') {
561      if ((*Format == '\n') && (Index < NumberOfCharacters - 2)) {
562        //
563        // If carage return add line feed
564        //
565        Buffer[Index++] = '\r';
566        BufferLeft -= sizeof (CHAR_W);
567      }
568
569      Buffer[Index++] = *Format;
570      BufferLeft -= sizeof (CHAR_W);
571    } else {
572
573      //
574      // Now it's time to parse what follows after %
575      //
576      Flags  = 0;
577      Width  = 0;
578      for (Done = FALSE; !Done;) {
579        Format++;
580
581        switch (*Format) {
582
583        case '-':
584          Flags |= LEFT_JUSTIFY;
585          break;
586
587        case '+':
588          Flags |= PREFIX_SIGN;
589          break;
590
591        case ' ':
592          Flags |= PREFIX_BLANK;
593          break;
594
595        case ',':
596          Flags |= COMMA_TYPE;
597          break;
598
599        case 'L':
600        case 'l':
601          Flags |= LONG_TYPE;
602          break;
603
604        case '*':
605          Width = VA_ARG (Marker, UINTN);
606          break;
607
608        case '0':
609          Flags |= PREFIX_ZERO;
610
611        case '1':
612        case '2':
613        case '3':
614        case '4':
615        case '5':
616        case '6':
617        case '7':
618        case '8':
619        case '9':
620          Count = 0;
621          do {
622            Count = (Count * 10) +*Format - '0';
623            Format++;
624          } while ((*Format >= '0') && (*Format <= '9'));
625          Format--;
626          Width = Count;
627          break;
628
629        default:
630          Done = TRUE;
631        }
632      }
633
634      switch (*Format) {
635      case 'p':
636        //
637        // Flag space, +, 0, L & l are invalid for type p.
638        //
639        Flags &= ~(PREFIX_BLANK| PREFIX_SIGN | LONG_TYPE);
640        if (sizeof (VOID *) > 4) {
641          Flags |= LONG_TYPE;
642          Value = VA_ARG (Marker, UINT64);
643        } else {
644          Value = VA_ARG (Marker, UINTN);
645        }
646        Flags |= PREFIX_ZERO;
647
648        EfiValueToHexStr (TempBuffer, Value, Flags, Width);
649        UnicodeStr = TempBuffer;
650
651        for ( ;(*UnicodeStr != '\0') && (Index < NumberOfCharacters - 1); UnicodeStr++) {
652          Buffer[Index++] = *UnicodeStr;
653        }
654        break;
655
656      case 'X':
657        Flags |= PREFIX_ZERO;
658        Width = sizeof (UINT64) * 2;
659
660      //
661      // break skiped on purpose
662      //
663      case 'x':
664        if ((Flags & LONG_TYPE) == LONG_TYPE) {
665          Value = VA_ARG (Marker, UINT64);
666        } else {
667          Value = VA_ARG (Marker, UINTN);
668        }
669
670        EfiValueToHexStr (TempBuffer, Value, Flags, Width);
671        UnicodeStr = TempBuffer;
672
673        for (; (*UnicodeStr != '\0') && (Index < NumberOfCharacters - 1); UnicodeStr++) {
674          Buffer[Index++] = *UnicodeStr;
675        }
676        break;
677
678      case 'd':
679        if ((Flags & LONG_TYPE) == LONG_TYPE) {
680          Value = VA_ARG (Marker, UINT64);
681        } else {
682          Value = (UINTN) VA_ARG (Marker, UINTN);
683        }
684
685        EfiValueToString (TempBuffer, Value, Flags, Width);
686        UnicodeStr = TempBuffer;
687
688        for (; (*UnicodeStr != '\0') && (Index < NumberOfCharacters - 1); UnicodeStr++) {
689          Buffer[Index++] = *UnicodeStr;
690        }
691        break;
692
693      case 's':
694      case 'S':
695        UnicodeStr = (CHAR16 *) VA_ARG (Marker, CHAR_W *);
696        if (UnicodeStr == NULL) {
697          UnicodeStr = L"<null string>";
698        }
699
700        for (Count = 0; (*UnicodeStr != '\0') && (Index < NumberOfCharacters - 1); UnicodeStr++, Count++) {
701          Buffer[Index++] = *UnicodeStr;
702        }
703        //
704        // Add padding if needed
705        //
706        for (; (Count < Width) && (Index < NumberOfCharacters - 1); Count++) {
707          Buffer[Index++] = ' ';
708        }
709
710        break;
711
712      case 'a':
713        AsciiStr = (CHAR8 *) VA_ARG (Marker, CHAR8 *);
714        if (AsciiStr == NULL) {
715          AsciiStr = (CHAR8 *) "<null string>";
716        }
717
718        for (Count = 0; (*AsciiStr != '\0') && (Index < NumberOfCharacters - 1); AsciiStr++, Count++) {
719          Buffer[Index++] = (CHAR_W) * AsciiStr;
720        }
721        //
722        // Add padding if needed
723        //
724        for (; (Count < Width) && (Index < NumberOfCharacters - 1); Count++) {
725          Buffer[Index++] = ' ';
726        }
727        break;
728
729      case 'c':
730        Buffer[Index++] = (CHAR_W) VA_ARG (Marker, UINTN);
731        break;
732
733      case 'g':
734        TmpGUID = VA_ARG (Marker, EFI_GUID *);
735        if (TmpGUID != NULL) {
736          Index += GuidToString (
737                    TmpGUID,
738                    &Buffer[Index],
739                    BufferLeft
740                    );
741        }
742        break;
743
744      case 't':
745        Index += TimeToString (
746                  VA_ARG (Marker, EFI_TIME *),
747                  &Buffer[Index],
748                  BufferLeft
749                  );
750        break;
751
752      case 'r':
753        Index += EfiStatusToString (
754                  VA_ARG (Marker, EFI_STATUS),
755                  &Buffer[Index],
756                  BufferLeft
757                  );
758        break;
759
760      case '%':
761        Buffer[Index++] = *Format;
762        break;
763
764      default:
765        //
766        // if the type is unknown print it to the screen
767        //
768        Buffer[Index++] = *Format;
769      }
770
771      BufferLeft = BufferSize - Index * sizeof (CHAR_W);
772    }
773  }
774
775  Buffer[Index++] = '\0';
776
777  return &Buffer[Index] - StartOfBuffer;
778}
779
780STATIC
781UINTN
782GuidToString (
783  IN  EFI_GUID  *Guid,
784  IN  CHAR_W    *Buffer,
785  IN  UINTN     BufferSize
786  )
787/*++
788
789Routine Description:
790
791  VSPrint worker function that prints an EFI_GUID.
792
793Arguments:
794
795  Guid       - Pointer to GUID to print.
796
797  Buffer     - Buffe to print Guid into.
798
799  BufferSize - Size of Buffer.
800
801Returns:
802
803  Number of characters printed.
804
805--*/
806{
807  UINTN Size;
808
809  Size = SPrint (
810          Buffer,
811          BufferSize,
812          STRING_W ("%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x"),
813          (UINTN)Guid->Data1,
814          (UINTN)Guid->Data2,
815          (UINTN)Guid->Data3,
816          (UINTN)Guid->Data4[0],
817          (UINTN)Guid->Data4[1],
818          (UINTN)Guid->Data4[2],
819          (UINTN)Guid->Data4[3],
820          (UINTN)Guid->Data4[4],
821          (UINTN)Guid->Data4[5],
822          (UINTN)Guid->Data4[6],
823          (UINTN)Guid->Data4[7]
824          );
825
826  //
827  // SPrint will null terminate the string. The -1 skips the null
828  //
829  return Size - 1;
830}
831
832
833STATIC
834UINTN
835TimeToString (
836  IN EFI_TIME   *Time,
837  OUT CHAR_W    *Buffer,
838  IN  UINTN     BufferSize
839  )
840/*++
841
842Routine Description:
843
844  VSPrint worker function that prints EFI_TIME.
845
846Arguments:
847
848  Time       - Pointer to EFI_TIME sturcture to print.
849
850  Buffer     - Buffer to print Time into.
851
852  BufferSize - Size of Buffer.
853
854Returns:
855
856  Number of characters printed.
857
858--*/
859{
860  UINTN Size;
861
862  Size = SPrint (
863          Buffer,
864          BufferSize,
865          STRING_W ("%02d/%02d/%04d  %02d:%02d"),
866          (UINTN)Time->Month,
867          (UINTN)Time->Day,
868          (UINTN)Time->Year,
869          (UINTN)Time->Hour,
870          (UINTN)Time->Minute
871          );
872
873  //
874  // SPrint will null terminate the string. The -1 skips the null
875  //
876  return Size - 1;
877}
878
879STATIC
880UINTN
881EfiStatusToString (
882  IN EFI_STATUS   Status,
883  OUT CHAR_W      *Buffer,
884  IN  UINTN       BufferSize
885  )
886/*++
887
888Routine Description:
889
890  VSPrint worker function that prints EFI_STATUS as a string. If string is
891  not known a hex value will be printed.
892
893Arguments:
894
895  Status     -  EFI_STATUS sturcture to print.
896
897  Buffer     - Buffer to print EFI_STATUS message string into.
898
899  BufferSize - Size of Buffer.
900
901Returns:
902
903  Number of characters printed.
904
905--*/
906{
907  UINTN   Size;
908  CHAR8   *Desc;
909
910  Desc = NULL;
911
912  //
913  // Can't use global Status String Array as UINTN is not constant for EBC
914  //
915  if (Status == EFI_SUCCESS) { Desc = (CHAR8 *) "Success"; } else
916  if (Status == EFI_LOAD_ERROR) { Desc = (CHAR8 *) "Load Error"; } else
917  if (Status == EFI_INVALID_PARAMETER) { Desc = (CHAR8 *) "Invalid Parameter"; } else
918  if (Status == EFI_UNSUPPORTED) { Desc = (CHAR8 *) "Unsupported"; } else
919  if (Status == EFI_BAD_BUFFER_SIZE) { Desc = (CHAR8 *) "Bad Buffer Size"; } else
920  if (Status == EFI_BUFFER_TOO_SMALL) { Desc = (CHAR8 *) "Buffer Too Small"; } else
921  if (Status == EFI_NOT_READY) { Desc = (CHAR8 *) "Not Ready"; } else
922  if (Status == EFI_DEVICE_ERROR) { Desc = (CHAR8 *) "Device Error"; } else
923  if (Status == EFI_WRITE_PROTECTED) { Desc = (CHAR8 *) "Write Protected"; } else
924  if (Status == EFI_OUT_OF_RESOURCES) { Desc = (CHAR8 *) "Out of Resources"; } else
925  if (Status == EFI_VOLUME_CORRUPTED) { Desc = (CHAR8 *) "Volume Corrupt"; } else
926  if (Status == EFI_VOLUME_FULL) { Desc = (CHAR8 *) "Volume Full"; } else
927  if (Status == EFI_NO_MEDIA) { Desc = (CHAR8 *) "No Media"; } else
928  if (Status == EFI_MEDIA_CHANGED) { Desc = (CHAR8 *) "Media changed"; } else
929  if (Status == EFI_NOT_FOUND) { Desc = (CHAR8 *) "Not Found"; } else
930  if (Status == EFI_ACCESS_DENIED) { Desc = (CHAR8 *) "Access Denied"; } else
931  if (Status == EFI_NO_RESPONSE) { Desc = (CHAR8 *) "No Response"; } else
932  if (Status == EFI_NO_MAPPING) { Desc = (CHAR8 *) "No mapping"; } else
933  if (Status == EFI_TIMEOUT) { Desc = (CHAR8 *) "Time out"; } else
934  if (Status == EFI_NOT_STARTED) { Desc = (CHAR8 *) "Not started"; } else
935  if (Status == EFI_ALREADY_STARTED) { Desc = (CHAR8 *) "Already started"; } else
936  if (Status == EFI_ABORTED) { Desc = (CHAR8 *) "Aborted"; } else
937  if (Status == EFI_ICMP_ERROR) { Desc = (CHAR8 *) "ICMP Error"; } else
938  if (Status == EFI_TFTP_ERROR) { Desc = (CHAR8 *) "TFTP Error"; } else
939  if (Status == EFI_PROTOCOL_ERROR) { Desc = (CHAR8 *) "Protocol Error"; } else
940  if (Status == EFI_WARN_UNKNOWN_GLYPH) { Desc = (CHAR8 *) "Warning Unknown Glyph"; } else
941  if (Status == EFI_WARN_DELETE_FAILURE) { Desc = (CHAR8 *) "Warning Delete Failure"; } else
942  if (Status == EFI_WARN_WRITE_FAILURE) { Desc = (CHAR8 *) "Warning Write Failure"; } else
943  if (Status == EFI_WARN_BUFFER_TOO_SMALL) { Desc = (CHAR8 *) "Warning Buffer Too Small"; }
944
945  //
946  // If we found a match, copy the message to the user's buffer. Otherwise
947  // sprint the hex status code to their buffer.
948  //
949  if (Desc != NULL) {
950    Size = SPrint (Buffer, BufferSize, STRING_W ("%a"), Desc);
951  } else {
952    Size = SPrint (Buffer, BufferSize, STRING_W ("%X"), Status);
953  }
954
955  return Size - 1;
956}
957