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