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
26void tf_string_print(const char *str)
27{
28	assert(str);
29
30	while (*str)
31		putchar(*str++);
32}
33
34static 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 *******************************************************************/
69void 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 */
82loop:
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
135void 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