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 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 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 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 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 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 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 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 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 * 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 * 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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