1 /*++ 2 3 Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.<BR> 4 This program and the accompanying materials 5 are licensed and made available under the terms and conditions of the BSD License 6 which accompanies this distribution. The full text of the license may be found at 7 http://opensource.org/licenses/bsd-license.php 8 9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 11 12 Module Name: 13 14 Print.c 15 16 Abstract: 17 18 Basic Ascii AvSPrintf() function named AvSPrint(). AvSPrint() enables very 19 simple implemenation of debug prints. 20 21 You can not Print more than PEI_LIB_MAX_PRINT_BUFFER characters at a 22 time. This makes the implementation very simple. 23 24 AvSPrint format specification has the follwoing form 25 26 %[flags][width]type 27 28 flags: 29 '-' - Left justify 30 '+' - Prefix a sign 31 ' ' - Prefix a blank 32 ',' - Place commas in numberss 33 '0' - Prefix for width with zeros 34 'l' - UINT64 35 'L' - UINT64 36 37 width: 38 '*' - Get width from a UINTN argumnet from the argument list 39 Decimal number that represents width of print 40 41 type: 42 'p' - arugment is VOID *; printed as hex number 43 'X' - argument is a UINTN hex number, prefix '0' 44 'x' - argument is a hex number 45 'd' - argument is a decimal number 46 'a' - argument is an ascii string 47 'S', 's' - argument is an Unicode string 48 'g' - argument is a pointer to an EFI_GUID 49 't' - argument is a pointer to an EFI_TIME structure 50 'c' - argument is an ascii character 51 'r' - argument is EFI_STATUS 52 '%' - Print a % 53 54 --*/ 55 56 #include "Tiano.h" 57 #include "Pei.h" 58 #include "PeiLib.h" 59 #include "Print.h" 60 61 62 STATIC 63 UINTN 64 ValueToString ( 65 IN OUT CHAR8 *Buffer, 66 IN INT64 Value, 67 IN UINTN Flags, 68 IN UINTN Width 69 ); 70 71 STATIC 72 UINTN 73 ValueTomHexStr ( 74 IN OUT CHAR8 *Buffer, 75 IN UINT64 Value, 76 IN UINTN Flags, 77 IN UINTN Width 78 ); 79 80 STATIC 81 UINTN 82 GuidToString ( 83 IN EFI_GUID *Guid, 84 IN OUT CHAR8 *Buffer, 85 IN UINTN BufferSize 86 ); 87 88 STATIC 89 UINTN 90 TimeToString ( 91 IN EFI_TIME *Time, 92 IN OUT CHAR8 *Buffer, 93 IN UINTN BufferSize 94 ); 95 96 STATIC 97 UINTN 98 EfiStatusToString ( 99 IN EFI_STATUS Status, 100 OUT CHAR8 *Buffer, 101 IN UINTN BufferSize 102 ); 103 104 105 UINTN 106 ASPrint ( 107 OUT CHAR8 *Buffer, 108 IN UINTN BufferSize, 109 IN CONST CHAR8 *Format, 110 ... 111 ) 112 /*++ 113 114 Routine Description: 115 116 ASPrint function to process format and place the results in Buffer. 117 118 Arguments: 119 120 Buffer - Ascii buffer to print the results of the parsing of Format into. 121 122 BufferSize - Maximum number of characters to put into buffer. Zero means no 123 limit. 124 125 Format - Ascii format string see file header for more details. 126 127 ... - Vararg list consumed by processing Format. 128 129 Returns: 130 131 Number of characters printed. 132 133 --*/ 134 { 135 UINTN Return; 136 VA_LIST Marker; 137 138 VA_START(Marker, Format); 139 Return = AvSPrint(Buffer, BufferSize, Format, Marker); 140 VA_END (Marker); 141 142 return Return; 143 } 144 145 146 UINTN 147 AvSPrint ( 148 OUT CHAR8 *StartOfBuffer, 149 IN UINTN BufferSize, 150 IN CONST CHAR8 *FormatString, 151 IN VA_LIST Marker 152 ) 153 /*++ 154 155 Routine Description: 156 157 AvSPrint function to process format and place the results in Buffer. Since a 158 VA_LIST is used this rountine allows the nesting of Vararg routines. Thus 159 this is the main print working routine 160 161 Arguments: 162 163 StartOfBuffer - Ascii buffer to print the results of the parsing of Format into. 164 165 BufferSize - Maximum number of characters to put into buffer. Zero means 166 no limit. 167 168 FormatString - Ascii format string see file header for more details. 169 170 Marker - Vararg list consumed by processing Format. 171 172 Returns: 173 174 Number of characters printed. 175 176 --*/ 177 { 178 CHAR8 TempBuffer[CHARACTER_NUMBER_FOR_VALUE]; 179 CHAR8 *Buffer; 180 CHAR8 *AsciiStr; 181 CHAR16 *UnicodeStr; 182 CHAR8 *Format; 183 UINTN Index; 184 UINTN Flags; 185 UINTN Width; 186 UINTN Count; 187 UINTN BufferLeft; 188 UINT64 Value; 189 EFI_GUID *TmpGUID; 190 BOOLEAN Done; 191 192 // 193 // Process the format string. Stop if Buffer is over run. 194 // 195 Buffer = StartOfBuffer; 196 Format = (CHAR8 *) FormatString; 197 BufferLeft = BufferSize; 198 for (Index = 0; (*Format != '\0') && (Index < BufferSize - 1); Format++) { 199 if (*Format != '%') { 200 if ((*Format == '\n') && (Index < BufferSize - 2)) { 201 // 202 // If carage return add line feed 203 // 204 Buffer[Index++] = '\r'; 205 BufferLeft -= sizeof (CHAR8); 206 } 207 208 Buffer[Index++] = *Format; 209 BufferLeft -= sizeof (CHAR8); 210 } else { 211 212 // 213 // Now it's time to parse what follows after % 214 // 215 Flags = 0; 216 Width = 0; 217 for (Done = FALSE; !Done; ) { 218 Format++; 219 220 switch (*Format) { 221 222 case '-': Flags |= LEFT_JUSTIFY; break; 223 case '+': Flags |= PREFIX_SIGN; break; 224 case ' ': Flags |= PREFIX_BLANK; break; 225 case ',': Flags |= COMMA_TYPE; break; 226 case 'L': 227 case 'l': Flags |= LONG_TYPE; break; 228 229 case '*': 230 Width = VA_ARG (Marker, UINTN); 231 break; 232 233 case '0': 234 Flags |= PREFIX_ZERO; 235 case '1': 236 case '2': 237 case '3': 238 case '4': 239 case '5': 240 case '6': 241 case '7': 242 case '8': 243 case '9': 244 Count = 0; 245 do { 246 Count = (Count * 10) + *Format - '0'; 247 Format++; 248 } while ((*Format >= '0') && (*Format <= '9')); 249 Format--; 250 Width = Count; 251 break; 252 253 default: 254 Done = TRUE; 255 } 256 } 257 258 switch (*Format) { 259 case 'p': 260 // 261 // Flag space, +, 0, L & l are invalid for type p. 262 // 263 Flags &= ~(PREFIX_BLANK| PREFIX_SIGN | LONG_TYPE); 264 if (sizeof (VOID *) > 4) { 265 Flags |= LONG_TYPE; 266 Value = VA_ARG (Marker, UINT64); 267 } else { 268 Value = VA_ARG (Marker, UINTN); 269 } 270 Flags |= PREFIX_ZERO; 271 272 ValueTomHexStr (TempBuffer, Value, Flags, Width); 273 AsciiStr = TempBuffer; 274 275 for (; (*AsciiStr != '\0') && (Index < BufferSize - 1); AsciiStr++) { 276 Buffer[Index++] = *AsciiStr; 277 } 278 break; 279 case 'X': 280 Flags |= PREFIX_ZERO; 281 Width = sizeof (UINT64) * 2; 282 283 // 284 // break skiped on purpose 285 // 286 case 'x': 287 if ((Flags & LONG_TYPE) == LONG_TYPE) { 288 Value = VA_ARG (Marker, UINT64); 289 } else { 290 Value = VA_ARG (Marker, UINTN); 291 } 292 293 ValueTomHexStr (TempBuffer, Value, Flags, Width); 294 AsciiStr = TempBuffer; 295 296 for (; (*AsciiStr != '\0') && (Index < BufferSize - 1); AsciiStr++) { 297 Buffer[Index++] = *AsciiStr; 298 } 299 break; 300 301 case 'd': 302 if ((Flags & LONG_TYPE) == LONG_TYPE) { 303 Value = VA_ARG (Marker, UINT64); 304 } else { 305 Value = (UINTN) VA_ARG (Marker, UINTN); 306 } 307 308 ValueToString (TempBuffer, Value, Flags, Width); 309 AsciiStr = TempBuffer; 310 311 for (; (*AsciiStr != '\0') && (Index < BufferSize - 1); AsciiStr++) { 312 Buffer[Index++] = *AsciiStr; 313 } 314 break; 315 316 case 's': 317 case 'S': 318 UnicodeStr = (CHAR16 *) VA_ARG (Marker, CHAR8 *); 319 if (UnicodeStr == NULL) { 320 UnicodeStr = L"<null string>"; 321 } 322 323 for (Count = 0; (*UnicodeStr != '\0') && (Index < BufferSize - 1); UnicodeStr++, Count++) { 324 Buffer[Index++] = (CHAR8) *UnicodeStr; 325 } 326 // 327 // Add padding if needed 328 // 329 for (; (Count < Width) && (Index < BufferSize - 1); Count++) { 330 Buffer[Index++] = ' '; 331 } 332 333 break; 334 335 case 'a': 336 AsciiStr = (CHAR8 *) VA_ARG (Marker, CHAR8 *); 337 if (AsciiStr == NULL) { 338 AsciiStr = "<null string>"; 339 } 340 341 for (Count = 0; (*AsciiStr != '\0') && (Index < BufferSize - 1); AsciiStr++, Count++) { 342 Buffer[Index++] = *AsciiStr; 343 } 344 // 345 // Add padding if needed 346 // 347 for (; (Count < Width) && (Index < BufferSize - 1); Count++) { 348 Buffer[Index++] = ' '; 349 } 350 break; 351 352 case 'c': 353 Buffer[Index++] = (CHAR8) VA_ARG (Marker, UINTN); 354 break; 355 356 case 'g': 357 TmpGUID = VA_ARG (Marker, EFI_GUID *); 358 if (TmpGUID != NULL) { 359 Index += GuidToString ( 360 TmpGUID, 361 &Buffer[Index], 362 BufferLeft 363 ); 364 } 365 break; 366 367 case 't': 368 Index += TimeToString ( 369 VA_ARG (Marker, EFI_TIME *), 370 &Buffer[Index], 371 BufferLeft 372 ); 373 break; 374 375 case 'r': 376 Index += EfiStatusToString ( 377 VA_ARG (Marker, EFI_STATUS), 378 &Buffer[Index], 379 BufferLeft 380 ); 381 break; 382 383 case '%': 384 Buffer[Index++] = *Format; 385 break; 386 387 default: 388 // 389 // if the type is unknown print it to the screen 390 // 391 Buffer[Index++] = *Format; 392 } 393 394 BufferLeft = BufferSize - Index; 395 } 396 } 397 398 Buffer[Index++] = '\0'; 399 400 return &Buffer[Index] - StartOfBuffer; 401 } 402 403 404 405 static CHAR8 mHexStr[] = { '0','1','2','3','4','5','6','7', 406 '8','9','A','B','C','D','E','F' }; 407 408 STATIC 409 UINTN 410 ValueTomHexStr ( 411 IN OUT CHAR8 *Buffer, 412 IN UINT64 Value, 413 IN UINTN Flags, 414 IN UINTN Width 415 ) 416 /*++ 417 418 Routine Description: 419 420 AvSPrint worker function that prints a Value as a hex number in Buffer 421 422 Arguments: 423 424 Buffer - Location to place ascii hex string of Value. 425 426 Value - Hex value to convert to a string in Buffer. 427 428 Flags - Flags to use in printing Hex string, see file header for details. 429 430 Width - Width of hex value. 431 432 Returns: 433 434 Number of characters printed. 435 436 --*/ 437 { 438 CHAR8 TempBuffer[CHARACTER_NUMBER_FOR_VALUE]; 439 CHAR8 *TempStr; 440 CHAR8 Prefix; 441 CHAR8 *BufferPtr; 442 UINTN Count; 443 UINTN Index; 444 445 TempStr = TempBuffer; 446 BufferPtr = Buffer; 447 448 // 449 // Count starts at one since we will null terminate. Each iteration of the 450 // loop picks off one nibble. Oh yea TempStr ends up backwards 451 // 452 Count = 0; 453 do { 454 *(TempStr++) = mHexStr[Value & 0x0f]; 455 Value = RShiftU64 (Value, 4); 456 Count++; 457 } while (Value != 0); 458 459 if (Flags & PREFIX_ZERO) { 460 Prefix = '0'; 461 } else if (!(Flags & LEFT_JUSTIFY)) { 462 Prefix = ' '; 463 } else { 464 Prefix = 0x00; 465 } 466 for (Index = Count; Index < Width; Index++) { 467 *(TempStr++) = Prefix; 468 } 469 470 // 471 // Reverse temp string into Buffer. 472 // 473 if (Width > 0 && (UINTN) (TempStr - TempBuffer) > Width) { 474 TempStr = TempBuffer + Width; 475 } 476 Index = 0; 477 while (TempStr != TempBuffer) { 478 *(BufferPtr++) = *(--TempStr); 479 Index++; 480 } 481 482 *BufferPtr = 0; 483 return Index; 484 } 485 486 STATIC 487 UINTN 488 ValueToString ( 489 IN OUT CHAR8 *Buffer, 490 IN INT64 Value, 491 IN UINTN Flags, 492 IN UINTN Width 493 ) 494 /*++ 495 496 Routine Description: 497 498 AvSPrint worker function that prints a Value as a decimal number in Buffer 499 500 Arguments: 501 502 Buffer - Location to place ascii decimal number string of Value. 503 504 Value - Decimal value to convert to a string in Buffer. 505 506 Flags - Flags to use in printing decimal string, see file header for details. 507 508 Width - Width of hex value. 509 510 Returns: 511 512 Number of characters printed. 513 514 --*/ 515 { 516 CHAR8 TempBuffer[CHARACTER_NUMBER_FOR_VALUE]; 517 CHAR8 *TempStr; 518 CHAR8 *BufferPtr; 519 UINTN Count; 520 UINTN NumberCount; 521 UINTN Remainder; 522 BOOLEAN Negative; 523 UINTN Index; 524 525 Negative = FALSE; 526 TempStr = TempBuffer; 527 BufferPtr = Buffer; 528 Count = 0; 529 NumberCount = 0; 530 Remainder = 0; 531 532 if (Value < 0) { 533 Negative = TRUE; 534 Value = -Value; 535 } 536 537 do { 538 Value = (INT64)DivU64x32 ((UINT64)Value, 10, &Remainder); 539 *(TempStr++) = (CHAR8)(Remainder + '0'); 540 Count++; 541 NumberCount++; 542 if ((Flags & COMMA_TYPE) == COMMA_TYPE) { 543 if (NumberCount % 3 == 0 && Value != 0) { 544 *(TempStr++) = ','; 545 Count++; 546 } 547 } 548 } while (Value != 0); 549 550 if (Negative) { 551 *(BufferPtr++) = '-'; 552 Count++; 553 } 554 555 // 556 // Reverse temp string into Buffer. 557 // 558 if (Width > 0 && (UINTN) (TempStr - TempBuffer) > Width) { 559 TempStr = TempBuffer + Width; 560 } 561 Index = 0; 562 while (TempStr != TempBuffer) { 563 *(BufferPtr++) = *(--TempStr); 564 } 565 566 *BufferPtr = 0; 567 return Index; 568 } 569 570 STATIC 571 UINTN 572 GuidToString ( 573 IN EFI_GUID *Guid, 574 IN CHAR8 *Buffer, 575 IN UINTN BufferSize 576 ) 577 /*++ 578 579 Routine Description: 580 581 AvSPrint worker function that prints an EFI_GUID. 582 583 Arguments: 584 585 Guid - Pointer to GUID to print. 586 587 Buffer - Buffe to print Guid into. 588 589 BufferSize - Size of Buffer. 590 591 Returns: 592 593 Number of characters printed. 594 595 --*/ 596 { 597 UINTN Size; 598 599 Size = ASPrint ( 600 Buffer, 601 BufferSize, 602 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", 603 (UINTN)Guid->Data1, 604 (UINTN)Guid->Data2, 605 (UINTN)Guid->Data3, 606 (UINTN)Guid->Data4[0], 607 (UINTN)Guid->Data4[1], 608 (UINTN)Guid->Data4[2], 609 (UINTN)Guid->Data4[3], 610 (UINTN)Guid->Data4[4], 611 (UINTN)Guid->Data4[5], 612 (UINTN)Guid->Data4[6], 613 (UINTN)Guid->Data4[7] 614 ); 615 616 // 617 // ASPrint will null terminate the string. The -1 skips the null 618 // 619 return Size - 1; 620 } 621 622 623 STATIC 624 UINTN 625 TimeToString ( 626 IN EFI_TIME *Time, 627 OUT CHAR8 *Buffer, 628 IN UINTN BufferSize 629 ) 630 /*++ 631 632 Routine Description: 633 634 AvSPrint worker function that prints EFI_TIME. 635 636 Arguments: 637 638 Time - Pointer to EFI_TIME sturcture to print. 639 640 Buffer - Buffer to print Time into. 641 642 BufferSize - Size of Buffer. 643 644 Returns: 645 646 Number of characters printed. 647 648 --*/ 649 { 650 UINTN Size; 651 652 Size = ASPrint ( 653 Buffer, 654 BufferSize, 655 "%02d/%02d/%04d %02d:%02d", 656 (UINTN)Time->Month, 657 (UINTN)Time->Day, 658 (UINTN)Time->Year, 659 (UINTN)Time->Hour, 660 (UINTN)Time->Minute 661 ); 662 663 // 664 // ASPrint will null terminate the string. The -1 skips the null 665 // 666 return Size - 1; 667 } 668 669 STATIC 670 UINTN 671 EfiStatusToString ( 672 IN EFI_STATUS Status, 673 OUT CHAR8 *Buffer, 674 IN UINTN BufferSize 675 ) 676 /*++ 677 678 Routine Description: 679 680 AvSPrint worker function that prints EFI_STATUS as a string. If string is 681 not known a hex value will be printed. 682 683 Arguments: 684 685 Status - EFI_STATUS sturcture to print. 686 687 Buffer - Buffer to print EFI_STATUS message string into. 688 689 BufferSize - Size of Buffer. 690 691 Returns: 692 693 Number of characters printed. 694 695 --*/ 696 { 697 UINTN Size; 698 CHAR8 *Desc; 699 700 if (Status == EFI_SUCCESS) { 701 Desc = "Success"; 702 } else if (Status == EFI_LOAD_ERROR) { 703 Desc = "Load Error"; 704 } else if (Status == EFI_INVALID_PARAMETER) { 705 Desc = "Invalid Parameter"; 706 } else if (Status == EFI_UNSUPPORTED) { 707 Desc = "Unsupported"; 708 } else if (Status == EFI_BAD_BUFFER_SIZE) { 709 Desc = "Bad Buffer Size"; 710 } else if (Status == EFI_BUFFER_TOO_SMALL) { 711 Desc = "Buffer Too Small"; 712 } else if (Status == EFI_NOT_READY) { 713 Desc = "Not Ready"; 714 } else if (Status == EFI_DEVICE_ERROR) { 715 Desc = "Device Error"; 716 } else if (Status == EFI_WRITE_PROTECTED) { 717 Desc = "Write Protected"; 718 } else if (Status == EFI_OUT_OF_RESOURCES) { 719 Desc = "Out of Resources"; 720 } else if (Status == EFI_VOLUME_CORRUPTED) { 721 Desc = "Volume Corrupt"; 722 } else if (Status == EFI_VOLUME_FULL) { 723 Desc = "Volume Full"; 724 } else if (Status == EFI_NO_MEDIA) { 725 Desc = "No Media"; 726 } else if (Status == EFI_MEDIA_CHANGED) { 727 Desc = "Media changed"; 728 } else if (Status == EFI_NOT_FOUND) { 729 Desc = "Not Found"; 730 } else if (Status == EFI_ACCESS_DENIED) { 731 Desc = "Access Denied"; 732 } else if (Status == EFI_NO_RESPONSE) { 733 Desc = "No Response"; 734 } else if (Status == EFI_NO_MAPPING) { 735 Desc = "No mapping"; 736 } else if (Status == EFI_TIMEOUT) { 737 Desc = "Time out"; 738 } else if (Status == EFI_NOT_STARTED) { 739 Desc = "Not started"; 740 } else if (Status == EFI_ALREADY_STARTED) { 741 Desc = "Already started"; 742 } else if (Status == EFI_ABORTED) { 743 Desc = "Aborted"; 744 } else if (Status == EFI_ICMP_ERROR) { 745 Desc = "ICMP Error"; 746 } else if (Status == EFI_TFTP_ERROR) { 747 Desc = "TFTP Error"; 748 } else if (Status == EFI_PROTOCOL_ERROR) { 749 Desc = "Protocol Error"; 750 } else if (Status == EFI_WARN_UNKNOWN_GLYPH) { 751 Desc = "Warning Unknown Glyph"; 752 } else if (Status == EFI_WARN_DELETE_FAILURE) { 753 Desc = "Warning Delete Failure"; 754 } else if (Status == EFI_WARN_WRITE_FAILURE) { 755 Desc = "Warning Write Failure"; 756 } else if (Status == EFI_WARN_BUFFER_TOO_SMALL) { 757 Desc = "Warning Buffer Too Small"; 758 } else { 759 Desc = NULL; 760 } 761 // 762 // If we found a match, copy the message to the user's buffer. Otherwise 763 // sprint the hex status code to their buffer. 764 // 765 if (Desc != NULL) { 766 Size = ASPrint (Buffer, BufferSize, "%a", Desc); 767 } else { 768 Size = ASPrint (Buffer, BufferSize, "%X", Status); 769 } 770 return Size - 1; 771 } 772