blob: 0a5ae65d039e335ccfe7b7fe6fccbe1ce44f2542 [file] [log] [blame]
Soby Mathewafe7e2f2014-06-12 17:23:58 +01001/*
Soby Mathewf62d5462016-03-22 17:38:00 +00002 * Copyright (c) 2014-2016, ARM Limited and Contributors. All rights reserved.
Soby Mathewafe7e2f2014-06-12 17:23:58 +01003 *
dp-armfa3cf0b2017-05-03 09:38:09 +01004 * SPDX-License-Identifier: BSD-3-Clause
Soby Mathewafe7e2f2014-06-12 17:23:58 +01005 */
Soby Mathew0691d972016-05-05 12:34:41 +01006#include <arch.h>
7#include <arch_helpers.h>
8#include <assert.h>
Soby Mathewafe7e2f2014-06-12 17:23:58 +01009#include <debug.h>
Soby Mathew0691d972016-05-05 12:34:41 +010010#include <limits.h>
Soby Mathewafe7e2f2014-06-12 17:23:58 +010011#include <stdarg.h>
12#include <stdint.h>
13
14/***********************************************************
15 * The tf_printf implementation for all BL stages
16 ***********************************************************/
Soby Mathewf62d5462016-03-22 17:38:00 +000017
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
26static void string_print(const char *str)
27{
28 while (*str)
29 putchar(*str++);
30}
31
Soby Mathew0691d972016-05-05 12:34:41 +010032#ifdef AARCH32
33#define unsigned_num_print(unum, radix) \
34 do { \
35 if ((radix) == 16) \
36 unsigned_hex_print(unum); \
37 else if ((radix) == 10) \
38 unsigned_dec_print(unum); \
39 else \
40 string_print("tf_printf : Unsupported radix");\
41 } while (0);
42
43/*
44 * Utility function to print an unsigned number in decimal format for AArch32.
45 * The function doesn't support printing decimal integers higher than 32 bits
46 * to avoid having to implement 64-bit integer compiler library functions.
47 */
48static void unsigned_dec_print(unsigned long long int unum)
49{
50 unsigned int local_num;
51 /* Just need enough space to store 32 bit decimal integer */
52 unsigned char num_buf[10];
53 int i = 0, rem;
54
55 if (unum > UINT_MAX) {
56 string_print("tf_printf : decimal numbers higher than 32 bits"
57 " not supported\n");
58 return;
59 }
60
61 local_num = (unsigned int)unum;
62
63 do {
64 rem = local_num % 10;
65 num_buf[i++] = '0' + rem;
66 } while (local_num /= 10);
67
68 while (--i >= 0)
69 putchar(num_buf[i]);
70}
71
72/*
73 * Utility function to print an unsigned number in hexadecimal format for
74 * AArch32. The function doesn't use 64-bit integer arithmetic to avoid
75 * having to implement 64-bit compiler library functions. It splits the
76 * 64 bit number into two 32 bit numbers and converts them into equivalent
77 * ASCII characters.
78 */
79static void unsigned_hex_print(unsigned long long int unum)
80{
81 /* Just need enough space to store 16 characters */
82 unsigned char num_buf[16];
83 int i = 0, rem;
84 uint32_t num_local = 0, num_msb = 0;
85
86 /* Get the LSB of 64 bit unum */
87 num_local = (uint32_t)unum;
88 /* Get the MSB of 64 bit unum. This works only on Little Endian */
89 assert((read_sctlr() & SCTLR_EE_BIT) == 0);
90 num_msb = *(((uint32_t *) &unum) + 1);
91
92 do {
93 do {
94 rem = (num_local & 0xf);
95 if (rem < 0xa)
96 num_buf[i++] = '0' + rem;
97 else
98 num_buf[i++] = 'a' + (rem - 0xa);
99 } while (num_local >>= 4);
100
101 num_local = num_msb;
102 num_msb = 0;
103 } while (num_local);
104
105 while (--i >= 0)
106 putchar(num_buf[i]);
107}
108
109#else
110
Soby Mathewf62d5462016-03-22 17:38:00 +0000111static void unsigned_num_print(unsigned long long int unum, unsigned int radix)
Soby Mathewafe7e2f2014-06-12 17:23:58 +0100112{
113 /* Just need enough space to store 64 bit decimal integer */
114 unsigned char num_buf[20];
Sandrine Bailleuxa64a8542015-03-05 10:54:34 +0000115 int i = 0, rem;
Soby Mathewafe7e2f2014-06-12 17:23:58 +0100116
117 do {
118 rem = unum % radix;
119 if (rem < 0xa)
120 num_buf[i++] = '0' + rem;
121 else
122 num_buf[i++] = 'a' + (rem - 0xa);
123 } while (unum /= radix);
124
125 while (--i >= 0)
126 putchar(num_buf[i]);
127}
Soby Mathew0691d972016-05-05 12:34:41 +0100128#endif /* AARCH32 */
Soby Mathewafe7e2f2014-06-12 17:23:58 +0100129
Soby Mathewafe7e2f2014-06-12 17:23:58 +0100130/*******************************************************************
131 * Reduced format print for Trusted firmware.
Soby Mathewf62d5462016-03-22 17:38:00 +0000132 * The following type specifiers are supported by this print
133 * %x - hexadecimal format
Soby Mathewafe7e2f2014-06-12 17:23:58 +0100134 * %s - string format
Soby Mathewf62d5462016-03-22 17:38:00 +0000135 * %d or %i - signed decimal format
136 * %u - unsigned decimal format
Antonio Nino Diazb3a0a7b2016-02-02 12:03:38 +0000137 * %p - pointer format
Soby Mathewf62d5462016-03-22 17:38:00 +0000138 *
139 * The following length specifiers are supported by this print
140 * %l - long int (64-bit on AArch64)
141 * %ll - long long int (64-bit on AArch64)
142 * %z - size_t sized integer formats (64 bit on AArch64)
143 *
144 * The print exits on all other formats specifiers other than valid
145 * combinations of the above specifiers.
Soby Mathewafe7e2f2014-06-12 17:23:58 +0100146 *******************************************************************/
Soby Mathewafe7e2f2014-06-12 17:23:58 +0100147void tf_printf(const char *fmt, ...)
148{
149 va_list args;
Soby Mathewf62d5462016-03-22 17:38:00 +0000150 int l_count;
151 long long int num;
152 unsigned long long int unum;
Soby Mathewafe7e2f2014-06-12 17:23:58 +0100153 char *str;
154
155 va_start(args, fmt);
156 while (*fmt) {
Soby Mathewf62d5462016-03-22 17:38:00 +0000157 l_count = 0;
Soby Mathewafe7e2f2014-06-12 17:23:58 +0100158
159 if (*fmt == '%') {
160 fmt++;
161 /* Check the format specifier */
162loop:
163 switch (*fmt) {
164 case 'i': /* Fall through to next one */
165 case 'd':
Soby Mathewf62d5462016-03-22 17:38:00 +0000166 num = get_num_va_args(args, l_count);
Soby Mathewafe7e2f2014-06-12 17:23:58 +0100167 if (num < 0) {
168 putchar('-');
Soby Mathewf62d5462016-03-22 17:38:00 +0000169 unum = (unsigned long long int)-num;
Soby Mathewafe7e2f2014-06-12 17:23:58 +0100170 } else
Soby Mathewf62d5462016-03-22 17:38:00 +0000171 unum = (unsigned long long int)num;
Soby Mathewafe7e2f2014-06-12 17:23:58 +0100172
173 unsigned_num_print(unum, 10);
174 break;
175 case 's':
176 str = va_arg(args, char *);
177 string_print(str);
178 break;
Antonio Nino Diazb3a0a7b2016-02-02 12:03:38 +0000179 case 'p':
Soby Mathewf62d5462016-03-22 17:38:00 +0000180 unum = (uintptr_t)va_arg(args, void *);
Antonio Nino Diazb3a0a7b2016-02-02 12:03:38 +0000181 if (unum)
182 string_print("0x");
183
184 unsigned_num_print(unum, 16);
185 break;
Soby Mathewafe7e2f2014-06-12 17:23:58 +0100186 case 'x':
Soby Mathewf62d5462016-03-22 17:38:00 +0000187 unum = get_unum_va_args(args, l_count);
Soby Mathewafe7e2f2014-06-12 17:23:58 +0100188 unsigned_num_print(unum, 16);
189 break;
Scott Branden57bd75c2016-03-23 13:37:33 -0700190 case 'z':
191 if (sizeof(size_t) == 8)
Soby Mathewf62d5462016-03-22 17:38:00 +0000192 l_count = 2;
193
Scott Branden57bd75c2016-03-23 13:37:33 -0700194 fmt++;
195 goto loop;
Soby Mathewafe7e2f2014-06-12 17:23:58 +0100196 case 'l':
Soby Mathewf62d5462016-03-22 17:38:00 +0000197 l_count++;
Soby Mathewafe7e2f2014-06-12 17:23:58 +0100198 fmt++;
199 goto loop;
200 case 'u':
Soby Mathewf62d5462016-03-22 17:38:00 +0000201 unum = get_unum_va_args(args, l_count);
Soby Mathewafe7e2f2014-06-12 17:23:58 +0100202 unsigned_num_print(unum, 10);
203 break;
204 default:
205 /* Exit on any other format specifier */
206 goto exit;
207 }
208 fmt++;
209 continue;
210 }
211 putchar(*fmt++);
212 }
213exit:
214 va_end(args);
215}