1 /* 2 * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 #include <assert.h> 7 #include <debug.h> 8 #include <stdarg.h> 9 #include <stdint.h> 10 11 /*********************************************************** 12 * The tf_printf implementation for all BL stages 13 ***********************************************************/ 14 15 #define get_num_va_args(_args, _lcount) \ 16 (((_lcount) > 1) ? va_arg(_args, long long int) : \ 17 ((_lcount) ? va_arg(_args, long int) : va_arg(_args, int))) 18 19 #define get_unum_va_args(_args, _lcount) \ 20 (((_lcount) > 1) ? va_arg(_args, unsigned long long int) : \ 21 ((_lcount) ? va_arg(_args, unsigned long int) : va_arg(_args, unsigned int))) 22 23 static int string_print(const char *str) 24 { 25 int count = 0; 26 27 assert(str); 28 29 while (*str) { 30 putchar(*str++); 31 count++; 32 } 33 34 return count; 35 } 36 37 static int unsigned_num_print(unsigned long long int unum, unsigned int radix, 38 char padc, int padn) 39 { 40 /* Just need enough space to store 64 bit decimal integer */ 41 unsigned char num_buf[20]; 42 int i = 0, rem, count = 0; 43 44 do { 45 rem = unum % radix; 46 if (rem < 0xa) 47 num_buf[i++] = '0' + rem; 48 else 49 num_buf[i++] = 'a' + (rem - 0xa); 50 } while (unum /= radix); 51 52 if (padn > 0) { 53 while (i < padn--) { 54 putchar(padc); 55 count++; 56 } 57 } 58 59 while (--i >= 0) { 60 putchar(num_buf[i]); 61 count++; 62 } 63 64 return count; 65 } 66 67 /******************************************************************* 68 * Reduced format print for Trusted firmware. 69 * The following type specifiers are supported by this print 70 * %x - hexadecimal format 71 * %s - string format 72 * %d or %i - signed decimal format 73 * %u - unsigned decimal format 74 * %p - pointer format 75 * 76 * The following length specifiers are supported by this print 77 * %l - long int (64-bit on AArch64) 78 * %ll - long long int (64-bit on AArch64) 79 * %z - size_t sized integer formats (64 bit on AArch64) 80 * 81 * The following padding specifiers are supported by this print 82 * %0NN - Left-pad the number with 0s (NN is a decimal number) 83 * 84 * The print exits on all other formats specifiers other than valid 85 * combinations of the above specifiers. 86 *******************************************************************/ 87 int vprintf(const char *fmt, va_list args) 88 { 89 int l_count; 90 long long int num; 91 unsigned long long int unum; 92 char *str; 93 char padc = 0; /* Padding character */ 94 int padn; /* Number of characters to pad */ 95 int count = 0; /* Number of printed characters */ 96 97 while (*fmt) { 98 l_count = 0; 99 padn = 0; 100 101 if (*fmt == '%') { 102 fmt++; 103 /* Check the format specifier */ 104 loop: 105 switch (*fmt) { 106 case 'i': /* Fall through to next one */ 107 case 'd': 108 num = get_num_va_args(args, l_count); 109 if (num < 0) { 110 putchar('-'); 111 unum = (unsigned long long int)-num; 112 padn--; 113 } else 114 unum = (unsigned long long int)num; 115 116 count += unsigned_num_print(unum, 10, 117 padc, padn); 118 break; 119 case 's': 120 str = va_arg(args, char *); 121 count += string_print(str); 122 break; 123 case 'p': 124 unum = (uintptr_t)va_arg(args, void *); 125 if (unum) { 126 count += string_print("0x"); 127 padn -= 2; 128 } 129 130 count += unsigned_num_print(unum, 16, 131 padc, padn); 132 break; 133 case 'x': 134 unum = get_unum_va_args(args, l_count); 135 count += unsigned_num_print(unum, 16, 136 padc, padn); 137 break; 138 case 'z': 139 if (sizeof(size_t) == 8) 140 l_count = 2; 141 142 fmt++; 143 goto loop; 144 case 'l': 145 l_count++; 146 fmt++; 147 goto loop; 148 case 'u': 149 unum = get_unum_va_args(args, l_count); 150 count += unsigned_num_print(unum, 10, 151 padc, padn); 152 break; 153 case '0': 154 padc = '0'; 155 padn = 0; 156 fmt++; 157 158 while (1) { 159 char ch = *fmt; 160 if (ch < '0' || ch > '9') { 161 goto loop; 162 } 163 padn = (padn * 10) + (ch - '0'); 164 fmt++; 165 } 166 default: 167 /* Exit on any other format specifier */ 168 return -1; 169 } 170 fmt++; 171 continue; 172 } 173 putchar(*fmt++); 174 count++; 175 } 176 177 return count; 178 } 179 180 int printf(const char *fmt, ...) 181 { 182 int count; 183 va_list va; 184 185 va_start(va, fmt); 186 count = vprintf(fmt, va); 187 va_end(va); 188 189 return count; 190 } 191