]> git.proxmox.com Git - mirror_edk2.git/blob - EdkCompatibilityPkg/Foundation/Library/Pei/PeiLib/Print/Print.c
Refine code to make it more safely.
[mirror_edk2.git] / EdkCompatibilityPkg / Foundation / Library / Pei / PeiLib / Print / Print.c
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 }