xref: /netbsd-src/sys/external/bsd/gnu-efi/dist/lib/print.c (revision 35ff39e48f27cc4d27af726cb651cda505a965b4)
1 /*	$NetBSD: print.c,v 1.5 2021/09/30 19:02:48 jmcneill Exp $	*/
2 
3 /*++
4 
5 Copyright (c) 1998  Intel Corporation
6 
7 Module Name:
8 
9     print.c
10 
11 Abstract:
12 
13 
14 
15 
16 Revision History
17 
18 --*/
19 
20 #include "lib.h"
21 #include "efistdarg.h"                        // !!!
22 
23 //
24 // Declare runtime functions
25 //
26 
27 #ifdef RUNTIME_CODE
28 #ifndef __GNUC__
29 #pragma RUNTIME_CODE(DbgPrint)
30 
31 // For debugging..
32 
33 /*
34 #pragma RUNTIME_CODE(_Print)
35 #pragma RUNTIME_CODE(PFLUSH)
36 #pragma RUNTIME_CODE(PSETATTR)
37 #pragma RUNTIME_CODE(PPUTC)
38 #pragma RUNTIME_CODE(PGETC)
39 #pragma RUNTIME_CODE(PITEM)
40 #pragma RUNTIME_CODE(ValueToHex)
41 #pragma RUNTIME_CODE(ValueToString)
42 #pragma RUNTIME_CODE(TimeToString)
43 */
44 
45 #endif /* !defined(__GNUC__) */
46 #endif
47 
48 //
49 //
50 //
51 
52 
53 #define PRINT_STRING_LEN            200
54 #define PRINT_ITEM_BUFFER_LEN       100
55 
56 typedef struct {
57     BOOLEAN             Ascii;
58     UINTN               Index;
59     union {
60         CONST CHAR16    *pw;
61         CONST CHAR8     *pc;
62     } un;
63 } POINTER;
64 
65 #define pw	un.pw
66 #define pc	un.pc
67 
68 typedef struct _pitem {
69 
70     POINTER     Item;
71     CHAR16      Scratch[PRINT_ITEM_BUFFER_LEN];
72     UINTN       Width;
73     UINTN       FieldWidth;
74     UINTN       *WidthParse;
75     CHAR16      Pad;
76     BOOLEAN     PadBefore;
77     BOOLEAN     Comma;
78     BOOLEAN     Long;
79 } PRINT_ITEM;
80 
81 
82 typedef struct _pstate {
83     // Input
84     POINTER     fmt;
85     va_list     args;
86 
87     // Output
88     CHAR16      *Buffer;
89     CHAR16      *End;
90     CHAR16      *Pos;
91     UINTN       Len;
92 
93     UINTN       Attr;
94     UINTN       RestoreAttr;
95 
96     UINTN       AttrNorm;
97     UINTN       AttrHighlight;
98     UINTN       AttrError;
99 
100     INTN        (EFIAPI *Output)(VOID *context, CHAR16 *str);
101     INTN        (EFIAPI *SetAttr)(VOID *context, UINTN attr);
102     VOID        *Context;
103 
104     // Current item being formatted
105     struct _pitem  *Item;
106 } PRINT_STATE;
107 
108 //
109 // Internal fucntions
110 //
111 
112 STATIC
113 UINTN
114 _Print (
115     IN PRINT_STATE     *ps
116     );
117 
118 STATIC
119 UINTN
120 _IPrint (
121     IN UINTN                            Column,
122     IN UINTN                            Row,
123     IN SIMPLE_TEXT_OUTPUT_INTERFACE     *Out,
124     IN CONST CHAR16                     *fmt,
125     IN CONST CHAR8                      *fmta,
126     IN va_list                          args
127     );
128 
129 STATIC
130 INTN EFIAPI
131 _DbgOut (
132     IN VOID     *Context,
133     IN CHAR16   *Buffer
134     );
135 
136 STATIC
137 VOID
138 PFLUSH (
139     IN OUT PRINT_STATE     *ps
140     );
141 
142 STATIC
143 VOID
144 PPUTC (
145     IN OUT PRINT_STATE     *ps,
146     IN CHAR16              c
147     );
148 
149 STATIC
150 VOID
151 PITEM (
152     IN OUT PRINT_STATE  *ps
153     );
154 
155 STATIC
156 CHAR16
157 PGETC (
158     IN POINTER      *p
159     );
160 
161 STATIC
162 VOID
163 PSETATTR (
164     IN OUT PRINT_STATE  *ps,
165     IN UINTN             Attr
166     );
167 
168 //
169 //
170 //
171 
172 INTN EFIAPI
173 _SPrint (
174     IN VOID     *Context,
175     IN CHAR16   *Buffer
176     );
177 
178 INTN EFIAPI
179 _PoolPrint (
180     IN VOID     *Context,
181     IN CHAR16   *Buffer
182     );
183 
184 INTN
DbgPrint(IN INTN mask,IN CONST CHAR8 * fmt,...)185 DbgPrint (
186     IN INTN         mask,
187     IN CONST CHAR8  *fmt,
188     ...
189     )
190 /*++
191 
192 Routine Description:
193 
194     Prints a formatted unicode string to the default StandardError console
195 
196 Arguments:
197 
198     mask        - Bit mask of debug string.  If a bit is set in the
199                   mask that is also set in EFIDebug the string is
200                   printed; otherwise, the string is not printed
201 
202     fmt         - Format string
203 
204 Returns:
205 
206     Length of string printed to the StandardError console
207 
208 --*/
209 {
210     SIMPLE_TEXT_OUTPUT_INTERFACE    *DbgOut;
211     PRINT_STATE     ps;
212     va_list         args;
213     UINTN           back;
214     UINTN           attr;
215     UINTN           SavedAttribute;
216 
217 
218     if (!(EFIDebug & mask)) {
219         return 0;
220     }
221 
222     va_start (args, fmt);
223     ZeroMem (&ps, sizeof(ps));
224 
225     ps.Output = _DbgOut;
226     ps.fmt.Ascii = TRUE;
227     ps.fmt.pc = fmt;
228     va_copy(ps.args, args);
229     ps.Attr = EFI_TEXT_ATTR(EFI_LIGHTGRAY, EFI_RED);
230 
231     DbgOut = LibRuntimeDebugOut;
232 
233     if (!DbgOut) {
234         DbgOut = ST->StdErr;
235     }
236 
237     if (DbgOut) {
238         ps.Attr = DbgOut->Mode->Attribute;
239         ps.Context = DbgOut;
240         ps.SetAttr = (INTN (EFIAPI *)(VOID *, UINTN))  DbgOut->SetAttribute;
241     }
242 
243     SavedAttribute = ps.Attr;
244 
245     back = (ps.Attr >> 4) & 0xf;
246     ps.AttrNorm = EFI_TEXT_ATTR(EFI_LIGHTGRAY, back);
247     ps.AttrHighlight = EFI_TEXT_ATTR(EFI_WHITE, back);
248     ps.AttrError = EFI_TEXT_ATTR(EFI_YELLOW, back);
249 
250     attr = ps.AttrNorm;
251 
252     if (mask & D_WARN) {
253         attr = ps.AttrHighlight;
254     }
255 
256     if (mask & D_ERROR) {
257         attr = ps.AttrError;
258     }
259 
260     if (ps.SetAttr) {
261         ps.Attr = attr;
262         uefi_call_wrapper(ps.SetAttr, 2, ps.Context, attr);
263     }
264 
265     _Print (&ps);
266 
267     va_end (ps.args);
268     va_end (args);
269 
270     //
271     // Restore original attributes
272     //
273 
274     if (ps.SetAttr) {
275         uefi_call_wrapper(ps.SetAttr, 2, ps.Context, SavedAttribute);
276     }
277 
278     return 0;
279 }
280 
281 STATIC
282 INTN
IsLocalPrint(void * func)283 IsLocalPrint(void *func)
284 {
285 	if (func == _DbgOut || func == _SPrint || func == _PoolPrint)
286 		return 1;
287 	return 0;
288 }
289 
290 STATIC
291 INTN EFIAPI
_DbgOut(IN VOID * Context,IN CHAR16 * Buffer)292 _DbgOut (
293     IN VOID     *Context,
294     IN CHAR16   *Buffer
295     )
296 // Append string worker for DbgPrint
297 {
298     SIMPLE_TEXT_OUTPUT_INTERFACE    *DbgOut;
299 
300     DbgOut = Context;
301 //    if (!DbgOut && ST && ST->ConOut) {
302 //        DbgOut = ST->ConOut;
303 //    }
304 
305     if (DbgOut) {
306 	if (IsLocalPrint(DbgOut->OutputString))
307 		DbgOut->OutputString(DbgOut, Buffer);
308         else
309 		uefi_call_wrapper(DbgOut->OutputString, 2, DbgOut, Buffer);
310     }
311 
312     return 0;
313 }
314 
315 INTN EFIAPI
_SPrint(IN VOID * Context,IN CHAR16 * Buffer)316 _SPrint (
317     IN VOID     *Context,
318     IN CHAR16   *Buffer
319     )
320 // Append string worker for UnicodeSPrint, PoolPrint and CatPrint
321 {
322     UINTN           len;
323     POOL_PRINT      *spc;
324 
325     spc = Context;
326     len = StrLen(Buffer);
327 
328     //
329     // Is the string is over the max truncate it
330     //
331 
332     if (spc->len + len > spc->maxlen) {
333         len = spc->maxlen - spc->len;
334     }
335 
336     //
337     // Append the new text
338     //
339 
340     CopyMem (spc->str + spc->len, Buffer, len * sizeof(CHAR16));
341     spc->len += len;
342 
343     //
344     // Null terminate it
345     //
346 
347     if (spc->len < spc->maxlen) {
348         spc->str[spc->len] = 0;
349     } else if (spc->maxlen) {
350         spc->str[spc->maxlen] = 0;
351     }
352 
353     return 0;
354 }
355 
356 
357 INTN EFIAPI
_PoolPrint(IN VOID * Context,IN CHAR16 * Buffer)358 _PoolPrint (
359     IN VOID     *Context,
360     IN CHAR16   *Buffer
361     )
362 // Append string worker for PoolPrint and CatPrint
363 {
364     UINTN           newlen;
365     POOL_PRINT      *spc;
366 
367     spc = Context;
368     newlen = spc->len + StrLen(Buffer) + 1;
369 
370     //
371     // Is the string is over the max, grow the buffer
372     //
373 
374     if (newlen > spc->maxlen) {
375 
376         //
377         // Grow the pool buffer
378         //
379 
380         newlen += PRINT_STRING_LEN;
381         spc->maxlen = newlen;
382         spc->str = ReallocatePool (
383                         spc->str,
384                         spc->len * sizeof(CHAR16),
385                         spc->maxlen * sizeof(CHAR16)
386                         );
387 
388         if (!spc->str) {
389             spc->len = 0;
390             spc->maxlen = 0;
391         }
392     }
393 
394     //
395     // Append the new text
396     //
397 
398     return _SPrint (Context, Buffer);
399 }
400 
401 
402 
403 VOID
_PoolCatPrint(IN CONST CHAR16 * fmt,IN va_list args,IN OUT POOL_PRINT * spc,IN INTN (EFIAPI * Output)(VOID * context,CHAR16 * str))404 _PoolCatPrint (
405     IN CONST CHAR16     *fmt,
406     IN va_list          args,
407     IN OUT POOL_PRINT   *spc,
408     IN INTN             (EFIAPI *Output)(VOID *context, CHAR16 *str)
409     )
410 // Dispatch function for UnicodeSPrint, PoolPrint, and CatPrint
411 {
412     PRINT_STATE         ps;
413 
414     ZeroMem (&ps, sizeof(ps));
415     ps.Output  = Output;
416     ps.Context = spc;
417     ps.fmt.pw = fmt;
418     va_copy(ps.args, args);
419     _Print (&ps);
420     va_end(ps.args);
421 }
422 
423 
424 
425 UINTN
UnicodeVSPrint(OUT CHAR16 * Str,IN UINTN StrSize,IN CONST CHAR16 * fmt,va_list args)426 UnicodeVSPrint (
427     OUT CHAR16        *Str,
428     IN UINTN          StrSize,
429     IN CONST CHAR16   *fmt,
430     va_list           args
431     )
432 /*++
433 
434 Routine Description:
435 
436     Prints a formatted unicode string to a buffer using a va_list
437 
438 Arguments:
439 
440     Str         - Output buffer to print the formatted string into
441 
442     StrSize     - Size of Str.  String is truncated to this size.
443                   A size of 0 means there is no limit
444 
445     fmt         - The format string
446 
447     args        - va_list
448 
449 
450 Returns:
451 
452     String length returned in buffer
453 
454 --*/
455 {
456     POOL_PRINT          spc;
457 
458     spc.str    = Str;
459     spc.maxlen = StrSize / sizeof(CHAR16) - 1;
460     spc.len    = 0;
461 
462     _PoolCatPrint (fmt, args, &spc, _SPrint);
463 
464     return spc.len;
465 }
466 
467 UINTN
UnicodeSPrint(OUT CHAR16 * Str,IN UINTN StrSize,IN CONST CHAR16 * fmt,...)468 UnicodeSPrint (
469     OUT CHAR16        *Str,
470     IN UINTN          StrSize,
471     IN CONST CHAR16   *fmt,
472     ...
473     )
474 /*++
475 
476 Routine Description:
477 
478     Prints a formatted unicode string to a buffer
479 
480 Arguments:
481 
482     Str         - Output buffer to print the formatted string into
483 
484     StrSize     - Size of Str.  String is truncated to this size.
485                   A size of 0 means there is no limit
486 
487     fmt         - The format string
488 
489 Returns:
490 
491     String length returned in buffer
492 
493 --*/
494 {
495     va_list          args;
496     UINTN            len;
497 
498     va_start (args, fmt);
499     len = UnicodeVSPrint(Str, StrSize, fmt, args);
500     va_end (args);
501 
502     return len;
503 }
504 
505 CHAR16 *
VPoolPrint(IN CONST CHAR16 * fmt,va_list args)506 VPoolPrint (
507     IN CONST CHAR16     *fmt,
508     va_list             args
509     )
510 /*++
511 
512 Routine Description:
513 
514     Prints a formatted unicode string to allocated pool using va_list argument.
515     The caller must free the resulting buffer.
516 
517 Arguments:
518 
519     fmt         - The format string
520     args        - The arguments in va_list form
521 
522 Returns:
523 
524     Allocated buffer with the formatted string printed in it.
525     The caller must free the allocated buffer.   The buffer
526     allocation is not packed.
527 
528 --*/
529 {
530     POOL_PRINT          spc;
531     ZeroMem (&spc, sizeof(spc));
532     _PoolCatPrint (fmt, args, &spc, _PoolPrint);
533     return spc.str;
534 }
535 
536 CHAR16 *
PoolPrint(IN CONST CHAR16 * fmt,...)537 PoolPrint (
538     IN CONST CHAR16     *fmt,
539     ...
540     )
541 /*++
542 
543 Routine Description:
544 
545     Prints a formatted unicode string to allocated pool.  The caller
546     must free the resulting buffer.
547 
548 Arguments:
549 
550     fmt         - The format string
551 
552 Returns:
553 
554     Allocated buffer with the formatted string printed in it.
555     The caller must free the allocated buffer.   The buffer
556     allocation is not packed.
557 
558 --*/
559 {
560     va_list args;
561     CHAR16 *pool;
562     va_start (args, fmt);
563     pool = VPoolPrint(fmt, args);
564     va_end (args);
565     return pool;
566 }
567 
568 CHAR16 *
CatPrint(IN OUT POOL_PRINT * Str,IN CONST CHAR16 * fmt,...)569 CatPrint (
570     IN OUT POOL_PRINT   *Str,
571     IN CONST CHAR16     *fmt,
572     ...
573     )
574 /*++
575 
576 Routine Description:
577 
578     Concatenates a formatted unicode string to allocated pool.
579     The caller must free the resulting buffer.
580 
581 Arguments:
582 
583     Str         - Tracks the allocated pool, size in use, and
584                   amount of pool allocated.
585 
586     fmt         - The format string
587 
588 Returns:
589 
590     Allocated buffer with the formatted string printed in it.
591     The caller must free the allocated buffer.   The buffer
592     allocation is not packed.
593 
594 --*/
595 {
596     va_list             args;
597 
598     va_start (args, fmt);
599     _PoolCatPrint (fmt, args, Str, _PoolPrint);
600     va_end (args);
601     return Str->str;
602 }
603 
604 
605 
606 UINTN
Print(IN CONST CHAR16 * fmt,...)607 Print (
608     IN CONST CHAR16   *fmt,
609     ...
610     )
611 /*++
612 
613 Routine Description:
614 
615     Prints a formatted unicode string to the default console
616 
617 Arguments:
618 
619     fmt         - Format string
620 
621 Returns:
622 
623     Length of string printed to the console
624 
625 --*/
626 {
627     va_list     args;
628     UINTN       back;
629 
630     va_start (args, fmt);
631     back = _IPrint ((UINTN) -1, (UINTN) -1, ST->ConOut, fmt, NULL, args);
632     va_end (args);
633     return back;
634 }
635 
636 UINTN
VPrint(IN CONST CHAR16 * fmt,va_list args)637 VPrint (
638     IN CONST CHAR16   *fmt,
639     va_list           args
640     )
641 /*++
642 
643 Routine Description:
644 
645     Prints a formatted unicode string to the default console using a va_list
646 
647 Arguments:
648 
649     fmt         - Format string
650     args        - va_list
651 Returns:
652 
653     Length of string printed to the console
654 
655 --*/
656 {
657     return _IPrint ((UINTN) -1, (UINTN) -1, ST->ConOut, fmt, NULL, args);
658 }
659 
660 
661 UINTN
PrintAt(IN UINTN Column,IN UINTN Row,IN CONST CHAR16 * fmt,...)662 PrintAt (
663     IN UINTN          Column,
664     IN UINTN          Row,
665     IN CONST CHAR16   *fmt,
666     ...
667     )
668 /*++
669 
670 Routine Description:
671 
672     Prints a formatted unicode string to the default console, at
673     the supplied cursor position
674 
675 Arguments:
676 
677     Column, Row - The cursor position to print the string at
678 
679     fmt         - Format string
680 
681 Returns:
682 
683     Length of string printed to the console
684 
685 --*/
686 {
687     va_list     args;
688     UINTN       back;
689 
690     va_start (args, fmt);
691     back = _IPrint (Column, Row, ST->ConOut, fmt, NULL, args);
692     va_end (args);
693     return back;
694 }
695 
696 
697 UINTN
IPrint(IN SIMPLE_TEXT_OUTPUT_INTERFACE * Out,IN CONST CHAR16 * fmt,...)698 IPrint (
699     IN SIMPLE_TEXT_OUTPUT_INTERFACE    *Out,
700     IN CONST CHAR16                    *fmt,
701     ...
702     )
703 /*++
704 
705 Routine Description:
706 
707     Prints a formatted unicode string to the specified console
708 
709 Arguments:
710 
711     Out         - The console to print the string too
712 
713     fmt         - Format string
714 
715 Returns:
716 
717     Length of string printed to the console
718 
719 --*/
720 {
721     va_list     args;
722     UINTN       back;
723 
724     va_start (args, fmt);
725     back = _IPrint ((UINTN) -1, (UINTN) -1, Out, fmt, NULL, args);
726     va_end (args);
727     return back;
728 }
729 
730 
731 UINTN
IPrintAt(IN SIMPLE_TEXT_OUTPUT_INTERFACE * Out,IN UINTN Column,IN UINTN Row,IN CONST CHAR16 * fmt,...)732 IPrintAt (
733     IN SIMPLE_TEXT_OUTPUT_INTERFACE     *Out,
734     IN UINTN                            Column,
735     IN UINTN                            Row,
736     IN CONST CHAR16                     *fmt,
737     ...
738     )
739 /*++
740 
741 Routine Description:
742 
743     Prints a formatted unicode string to the specified console, at
744     the supplied cursor position
745 
746 Arguments:
747 
748     Out         - The console to print the string to
749 
750     Column, Row - The cursor position to print the string at
751 
752     fmt         - Format string
753 
754 Returns:
755 
756     Length of string printed to the console
757 
758 --*/
759 {
760     va_list     args;
761     UINTN       back;
762 
763     va_start (args, fmt);
764     back = _IPrint (Column, Row, Out, fmt, NULL, args);
765     va_end (args);
766     return back;
767 }
768 
769 
770 UINTN
_IPrint(IN UINTN Column,IN UINTN Row,IN SIMPLE_TEXT_OUTPUT_INTERFACE * Out,IN CONST CHAR16 * fmt,IN CONST CHAR8 * fmta,IN va_list args)771 _IPrint (
772     IN UINTN                            Column,
773     IN UINTN                            Row,
774     IN SIMPLE_TEXT_OUTPUT_INTERFACE     *Out,
775     IN CONST CHAR16                     *fmt,
776     IN CONST CHAR8                      *fmta,
777     IN va_list                          args
778     )
779 // Display string worker for: Print, PrintAt, IPrint, IPrintAt
780 {
781     PRINT_STATE     ps;
782     UINTN            back;
783 
784     ZeroMem (&ps, sizeof(ps));
785     ps.Context = Out;
786     ps.Output  = (INTN (EFIAPI *)(VOID *, CHAR16 *)) Out->OutputString;
787     ps.SetAttr = (INTN (EFIAPI *)(VOID *, UINTN))  Out->SetAttribute;
788     ps.Attr = Out->Mode->Attribute;
789 
790     back = (ps.Attr >> 4) & 0xF;
791     ps.AttrNorm = EFI_TEXT_ATTR(EFI_LIGHTGRAY, back);
792     ps.AttrHighlight = EFI_TEXT_ATTR(EFI_WHITE, back);
793     ps.AttrError = EFI_TEXT_ATTR(EFI_YELLOW, back);
794 
795     if (fmt) {
796         ps.fmt.pw = fmt;
797     } else {
798         ps.fmt.Ascii = TRUE;
799         ps.fmt.pc = fmta;
800     }
801 
802     va_copy(ps.args, args);
803 
804     if (Column != (UINTN) -1) {
805         uefi_call_wrapper(Out->SetCursorPosition, 3, Out, Column, Row);
806     }
807 
808     back = _Print (&ps);
809     va_end(ps.args);
810     return back;
811 }
812 
813 
814 UINTN
AsciiPrint(IN CONST CHAR8 * fmt,...)815 AsciiPrint (
816     IN CONST CHAR8    *fmt,
817     ...
818     )
819 /*++
820 
821 Routine Description:
822 
823     For those whom really can't deal with unicode, a print
824     function that takes an ascii format string
825 
826 Arguments:
827 
828     fmt         - ascii format string
829 
830 Returns:
831 
832     Length of string printed to the console
833 
834 --*/
835 
836 {
837     va_list     args;
838     UINTN       back;
839 
840     va_start (args, fmt);
841     back = _IPrint ((UINTN) -1, (UINTN) -1, ST->ConOut, NULL, fmt, args);
842     va_end (args);
843     return back;
844 }
845 
846 
847 UINTN
AsciiVSPrint(OUT CHAR8 * Str,IN UINTN StrSize,IN CONST CHAR8 * fmt,va_list args)848 AsciiVSPrint (
849     OUT CHAR8         *Str,
850     IN UINTN          StrSize,
851     IN CONST CHAR8    *fmt,
852     va_list           args
853 )
854 /*++
855 
856 Routine Description:
857 
858     Prints a formatted ascii string to a buffer using a va_list
859 
860 Arguments:
861 
862     Str         - Output buffer to print the formatted string into
863 
864     StrSize     - Size of Str.  String is truncated to this size.
865                   A size of 0 means there is no limit
866 
867     fmt         - The format string
868 
869     args        - va_list
870 
871 
872 Returns:
873 
874     String length returned in buffer
875 
876 --*/
877 // Use UnicodeVSPrint() and convert back to ASCII
878 {
879     CHAR16 *UnicodeStr, *UnicodeFmt;
880     UINTN i, Len;
881 
882     UnicodeStr = AllocatePool(StrSize * sizeof(CHAR16));
883     if (!UnicodeStr)
884         return 0;
885 
886     UnicodeFmt = PoolPrint(L"%a", fmt);
887     if (!UnicodeFmt) {
888         FreePool(UnicodeStr);
889         return 0;
890     }
891 
892     Len = UnicodeVSPrint(UnicodeStr, StrSize, UnicodeFmt, args);
893     FreePool(UnicodeFmt);
894 
895     // The strings are ASCII so just do a plain Unicode conversion
896     for (i = 0; i < Len; i++)
897         Str[i] = (CHAR8)UnicodeStr[i];
898     Str[Len] = 0;
899     FreePool(UnicodeStr);
900 
901     return Len;
902 }
903 
904 
905 STATIC
906 VOID
PFLUSH(IN OUT PRINT_STATE * ps)907 PFLUSH (
908     IN OUT PRINT_STATE     *ps
909     )
910 {
911     *ps->Pos = 0;
912     if (IsLocalPrint(ps->Output))
913 	ps->Output(ps->Context, ps->Buffer);
914     else
915     	uefi_call_wrapper(ps->Output, 2, ps->Context, ps->Buffer);
916     ps->Pos = ps->Buffer;
917 }
918 
919 STATIC
920 VOID
PSETATTR(IN OUT PRINT_STATE * ps,IN UINTN Attr)921 PSETATTR (
922     IN OUT PRINT_STATE  *ps,
923     IN UINTN             Attr
924     )
925 {
926    PFLUSH (ps);
927 
928    ps->RestoreAttr = ps->Attr;
929    if (ps->SetAttr) {
930 	uefi_call_wrapper(ps->SetAttr, 2, ps->Context, Attr);
931    }
932 
933    ps->Attr = Attr;
934 }
935 
936 STATIC
937 VOID
PPUTC(IN OUT PRINT_STATE * ps,IN CHAR16 c)938 PPUTC (
939     IN OUT PRINT_STATE     *ps,
940     IN CHAR16              c
941     )
942 {
943     // if this is a newline, add a carraige return
944     if (c == '\n') {
945         PPUTC (ps, '\r');
946     }
947 
948     *ps->Pos = c;
949     ps->Pos += 1;
950     ps->Len += 1;
951 
952     // if at the end of the buffer, flush it
953     if (ps->Pos >= ps->End) {
954         PFLUSH(ps);
955     }
956 }
957 
958 
959 STATIC
960 CHAR16
PGETC(IN POINTER * p)961 PGETC (
962     IN POINTER      *p
963     )
964 {
965     CHAR16      c;
966 
967     c = p->Ascii ? p->pc[p->Index] : p->pw[p->Index];
968     p->Index += 1;
969 
970     return  c;
971 }
972 
973 
974 STATIC
975 VOID
PITEM(IN OUT PRINT_STATE * ps)976 PITEM (
977     IN OUT PRINT_STATE  *ps
978     )
979 {
980     UINTN               Len, i;
981     PRINT_ITEM          *Item;
982     CHAR16              c;
983 
984     // Get the length of the item
985     Item = ps->Item;
986     Item->Item.Index = 0;
987     while (Item->Item.Index < Item->FieldWidth) {
988         c = PGETC(&Item->Item);
989         if (!c) {
990             Item->Item.Index -= 1;
991             break;
992         }
993     }
994     Len = Item->Item.Index;
995 
996     // if there is no item field width, use the items width
997     if (Item->FieldWidth == (UINTN) -1) {
998         Item->FieldWidth = Len;
999     }
1000 
1001     // if item is larger then width, update width
1002     if (Len > Item->Width) {
1003         Item->Width = Len;
1004     }
1005 
1006 
1007     // if pad field before, add pad char
1008     if (Item->PadBefore) {
1009         for (i=Item->Width; i < Item->FieldWidth; i+=1) {
1010             PPUTC (ps, ' ');
1011         }
1012     }
1013 
1014     // pad item
1015     for (i=Len; i < Item->Width; i++) {
1016         PPUTC (ps, Item->Pad);
1017     }
1018 
1019     // add the item
1020     Item->Item.Index=0;
1021     while (Item->Item.Index < Len) {
1022         PPUTC (ps, PGETC(&Item->Item));
1023     }
1024 
1025     // If pad at the end, add pad char
1026     if (!Item->PadBefore) {
1027         for (i=Item->Width; i < Item->FieldWidth; i+=1) {
1028             PPUTC (ps, ' ');
1029         }
1030     }
1031 }
1032 
1033 
1034 STATIC
1035 UINTN
_Print(IN PRINT_STATE * ps)1036 _Print (
1037     IN PRINT_STATE     *ps
1038     )
1039 /*++
1040 
1041 Routine Description:
1042 
1043     %w.lF   -   w = width
1044                 l = field width
1045                 F = format of arg
1046 
1047   Args F:
1048     0       -   pad with zeros
1049     -       -   justify on left (default is on right)
1050     ,       -   add comma's to field
1051     *       -   width provided on stack
1052     n       -   Set output attribute to normal (for this field only)
1053     h       -   Set output attribute to highlight (for this field only)
1054     e       -   Set output attribute to error (for this field only)
1055     l       -   Value is 64 bits
1056 
1057     a       -   ascii string
1058     s       -   unicode string
1059     X       -   fixed 8 byte value in hex
1060     x       -   hex value
1061     d       -   value as signed decimal
1062     u       -   value as unsigned decimal
1063     f       -   value as floating point
1064     c       -   Unicode char
1065     t       -   EFI time structure
1066     g       -   Pointer to GUID
1067     r       -   EFI status code (result code)
1068     D       -   pointer to Device Path with normal ending.
1069 
1070     N       -   Set output attribute to normal
1071     H       -   Set output attribute to highlight
1072     E       -   Set output attribute to error
1073     %       -   Print a %
1074 
1075 Arguments:
1076 
1077     SystemTable     - The system table
1078 
1079 Returns:
1080 
1081     Number of charactors written
1082 
1083 --*/
1084 {
1085     CHAR16          c;
1086     UINTN           Attr;
1087     PRINT_ITEM      Item;
1088     CHAR16          Buffer[PRINT_STRING_LEN];
1089 
1090     ps->Len = 0;
1091     ps->Buffer = Buffer;
1092     ps->Pos = Buffer;
1093     ps->End = Buffer + PRINT_STRING_LEN - 1;
1094     ps->Item = &Item;
1095 
1096     ps->fmt.Index = 0;
1097     while ((c = PGETC(&ps->fmt))) {
1098 
1099         if (c != '%') {
1100             PPUTC ( ps, c );
1101             continue;
1102         }
1103 
1104         // setup for new item
1105         Item.FieldWidth = (UINTN) -1;
1106         Item.Width = 0;
1107         Item.WidthParse = &Item.Width;
1108         Item.Pad = ' ';
1109         Item.PadBefore = TRUE;
1110         Item.Comma = FALSE;
1111         Item.Long = FALSE;
1112         Item.Item.Ascii = FALSE;
1113         Item.Item.pw = NULL;
1114         ps->RestoreAttr = 0;
1115         Attr = 0;
1116 
1117         while ((c = PGETC(&ps->fmt))) {
1118 
1119             switch (c) {
1120 
1121             case '%':
1122                 //
1123                 // %% -> %
1124                 //
1125                 Item.Scratch[0] = '%';
1126                 Item.Scratch[1] = 0;
1127                 Item.Item.pw = Item.Scratch;
1128                 break;
1129 
1130             case '0':
1131                 Item.Pad = '0';
1132                 break;
1133 
1134             case '-':
1135                 Item.PadBefore = FALSE;
1136                 break;
1137 
1138             case ',':
1139                 Item.Comma = TRUE;
1140                 break;
1141 
1142             case '.':
1143                 Item.WidthParse = &Item.FieldWidth;
1144                 break;
1145 
1146             case '*':
1147                 *Item.WidthParse = va_arg(ps->args, UINTN);
1148                 break;
1149 
1150             case '1':
1151             case '2':
1152             case '3':
1153             case '4':
1154             case '5':
1155             case '6':
1156             case '7':
1157             case '8':
1158             case '9':
1159                 *Item.WidthParse = 0;
1160                 do {
1161                     *Item.WidthParse = *Item.WidthParse * 10 + c - '0';
1162                     c = PGETC(&ps->fmt);
1163                 } while (c >= '0'  &&  c <= '9') ;
1164                 ps->fmt.Index -= 1;
1165                 break;
1166 
1167             case 'a':
1168                 Item.Item.pc = va_arg(ps->args, CHAR8 *);
1169                 Item.Item.Ascii = TRUE;
1170                 if (!Item.Item.pc) {
1171                     Item.Item.pc = (CHAR8 *)"(null)";
1172                 }
1173                 break;
1174 
1175             case 's':
1176                 Item.Item.pw = va_arg(ps->args, CHAR16 *);
1177                 if (!Item.Item.pw) {
1178                     Item.Item.pw = L"(null)";
1179                 }
1180                 break;
1181 
1182             case 'c':
1183                 Item.Scratch[0] = (CHAR16) va_arg(ps->args, UINTN);
1184                 Item.Scratch[1] = 0;
1185                 Item.Item.pw = Item.Scratch;
1186                 break;
1187 
1188             case 'l':
1189                 Item.Long = TRUE;
1190                 break;
1191 
1192             case 'X':
1193                 Item.Width = Item.Long ? 16 : 8;
1194                 Item.Pad = '0';
1195 #if __GNUC__ >= 7
1196 		__attribute__ ((fallthrough));
1197 #endif
1198             case 'x':
1199                 ValueToHex (
1200                     Item.Scratch,
1201                     Item.Long ? va_arg(ps->args, UINT64) : va_arg(ps->args, UINT32)
1202                     );
1203                 Item.Item.pw = Item.Scratch;
1204 
1205                 break;
1206 
1207 
1208             case 'g':
1209                 GuidToString (Item.Scratch, va_arg(ps->args, EFI_GUID *));
1210                 Item.Item.pw = Item.Scratch;
1211                 break;
1212 
1213             case 'u':
1214                 ValueToString (
1215                     Item.Scratch,
1216                     Item.Comma,
1217                     Item.Long ? va_arg(ps->args, UINT64) : va_arg(ps->args, UINT32)
1218                     );
1219                 Item.Item.pw = Item.Scratch;
1220                 break;
1221 
1222             case 'd':
1223                 ValueToString (
1224                     Item.Scratch,
1225                     Item.Comma,
1226                     Item.Long ? va_arg(ps->args, INT64) : va_arg(ps->args, INT32)
1227                     );
1228                 Item.Item.pw = Item.Scratch;
1229                 break;
1230 
1231             case 'D':
1232             {
1233                 EFI_DEVICE_PATH *dp = va_arg(ps->args, EFI_DEVICE_PATH *);
1234                 CHAR16 *dpstr = DevicePathToStr(dp);
1235                 StrnCpy(Item.Scratch, dpstr, PRINT_ITEM_BUFFER_LEN);
1236                 Item.Scratch[PRINT_ITEM_BUFFER_LEN-1] = L'\0';
1237                 FreePool(dpstr);
1238 
1239                 Item.Item.pw = Item.Scratch;
1240                 break;
1241             }
1242 
1243 #ifndef __NetBSD__
1244             case 'f':
1245                 FloatToString (
1246                     Item.Scratch,
1247                     Item.Comma,
1248                     va_arg(ps->args, double)
1249                     );
1250                 Item.Item.pw = Item.Scratch;
1251                 break;
1252 #endif
1253 
1254             case 't':
1255                 TimeToString (Item.Scratch, va_arg(ps->args, EFI_TIME *));
1256                 Item.Item.pw = Item.Scratch;
1257                 break;
1258 
1259             case 'r':
1260                 StatusToString (Item.Scratch, va_arg(ps->args, EFI_STATUS));
1261                 Item.Item.pw = Item.Scratch;
1262                 break;
1263 
1264             case 'n':
1265                 PSETATTR(ps, ps->AttrNorm);
1266                 break;
1267 
1268             case 'h':
1269                 PSETATTR(ps, ps->AttrHighlight);
1270                 break;
1271 
1272             case 'e':
1273                 PSETATTR(ps, ps->AttrError);
1274                 break;
1275 
1276             case 'N':
1277                 Attr = ps->AttrNorm;
1278                 break;
1279 
1280             case 'H':
1281                 Attr = ps->AttrHighlight;
1282                 break;
1283 
1284             case 'E':
1285                 Attr = ps->AttrError;
1286                 break;
1287 
1288             default:
1289                 Item.Scratch[0] = '?';
1290                 Item.Scratch[1] = 0;
1291                 Item.Item.pw = Item.Scratch;
1292                 break;
1293             }
1294 
1295             // if we have an Item
1296             if (Item.Item.pw) {
1297                 PITEM (ps);
1298                 break;
1299             }
1300 
1301             // if we have an Attr set
1302             if (Attr) {
1303                 PSETATTR(ps, Attr);
1304                 ps->RestoreAttr = 0;
1305                 break;
1306             }
1307         }
1308 
1309         if (ps->RestoreAttr) {
1310             PSETATTR(ps, ps->RestoreAttr);
1311         }
1312     }
1313 
1314     // Flush buffer
1315     PFLUSH (ps);
1316     return ps->Len;
1317 }
1318 
1319 STATIC CHAR8 Hex[] = {'0','1','2','3','4','5','6','7',
1320                       '8','9','A','B','C','D','E','F'};
1321 
1322 VOID
ValueToHex(IN CHAR16 * Buffer,IN UINT64 v)1323 ValueToHex (
1324     IN CHAR16   *Buffer,
1325     IN UINT64   v
1326     )
1327 {
1328     CHAR8           str[30], *p1;
1329     CHAR16          *p2;
1330 
1331     if (!v) {
1332         Buffer[0] = '0';
1333         Buffer[1] = 0;
1334         return ;
1335     }
1336 
1337     p1 = str;
1338     p2 = Buffer;
1339 
1340     while (v) {
1341         // Without the cast, the MSVC compiler may insert a reference to __allmull
1342         *(p1++) = Hex[(UINTN)(v & 0xf)];
1343         v = RShiftU64 (v, 4);
1344     }
1345 
1346     while (p1 != str) {
1347         *(p2++) = *(--p1);
1348     }
1349     *p2 = 0;
1350 }
1351 
1352 
1353 VOID
ValueToString(IN CHAR16 * Buffer,IN BOOLEAN Comma,IN INT64 v)1354 ValueToString (
1355     IN CHAR16   *Buffer,
1356     IN BOOLEAN  Comma,
1357     IN INT64    v
1358     )
1359 {
1360     STATIC CHAR8 ca[] = {  3, 1, 2 };
1361     CHAR8        str[40], *p1;
1362     CHAR16       *p2;
1363     UINTN        c, r;
1364 
1365     if (!v) {
1366         Buffer[0] = '0';
1367         Buffer[1] = 0;
1368         return ;
1369     }
1370 
1371     p1 = str;
1372     p2 = Buffer;
1373 
1374     if (v < 0) {
1375         *(p2++) = '-';
1376         v = -v;
1377     }
1378 
1379     while (v) {
1380         v = (INT64)DivU64x32 ((UINT64)v, 10, &r);
1381         *(p1++) = (CHAR8)r + '0';
1382     }
1383 
1384     c = (UINTN) (Comma ? ca[(p1 - str) % 3] : 999) + 1;
1385     while (p1 != str) {
1386 
1387         c -= 1;
1388         if (!c) {
1389             *(p2++) = ',';
1390             c = 3;
1391         }
1392 
1393         *(p2++) = *(--p1);
1394     }
1395     *p2 = 0;
1396 }
1397 
1398 #ifndef __NetBSD__
1399 VOID
FloatToString(IN CHAR16 * Buffer,IN BOOLEAN Comma,IN double v)1400 FloatToString (
1401     IN CHAR16   *Buffer,
1402     IN BOOLEAN  Comma,
1403     IN double   v
1404     )
1405 {
1406     /*
1407      * Integer part.
1408      */
1409     INTN i = (INTN)v;
1410     ValueToString(Buffer, Comma, i);
1411 
1412 
1413     /*
1414      * Decimal point.
1415      */
1416     UINTN x = StrLen(Buffer);
1417     Buffer[x] = L'.';
1418     x++;
1419 
1420 
1421     /*
1422      * Keep fractional part.
1423      */
1424     float f = (float)(v - i);
1425     if (f < 0) f = -f;
1426 
1427 
1428     /*
1429      * Leading fractional zeroes.
1430      */
1431     f *= 10.0;
1432     while (   (f != 0)
1433            && ((INTN)f == 0))
1434     {
1435       Buffer[x] = L'0';
1436       x++;
1437       f *= 10.0;
1438     }
1439 
1440 
1441     /*
1442      * Fractional digits.
1443      */
1444     while ((float)(INTN)f != f)
1445     {
1446       f *= 10;
1447     }
1448     ValueToString(Buffer + x, FALSE, (INTN)f);
1449     return;
1450 }
1451 #endif
1452 
1453 VOID
TimeToString(OUT CHAR16 * Buffer,IN EFI_TIME * Time)1454 TimeToString (
1455     OUT CHAR16      *Buffer,
1456     IN EFI_TIME     *Time
1457     )
1458 {
1459     UINTN       Hour, Year;
1460     CHAR16      AmPm;
1461 
1462     AmPm = 'a';
1463     Hour = Time->Hour;
1464     if (Time->Hour == 0) {
1465         Hour = 12;
1466     } else if (Time->Hour >= 12) {
1467         AmPm = 'p';
1468         if (Time->Hour >= 13) {
1469             Hour -= 12;
1470         }
1471     }
1472 
1473     Year = Time->Year % 100;
1474 
1475     // bugbug: for now just print it any old way
1476     UnicodeSPrint (Buffer, 0, L"%02d/%02d/%02d  %02d:%02d%c",
1477         Time->Month,
1478         Time->Day,
1479         Year,
1480         Hour,
1481         Time->Minute,
1482         AmPm
1483         );
1484 }
1485 
1486 
1487 
1488 
1489 VOID
DumpHex(IN UINTN Indent,IN UINTN Offset,IN UINTN DataSize,IN VOID * UserData)1490 DumpHex (
1491     IN UINTN        Indent,
1492     IN UINTN        Offset,
1493     IN UINTN        DataSize,
1494     IN VOID         *UserData
1495     )
1496 {
1497     CHAR8           *Data, Val[50], Str[20], c;
1498     UINTN           Size, Index;
1499 
1500     UINTN           ScreenCount;
1501     UINTN           TempColumn;
1502     UINTN           ScreenSize;
1503     CHAR16          ReturnStr[1];
1504 
1505 
1506     uefi_call_wrapper(ST->ConOut->QueryMode, 4, ST->ConOut, ST->ConOut->Mode->Mode, &TempColumn, &ScreenSize);
1507     ScreenCount = 0;
1508     ScreenSize -= 2;
1509 
1510     Data = UserData;
1511     while (DataSize) {
1512         Size = 16;
1513         if (Size > DataSize) {
1514             Size = DataSize;
1515         }
1516 
1517         for (Index=0; Index < Size; Index += 1) {
1518             c = Data[Index];
1519             Val[Index*3+0] = Hex[c>>4];
1520             Val[Index*3+1] = Hex[c&0xF];
1521             Val[Index*3+2] = (Index == 7)?'-':' ';
1522             Str[Index] = (c < ' ' || c > 'z') ? '.' : c;
1523         }
1524 
1525         Val[Index*3] = 0;
1526         Str[Index] = 0;
1527         Print (L"%*a%X: %-.48a *%a*\n", Indent, "", Offset, Val, Str);
1528 
1529         Data += Size;
1530         Offset += Size;
1531         DataSize -= Size;
1532 
1533         ScreenCount++;
1534         if (ScreenCount >= ScreenSize && ScreenSize != 0) {
1535             //
1536             // If ScreenSize == 0 we have the console redirected so don't
1537             //  block updates
1538             //
1539             ScreenCount = 0;
1540             Print (L"Press Enter to continue :");
1541             Input (L"", ReturnStr, sizeof(ReturnStr)/sizeof(CHAR16));
1542             Print (L"\n");
1543         }
1544 
1545     }
1546 }
1547