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