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