Home | History | Annotate | Download | only in common
      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 
     26 void tf_string_print(const char *str)
     27 {
     28 	assert(str);
     29 
     30 	while (*str)
     31 		putchar(*str++);
     32 }
     33 
     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  *******************************************************************/
     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 
    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