1 /*
2  * Copyright (c) 2014-2016, ARM Limited and Contributors. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 #include <arch.h>
7 #include <arch_helpers.h>
8 #include <assert.h>
9 #include <debug.h>
10 #include <limits.h>
11 #include <stdarg.h>
12 #include <stdint.h>
13 
14 /***********************************************************
15  * The tf_printf implementation for all BL stages
16  ***********************************************************/
17 
18 #define get_num_va_args(args, lcount) \
19 	(((lcount) > 1) ? va_arg(args, long long int) :	\
20 	((lcount) ? va_arg(args, long int) : va_arg(args, int)))
21 
22 #define get_unum_va_args(args, lcount) \
23 	(((lcount) > 1) ? va_arg(args, unsigned long long int) :	\
24 	((lcount) ? va_arg(args, unsigned long int) : va_arg(args, unsigned int)))
25 
tf_string_print(const char * str)26 void tf_string_print(const char *str)
27 {
28 	assert(str);
29 
30 	while (*str)
31 		putchar(*str++);
32 }
33 
unsigned_num_print(unsigned long long int unum,unsigned int radix)34 static void unsigned_num_print(unsigned long long int unum, unsigned int radix)
35 {
36 	/* Just need enough space to store 64 bit decimal integer */
37 	unsigned char num_buf[20];
38 	int i = 0, rem;
39 
40 	do {
41 		rem = unum % radix;
42 		if (rem < 0xa)
43 			num_buf[i++] = '0' + rem;
44 		else
45 			num_buf[i++] = 'a' + (rem - 0xa);
46 	} while (unum /= radix);
47 
48 	while (--i >= 0)
49 		putchar(num_buf[i]);
50 }
51 
52 /*******************************************************************
53  * Reduced format print for Trusted firmware.
54  * The following type specifiers are supported by this print
55  * %x - hexadecimal format
56  * %s - string format
57  * %d or %i - signed decimal format
58  * %u - unsigned decimal format
59  * %p - pointer format
60  *
61  * The following length specifiers are supported by this print
62  * %l - long int (64-bit on AArch64)
63  * %ll - long long int (64-bit on AArch64)
64  * %z - size_t sized integer formats (64 bit on AArch64)
65  *
66  * The print exits on all other formats specifiers other than valid
67  * combinations of the above specifiers.
68  *******************************************************************/
tf_vprintf(const char * fmt,va_list args)69 void tf_vprintf(const char *fmt, va_list args)
70 {
71 	int l_count;
72 	long long int num;
73 	unsigned long long int unum;
74 	char *str;
75 
76 	while (*fmt) {
77 		l_count = 0;
78 
79 		if (*fmt == '%') {
80 			fmt++;
81 			/* Check the format specifier */
82 loop:
83 			switch (*fmt) {
84 			case 'i': /* Fall through to next one */
85 			case 'd':
86 				num = get_num_va_args(args, l_count);
87 				if (num < 0) {
88 					putchar('-');
89 					unum = (unsigned long long int)-num;
90 				} else
91 					unum = (unsigned long long int)num;
92 
93 				unsigned_num_print(unum, 10);
94 				break;
95 			case 's':
96 				str = va_arg(args, char *);
97 				tf_string_print(str);
98 				break;
99 			case 'p':
100 				unum = (uintptr_t)va_arg(args, void *);
101 				if (unum)
102 					tf_string_print("0x");
103 
104 				unsigned_num_print(unum, 16);
105 				break;
106 			case 'x':
107 				unum = get_unum_va_args(args, l_count);
108 				unsigned_num_print(unum, 16);
109 				break;
110 			case 'z':
111 				if (sizeof(size_t) == 8)
112 					l_count = 2;
113 
114 				fmt++;
115 				goto loop;
116 			case 'l':
117 				l_count++;
118 				fmt++;
119 				goto loop;
120 			case 'u':
121 				unum = get_unum_va_args(args, l_count);
122 				unsigned_num_print(unum, 10);
123 				break;
124 			default:
125 				/* Exit on any other format specifier */
126 				return;
127 			}
128 			fmt++;
129 			continue;
130 		}
131 		putchar(*fmt++);
132 	}
133 }
134 
tf_printf(const char * fmt,...)135 void tf_printf(const char *fmt, ...)
136 {
137 	va_list va;
138 
139 	va_start(va, fmt);
140 	tf_vprintf(fmt, va);
141 	va_end(va);
142 }
143