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