xref: /openbmc/linux/arch/x86/boot/printf.c (revision 97873a3d)
197873a3dSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
296ae6ea0SThomas Gleixner /* -*- linux-c -*- ------------------------------------------------------- *
396ae6ea0SThomas Gleixner  *
496ae6ea0SThomas Gleixner  *   Copyright (C) 1991, 1992 Linus Torvalds
596ae6ea0SThomas Gleixner  *   Copyright 2007 rPath, Inc. - All Rights Reserved
696ae6ea0SThomas Gleixner  *
796ae6ea0SThomas Gleixner  * ----------------------------------------------------------------------- */
896ae6ea0SThomas Gleixner 
996ae6ea0SThomas Gleixner /*
1096ae6ea0SThomas Gleixner  * Oh, it's a waste of space, but oh-so-yummy for debugging.  This
1196ae6ea0SThomas Gleixner  * version of printf() does not include 64-bit support.  "Live with
1296ae6ea0SThomas Gleixner  * it."
1396ae6ea0SThomas Gleixner  *
1496ae6ea0SThomas Gleixner  */
1596ae6ea0SThomas Gleixner 
1696ae6ea0SThomas Gleixner #include "boot.h"
1796ae6ea0SThomas Gleixner 
skip_atoi(const char ** s)1896ae6ea0SThomas Gleixner static int skip_atoi(const char **s)
1996ae6ea0SThomas Gleixner {
2096ae6ea0SThomas Gleixner 	int i = 0;
2196ae6ea0SThomas Gleixner 
2296ae6ea0SThomas Gleixner 	while (isdigit(**s))
2396ae6ea0SThomas Gleixner 		i = i * 10 + *((*s)++) - '0';
2496ae6ea0SThomas Gleixner 	return i;
2596ae6ea0SThomas Gleixner }
2696ae6ea0SThomas Gleixner 
2796ae6ea0SThomas Gleixner #define ZEROPAD	1		/* pad with zero */
2896ae6ea0SThomas Gleixner #define SIGN	2		/* unsigned/signed long */
2996ae6ea0SThomas Gleixner #define PLUS	4		/* show plus */
3096ae6ea0SThomas Gleixner #define SPACE	8		/* space if plus */
3196ae6ea0SThomas Gleixner #define LEFT	16		/* left justified */
329b706aeeSDenys Vlasenko #define SMALL	32		/* Must be 32 == 0x20 */
339b706aeeSDenys Vlasenko #define SPECIAL	64		/* 0x */
3496ae6ea0SThomas Gleixner 
35f4ed2877SYinghai Lu #define __do_div(n, base) ({ \
3696ae6ea0SThomas Gleixner int __res; \
3796ae6ea0SThomas Gleixner __res = ((unsigned long) n) % (unsigned) base; \
3896ae6ea0SThomas Gleixner n = ((unsigned long) n) / (unsigned) base; \
3996ae6ea0SThomas Gleixner __res; })
4096ae6ea0SThomas Gleixner 
number(char * str,long num,int base,int size,int precision,int type)4196ae6ea0SThomas Gleixner static char *number(char *str, long num, int base, int size, int precision,
4296ae6ea0SThomas Gleixner 		    int type)
4396ae6ea0SThomas Gleixner {
449b706aeeSDenys Vlasenko 	/* we are called with base 8, 10 or 16, only, thus don't need "G..."  */
459b706aeeSDenys Vlasenko 	static const char digits[16] = "0123456789ABCDEF"; /* "GHIJKLMNOPQRSTUVWXYZ"; */
469b706aeeSDenys Vlasenko 
479b706aeeSDenys Vlasenko 	char tmp[66];
489b706aeeSDenys Vlasenko 	char c, sign, locase;
4996ae6ea0SThomas Gleixner 	int i;
5096ae6ea0SThomas Gleixner 
519b706aeeSDenys Vlasenko 	/* locase = 0 or 0x20. ORing digits or letters with 'locase'
529b706aeeSDenys Vlasenko 	 * produces same digits or (maybe lowercased) letters */
539b706aeeSDenys Vlasenko 	locase = (type & SMALL);
5496ae6ea0SThomas Gleixner 	if (type & LEFT)
5596ae6ea0SThomas Gleixner 		type &= ~ZEROPAD;
565b8fafcaSDan Carpenter 	if (base < 2 || base > 16)
577fafd91dSHarvey Harrison 		return NULL;
5896ae6ea0SThomas Gleixner 	c = (type & ZEROPAD) ? '0' : ' ';
5996ae6ea0SThomas Gleixner 	sign = 0;
6096ae6ea0SThomas Gleixner 	if (type & SIGN) {
6196ae6ea0SThomas Gleixner 		if (num < 0) {
6296ae6ea0SThomas Gleixner 			sign = '-';
6396ae6ea0SThomas Gleixner 			num = -num;
6496ae6ea0SThomas Gleixner 			size--;
6596ae6ea0SThomas Gleixner 		} else if (type & PLUS) {
6696ae6ea0SThomas Gleixner 			sign = '+';
6796ae6ea0SThomas Gleixner 			size--;
6896ae6ea0SThomas Gleixner 		} else if (type & SPACE) {
6996ae6ea0SThomas Gleixner 			sign = ' ';
7096ae6ea0SThomas Gleixner 			size--;
7196ae6ea0SThomas Gleixner 		}
7296ae6ea0SThomas Gleixner 	}
7396ae6ea0SThomas Gleixner 	if (type & SPECIAL) {
7496ae6ea0SThomas Gleixner 		if (base == 16)
7596ae6ea0SThomas Gleixner 			size -= 2;
7696ae6ea0SThomas Gleixner 		else if (base == 8)
7796ae6ea0SThomas Gleixner 			size--;
7896ae6ea0SThomas Gleixner 	}
7996ae6ea0SThomas Gleixner 	i = 0;
8096ae6ea0SThomas Gleixner 	if (num == 0)
8196ae6ea0SThomas Gleixner 		tmp[i++] = '0';
8296ae6ea0SThomas Gleixner 	else
8396ae6ea0SThomas Gleixner 		while (num != 0)
84f4ed2877SYinghai Lu 			tmp[i++] = (digits[__do_div(num, base)] | locase);
8596ae6ea0SThomas Gleixner 	if (i > precision)
8696ae6ea0SThomas Gleixner 		precision = i;
8796ae6ea0SThomas Gleixner 	size -= precision;
8896ae6ea0SThomas Gleixner 	if (!(type & (ZEROPAD + LEFT)))
8996ae6ea0SThomas Gleixner 		while (size-- > 0)
9096ae6ea0SThomas Gleixner 			*str++ = ' ';
9196ae6ea0SThomas Gleixner 	if (sign)
9296ae6ea0SThomas Gleixner 		*str++ = sign;
9396ae6ea0SThomas Gleixner 	if (type & SPECIAL) {
9496ae6ea0SThomas Gleixner 		if (base == 8)
9596ae6ea0SThomas Gleixner 			*str++ = '0';
9696ae6ea0SThomas Gleixner 		else if (base == 16) {
9796ae6ea0SThomas Gleixner 			*str++ = '0';
989b706aeeSDenys Vlasenko 			*str++ = ('X' | locase);
9996ae6ea0SThomas Gleixner 		}
10096ae6ea0SThomas Gleixner 	}
10196ae6ea0SThomas Gleixner 	if (!(type & LEFT))
10296ae6ea0SThomas Gleixner 		while (size-- > 0)
10396ae6ea0SThomas Gleixner 			*str++ = c;
10496ae6ea0SThomas Gleixner 	while (i < precision--)
10596ae6ea0SThomas Gleixner 		*str++ = '0';
10696ae6ea0SThomas Gleixner 	while (i-- > 0)
10796ae6ea0SThomas Gleixner 		*str++ = tmp[i];
10896ae6ea0SThomas Gleixner 	while (size-- > 0)
10996ae6ea0SThomas Gleixner 		*str++ = ' ';
11096ae6ea0SThomas Gleixner 	return str;
11196ae6ea0SThomas Gleixner }
11296ae6ea0SThomas Gleixner 
vsprintf(char * buf,const char * fmt,va_list args)11396ae6ea0SThomas Gleixner int vsprintf(char *buf, const char *fmt, va_list args)
11496ae6ea0SThomas Gleixner {
11596ae6ea0SThomas Gleixner 	int len;
11696ae6ea0SThomas Gleixner 	unsigned long num;
11796ae6ea0SThomas Gleixner 	int i, base;
11896ae6ea0SThomas Gleixner 	char *str;
11996ae6ea0SThomas Gleixner 	const char *s;
12096ae6ea0SThomas Gleixner 
12196ae6ea0SThomas Gleixner 	int flags;		/* flags to number() */
12296ae6ea0SThomas Gleixner 
12396ae6ea0SThomas Gleixner 	int field_width;	/* width of output field */
12496ae6ea0SThomas Gleixner 	int precision;		/* min. # of digits for integers; max
12596ae6ea0SThomas Gleixner 				   number of chars for from string */
12696ae6ea0SThomas Gleixner 	int qualifier;		/* 'h', 'l', or 'L' for integer fields */
12796ae6ea0SThomas Gleixner 
12896ae6ea0SThomas Gleixner 	for (str = buf; *fmt; ++fmt) {
12996ae6ea0SThomas Gleixner 		if (*fmt != '%') {
13096ae6ea0SThomas Gleixner 			*str++ = *fmt;
13196ae6ea0SThomas Gleixner 			continue;
13296ae6ea0SThomas Gleixner 		}
13396ae6ea0SThomas Gleixner 
13496ae6ea0SThomas Gleixner 		/* process flags */
13596ae6ea0SThomas Gleixner 		flags = 0;
13696ae6ea0SThomas Gleixner 	      repeat:
13796ae6ea0SThomas Gleixner 		++fmt;		/* this also skips first '%' */
13896ae6ea0SThomas Gleixner 		switch (*fmt) {
13996ae6ea0SThomas Gleixner 		case '-':
14096ae6ea0SThomas Gleixner 			flags |= LEFT;
14196ae6ea0SThomas Gleixner 			goto repeat;
14296ae6ea0SThomas Gleixner 		case '+':
14396ae6ea0SThomas Gleixner 			flags |= PLUS;
14496ae6ea0SThomas Gleixner 			goto repeat;
14596ae6ea0SThomas Gleixner 		case ' ':
14696ae6ea0SThomas Gleixner 			flags |= SPACE;
14796ae6ea0SThomas Gleixner 			goto repeat;
14896ae6ea0SThomas Gleixner 		case '#':
14996ae6ea0SThomas Gleixner 			flags |= SPECIAL;
15096ae6ea0SThomas Gleixner 			goto repeat;
15196ae6ea0SThomas Gleixner 		case '0':
15296ae6ea0SThomas Gleixner 			flags |= ZEROPAD;
15396ae6ea0SThomas Gleixner 			goto repeat;
15496ae6ea0SThomas Gleixner 		}
15596ae6ea0SThomas Gleixner 
15696ae6ea0SThomas Gleixner 		/* get field width */
15796ae6ea0SThomas Gleixner 		field_width = -1;
15896ae6ea0SThomas Gleixner 		if (isdigit(*fmt))
15996ae6ea0SThomas Gleixner 			field_width = skip_atoi(&fmt);
16096ae6ea0SThomas Gleixner 		else if (*fmt == '*') {
16196ae6ea0SThomas Gleixner 			++fmt;
16296ae6ea0SThomas Gleixner 			/* it's the next argument */
16396ae6ea0SThomas Gleixner 			field_width = va_arg(args, int);
16496ae6ea0SThomas Gleixner 			if (field_width < 0) {
16596ae6ea0SThomas Gleixner 				field_width = -field_width;
16696ae6ea0SThomas Gleixner 				flags |= LEFT;
16796ae6ea0SThomas Gleixner 			}
16896ae6ea0SThomas Gleixner 		}
16996ae6ea0SThomas Gleixner 
17096ae6ea0SThomas Gleixner 		/* get the precision */
17196ae6ea0SThomas Gleixner 		precision = -1;
17296ae6ea0SThomas Gleixner 		if (*fmt == '.') {
17396ae6ea0SThomas Gleixner 			++fmt;
17496ae6ea0SThomas Gleixner 			if (isdigit(*fmt))
17596ae6ea0SThomas Gleixner 				precision = skip_atoi(&fmt);
17696ae6ea0SThomas Gleixner 			else if (*fmt == '*') {
17796ae6ea0SThomas Gleixner 				++fmt;
17896ae6ea0SThomas Gleixner 				/* it's the next argument */
17996ae6ea0SThomas Gleixner 				precision = va_arg(args, int);
18096ae6ea0SThomas Gleixner 			}
18196ae6ea0SThomas Gleixner 			if (precision < 0)
18296ae6ea0SThomas Gleixner 				precision = 0;
18396ae6ea0SThomas Gleixner 		}
18496ae6ea0SThomas Gleixner 
18596ae6ea0SThomas Gleixner 		/* get the conversion qualifier */
18696ae6ea0SThomas Gleixner 		qualifier = -1;
18796ae6ea0SThomas Gleixner 		if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') {
18896ae6ea0SThomas Gleixner 			qualifier = *fmt;
18996ae6ea0SThomas Gleixner 			++fmt;
19096ae6ea0SThomas Gleixner 		}
19196ae6ea0SThomas Gleixner 
19296ae6ea0SThomas Gleixner 		/* default base */
19396ae6ea0SThomas Gleixner 		base = 10;
19496ae6ea0SThomas Gleixner 
19596ae6ea0SThomas Gleixner 		switch (*fmt) {
19696ae6ea0SThomas Gleixner 		case 'c':
19796ae6ea0SThomas Gleixner 			if (!(flags & LEFT))
19896ae6ea0SThomas Gleixner 				while (--field_width > 0)
19996ae6ea0SThomas Gleixner 					*str++ = ' ';
20096ae6ea0SThomas Gleixner 			*str++ = (unsigned char)va_arg(args, int);
20196ae6ea0SThomas Gleixner 			while (--field_width > 0)
20296ae6ea0SThomas Gleixner 				*str++ = ' ';
20396ae6ea0SThomas Gleixner 			continue;
20496ae6ea0SThomas Gleixner 
20596ae6ea0SThomas Gleixner 		case 's':
20696ae6ea0SThomas Gleixner 			s = va_arg(args, char *);
20796ae6ea0SThomas Gleixner 			len = strnlen(s, precision);
20896ae6ea0SThomas Gleixner 
20996ae6ea0SThomas Gleixner 			if (!(flags & LEFT))
21096ae6ea0SThomas Gleixner 				while (len < field_width--)
21196ae6ea0SThomas Gleixner 					*str++ = ' ';
21296ae6ea0SThomas Gleixner 			for (i = 0; i < len; ++i)
21396ae6ea0SThomas Gleixner 				*str++ = *s++;
21496ae6ea0SThomas Gleixner 			while (len < field_width--)
21596ae6ea0SThomas Gleixner 				*str++ = ' ';
21696ae6ea0SThomas Gleixner 			continue;
21796ae6ea0SThomas Gleixner 
21896ae6ea0SThomas Gleixner 		case 'p':
21996ae6ea0SThomas Gleixner 			if (field_width == -1) {
22096ae6ea0SThomas Gleixner 				field_width = 2 * sizeof(void *);
22196ae6ea0SThomas Gleixner 				flags |= ZEROPAD;
22296ae6ea0SThomas Gleixner 			}
22396ae6ea0SThomas Gleixner 			str = number(str,
22496ae6ea0SThomas Gleixner 				     (unsigned long)va_arg(args, void *), 16,
22596ae6ea0SThomas Gleixner 				     field_width, precision, flags);
22696ae6ea0SThomas Gleixner 			continue;
22796ae6ea0SThomas Gleixner 
22896ae6ea0SThomas Gleixner 		case 'n':
22996ae6ea0SThomas Gleixner 			if (qualifier == 'l') {
23096ae6ea0SThomas Gleixner 				long *ip = va_arg(args, long *);
23196ae6ea0SThomas Gleixner 				*ip = (str - buf);
23296ae6ea0SThomas Gleixner 			} else {
23396ae6ea0SThomas Gleixner 				int *ip = va_arg(args, int *);
23496ae6ea0SThomas Gleixner 				*ip = (str - buf);
23596ae6ea0SThomas Gleixner 			}
23696ae6ea0SThomas Gleixner 			continue;
23796ae6ea0SThomas Gleixner 
23896ae6ea0SThomas Gleixner 		case '%':
23996ae6ea0SThomas Gleixner 			*str++ = '%';
24096ae6ea0SThomas Gleixner 			continue;
24196ae6ea0SThomas Gleixner 
24296ae6ea0SThomas Gleixner 			/* integer number formats - set up the flags and "break" */
24396ae6ea0SThomas Gleixner 		case 'o':
24496ae6ea0SThomas Gleixner 			base = 8;
24596ae6ea0SThomas Gleixner 			break;
24696ae6ea0SThomas Gleixner 
24796ae6ea0SThomas Gleixner 		case 'x':
2489b706aeeSDenys Vlasenko 			flags |= SMALL;
2499b706aeeSDenys Vlasenko 		case 'X':
25096ae6ea0SThomas Gleixner 			base = 16;
25196ae6ea0SThomas Gleixner 			break;
25296ae6ea0SThomas Gleixner 
25396ae6ea0SThomas Gleixner 		case 'd':
25496ae6ea0SThomas Gleixner 		case 'i':
25596ae6ea0SThomas Gleixner 			flags |= SIGN;
25696ae6ea0SThomas Gleixner 		case 'u':
25796ae6ea0SThomas Gleixner 			break;
25896ae6ea0SThomas Gleixner 
25996ae6ea0SThomas Gleixner 		default:
26096ae6ea0SThomas Gleixner 			*str++ = '%';
26196ae6ea0SThomas Gleixner 			if (*fmt)
26296ae6ea0SThomas Gleixner 				*str++ = *fmt;
26396ae6ea0SThomas Gleixner 			else
26496ae6ea0SThomas Gleixner 				--fmt;
26596ae6ea0SThomas Gleixner 			continue;
26696ae6ea0SThomas Gleixner 		}
26796ae6ea0SThomas Gleixner 		if (qualifier == 'l')
26896ae6ea0SThomas Gleixner 			num = va_arg(args, unsigned long);
26996ae6ea0SThomas Gleixner 		else if (qualifier == 'h') {
27096ae6ea0SThomas Gleixner 			num = (unsigned short)va_arg(args, int);
27196ae6ea0SThomas Gleixner 			if (flags & SIGN)
27296ae6ea0SThomas Gleixner 				num = (short)num;
27396ae6ea0SThomas Gleixner 		} else if (flags & SIGN)
27496ae6ea0SThomas Gleixner 			num = va_arg(args, int);
27596ae6ea0SThomas Gleixner 		else
27696ae6ea0SThomas Gleixner 			num = va_arg(args, unsigned int);
27796ae6ea0SThomas Gleixner 		str = number(str, num, base, field_width, precision, flags);
27896ae6ea0SThomas Gleixner 	}
27996ae6ea0SThomas Gleixner 	*str = '\0';
28096ae6ea0SThomas Gleixner 	return str - buf;
28196ae6ea0SThomas Gleixner }
28296ae6ea0SThomas Gleixner 
sprintf(char * buf,const char * fmt,...)28396ae6ea0SThomas Gleixner int sprintf(char *buf, const char *fmt, ...)
28496ae6ea0SThomas Gleixner {
28596ae6ea0SThomas Gleixner 	va_list args;
28696ae6ea0SThomas Gleixner 	int i;
28796ae6ea0SThomas Gleixner 
28896ae6ea0SThomas Gleixner 	va_start(args, fmt);
28996ae6ea0SThomas Gleixner 	i = vsprintf(buf, fmt, args);
29096ae6ea0SThomas Gleixner 	va_end(args);
29196ae6ea0SThomas Gleixner 	return i;
29296ae6ea0SThomas Gleixner }
29396ae6ea0SThomas Gleixner 
printf(const char * fmt,...)29496ae6ea0SThomas Gleixner int printf(const char *fmt, ...)
29596ae6ea0SThomas Gleixner {
29696ae6ea0SThomas Gleixner 	char printf_buf[1024];
29796ae6ea0SThomas Gleixner 	va_list args;
29896ae6ea0SThomas Gleixner 	int printed;
29996ae6ea0SThomas Gleixner 
30096ae6ea0SThomas Gleixner 	va_start(args, fmt);
30196ae6ea0SThomas Gleixner 	printed = vsprintf(printf_buf, fmt, args);
30296ae6ea0SThomas Gleixner 	va_end(args);
30396ae6ea0SThomas Gleixner 
30496ae6ea0SThomas Gleixner 	puts(printf_buf);
30596ae6ea0SThomas Gleixner 
30696ae6ea0SThomas Gleixner 	return printed;
30796ae6ea0SThomas Gleixner }
308