Skip to content

Commit 2c7d1e3

Browse files
nivedita76ardbiesheuvel
authored andcommitted
efi/libstub: Add a basic printf implementation
Copy vsprintf from arch/x86/boot/printf.c to get a simple printf implementation. Signed-off-by: Arvind Sankar <[email protected]> Link: https://lore.kernel.org/r/[email protected] [ardb: add some missing braces in if...else clauses] Signed-off-by: Ard Biesheuvel <[email protected]>
1 parent fd0528a commit 2c7d1e3

File tree

4 files changed

+320
-1
lines changed

4 files changed

+320
-1
lines changed

drivers/firmware/efi/libstub/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ KCOV_INSTRUMENT := n
4444
lib-y := efi-stub-helper.o gop.o secureboot.o tpm.o \
4545
file.o mem.o random.o randomalloc.o pci.o \
4646
skip_spaces.o lib-cmdline.o lib-ctype.o \
47-
alignedmem.o relocate.o
47+
alignedmem.o relocate.o vsprintf.o
4848

4949
# include the stub's generic dependencies from lib/ when building for ARM/arm64
5050
efi-deps-y := fdt_rw.c fdt_ro.c fdt_wip.c fdt.c fdt_empty_tree.c fdt_sw.c

drivers/firmware/efi/libstub/efi-stub-helper.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
* Copyright 2011 Intel Corporation; author Matt Fleming
88
*/
99

10+
#include <stdarg.h>
11+
1012
#include <linux/efi.h>
1113
#include <linux/kernel.h>
1214
#include <asm/efi.h>
@@ -51,6 +53,21 @@ void efi_puts(const char *str)
5153
}
5254
}
5355

56+
int efi_printk(const char *fmt, ...)
57+
{
58+
char printf_buf[256];
59+
va_list args;
60+
int printed;
61+
62+
va_start(args, fmt);
63+
printed = vsprintf(printf_buf, fmt, args);
64+
va_end(args);
65+
66+
efi_puts(printf_buf);
67+
68+
return printed;
69+
}
70+
5471
/*
5572
* Parse the ASCII string 'cmdline' for EFI options, denoted by the efi=
5673
* option, e.g. efi=nochunk.

drivers/firmware/efi/libstub/efistub.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#ifndef _DRIVERS_FIRMWARE_EFI_EFISTUB_H
44
#define _DRIVERS_FIRMWARE_EFI_EFISTUB_H
55

6+
#include <linux/compiler.h>
67
#include <linux/efi.h>
78
#include <linux/kernel.h>
89
#include <linux/types.h>
@@ -632,6 +633,8 @@ void *get_efi_config_table(efi_guid_t guid);
632633
void efi_char16_puts(efi_char16_t *);
633634
void efi_puts(const char *str);
634635

636+
__printf(1, 2) int efi_printk(char const *fmt, ...);
637+
635638
void efi_free(unsigned long size, unsigned long addr);
636639

637640
char *efi_convert_cmdline(efi_loaded_image_t *image, int *cmd_line_len,
Lines changed: 299 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,299 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
/* -*- linux-c -*- ------------------------------------------------------- *
3+
*
4+
* Copyright (C) 1991, 1992 Linus Torvalds
5+
* Copyright 2007 rPath, Inc. - All Rights Reserved
6+
*
7+
* ----------------------------------------------------------------------- */
8+
9+
/*
10+
* Oh, it's a waste of space, but oh-so-yummy for debugging. This
11+
* version of printf() does not include 64-bit support. "Live with
12+
* it."
13+
*
14+
*/
15+
16+
#include <stdarg.h>
17+
18+
#include <linux/compiler.h>
19+
#include <linux/ctype.h>
20+
#include <linux/string.h>
21+
22+
static int skip_atoi(const char **s)
23+
{
24+
int i = 0;
25+
26+
while (isdigit(**s))
27+
i = i * 10 + *((*s)++) - '0';
28+
return i;
29+
}
30+
31+
#define ZEROPAD 1 /* pad with zero */
32+
#define SIGN 2 /* unsigned/signed long */
33+
#define PLUS 4 /* show plus */
34+
#define SPACE 8 /* space if plus */
35+
#define LEFT 16 /* left justified */
36+
#define SMALL 32 /* Must be 32 == 0x20 */
37+
#define SPECIAL 64 /* 0x */
38+
39+
#define __do_div(n, base) ({ \
40+
int __res; \
41+
__res = ((unsigned long) n) % (unsigned) base; \
42+
n = ((unsigned long) n) / (unsigned) base; \
43+
__res; })
44+
45+
static char *number(char *str, long num, int base, int size, int precision,
46+
int type)
47+
{
48+
/* we are called with base 8, 10 or 16, only, thus don't need "G..." */
49+
static const char digits[16] = "0123456789ABCDEF"; /* "GHIJKLMNOPQRSTUVWXYZ"; */
50+
51+
char tmp[66];
52+
char c, sign, locase;
53+
int i;
54+
55+
/* locase = 0 or 0x20. ORing digits or letters with 'locase'
56+
* produces same digits or (maybe lowercased) letters */
57+
locase = (type & SMALL);
58+
if (type & LEFT)
59+
type &= ~ZEROPAD;
60+
if (base < 2 || base > 16)
61+
return NULL;
62+
c = (type & ZEROPAD) ? '0' : ' ';
63+
sign = 0;
64+
if (type & SIGN) {
65+
if (num < 0) {
66+
sign = '-';
67+
num = -num;
68+
size--;
69+
} else if (type & PLUS) {
70+
sign = '+';
71+
size--;
72+
} else if (type & SPACE) {
73+
sign = ' ';
74+
size--;
75+
}
76+
}
77+
if (type & SPECIAL) {
78+
if (base == 16)
79+
size -= 2;
80+
else if (base == 8)
81+
size--;
82+
}
83+
i = 0;
84+
if (num == 0)
85+
tmp[i++] = '0';
86+
else
87+
while (num != 0)
88+
tmp[i++] = (digits[__do_div(num, base)] | locase);
89+
if (i > precision)
90+
precision = i;
91+
size -= precision;
92+
if (!(type & (ZEROPAD + LEFT)))
93+
while (size-- > 0)
94+
*str++ = ' ';
95+
if (sign)
96+
*str++ = sign;
97+
if (type & SPECIAL) {
98+
if (base == 8) {
99+
*str++ = '0';
100+
} else if (base == 16) {
101+
*str++ = '0';
102+
*str++ = ('X' | locase);
103+
}
104+
}
105+
if (!(type & LEFT))
106+
while (size-- > 0)
107+
*str++ = c;
108+
while (i < precision--)
109+
*str++ = '0';
110+
while (i-- > 0)
111+
*str++ = tmp[i];
112+
while (size-- > 0)
113+
*str++ = ' ';
114+
return str;
115+
}
116+
117+
int vsprintf(char *buf, const char *fmt, va_list args)
118+
{
119+
int len;
120+
unsigned long num;
121+
int i, base;
122+
char *str;
123+
const char *s;
124+
125+
int flags; /* flags to number() */
126+
127+
int field_width; /* width of output field */
128+
int precision; /* min. # of digits for integers; max
129+
number of chars for from string */
130+
int qualifier; /* 'h', 'l', or 'L' for integer fields */
131+
132+
for (str = buf; *fmt; ++fmt) {
133+
if (*fmt != '%') {
134+
*str++ = *fmt;
135+
continue;
136+
}
137+
138+
/* process flags */
139+
flags = 0;
140+
repeat:
141+
++fmt; /* this also skips first '%' */
142+
switch (*fmt) {
143+
case '-':
144+
flags |= LEFT;
145+
goto repeat;
146+
case '+':
147+
flags |= PLUS;
148+
goto repeat;
149+
case ' ':
150+
flags |= SPACE;
151+
goto repeat;
152+
case '#':
153+
flags |= SPECIAL;
154+
goto repeat;
155+
case '0':
156+
flags |= ZEROPAD;
157+
goto repeat;
158+
}
159+
160+
/* get field width */
161+
field_width = -1;
162+
if (isdigit(*fmt)) {
163+
field_width = skip_atoi(&fmt);
164+
} else if (*fmt == '*') {
165+
++fmt;
166+
/* it's the next argument */
167+
field_width = va_arg(args, int);
168+
if (field_width < 0) {
169+
field_width = -field_width;
170+
flags |= LEFT;
171+
}
172+
}
173+
174+
/* get the precision */
175+
precision = -1;
176+
if (*fmt == '.') {
177+
++fmt;
178+
if (isdigit(*fmt)) {
179+
precision = skip_atoi(&fmt);
180+
} else if (*fmt == '*') {
181+
++fmt;
182+
/* it's the next argument */
183+
precision = va_arg(args, int);
184+
}
185+
if (precision < 0)
186+
precision = 0;
187+
}
188+
189+
/* get the conversion qualifier */
190+
qualifier = -1;
191+
if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') {
192+
qualifier = *fmt;
193+
++fmt;
194+
}
195+
196+
/* default base */
197+
base = 10;
198+
199+
switch (*fmt) {
200+
case 'c':
201+
if (!(flags & LEFT))
202+
while (--field_width > 0)
203+
*str++ = ' ';
204+
*str++ = (unsigned char)va_arg(args, int);
205+
while (--field_width > 0)
206+
*str++ = ' ';
207+
continue;
208+
209+
case 's':
210+
s = va_arg(args, char *);
211+
len = strnlen(s, precision);
212+
213+
if (!(flags & LEFT))
214+
while (len < field_width--)
215+
*str++ = ' ';
216+
for (i = 0; i < len; ++i)
217+
*str++ = *s++;
218+
while (len < field_width--)
219+
*str++ = ' ';
220+
continue;
221+
222+
case 'p':
223+
if (field_width == -1) {
224+
field_width = 2 * sizeof(void *);
225+
flags |= ZEROPAD;
226+
}
227+
str = number(str,
228+
(unsigned long)va_arg(args, void *), 16,
229+
field_width, precision, flags);
230+
continue;
231+
232+
case 'n':
233+
if (qualifier == 'l') {
234+
long *ip = va_arg(args, long *);
235+
*ip = (str - buf);
236+
} else {
237+
int *ip = va_arg(args, int *);
238+
*ip = (str - buf);
239+
}
240+
continue;
241+
242+
case '%':
243+
*str++ = '%';
244+
continue;
245+
246+
/* integer number formats - set up the flags and "break" */
247+
case 'o':
248+
base = 8;
249+
break;
250+
251+
case 'x':
252+
flags |= SMALL;
253+
fallthrough;
254+
case 'X':
255+
base = 16;
256+
break;
257+
258+
case 'd':
259+
case 'i':
260+
flags |= SIGN;
261+
fallthrough;
262+
case 'u':
263+
break;
264+
265+
default:
266+
*str++ = '%';
267+
if (*fmt)
268+
*str++ = *fmt;
269+
else
270+
--fmt;
271+
continue;
272+
}
273+
if (qualifier == 'l') {
274+
num = va_arg(args, unsigned long);
275+
} else if (qualifier == 'h') {
276+
num = (unsigned short)va_arg(args, int);
277+
if (flags & SIGN)
278+
num = (short)num;
279+
} else if (flags & SIGN) {
280+
num = va_arg(args, int);
281+
} else {
282+
num = va_arg(args, unsigned int);
283+
}
284+
str = number(str, num, base, field_width, precision, flags);
285+
}
286+
*str = '\0';
287+
return str - buf;
288+
}
289+
290+
int sprintf(char *buf, const char *fmt, ...)
291+
{
292+
va_list args;
293+
int i;
294+
295+
va_start(args, fmt);
296+
i = vsprintf(buf, fmt, args);
297+
va_end(args);
298+
return i;
299+
}

0 commit comments

Comments
 (0)