1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * EFI efi_selftest
4 *
5 * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de>
6 */
7
8 #include <efi_selftest.h>
9 #include <net.h>
10 #include <vsprintf.h>
11
12 struct efi_simple_text_output_protocol *con_out;
13 struct efi_simple_text_input_protocol *con_in;
14
15 /*
16 * Print a MAC address to an u16 string
17 *
18 * @pointer: mac address
19 * @buf: pointer to buffer address
20 * on return position of terminating zero word
21 */
mac(void * pointer,u16 ** buf)22 static void mac(void *pointer, u16 **buf)
23 {
24 int i, j;
25 u16 c;
26 u8 *p = (u8 *)pointer;
27 u8 byte;
28 u16 *pos = *buf;
29
30 for (i = 0; i < ARP_HLEN; ++i) {
31 if (i)
32 *pos++ = ':';
33 byte = p[i];
34 for (j = 4; j >= 0; j -= 4) {
35 c = (byte >> j) & 0x0f;
36 c += '0';
37 if (c > '9')
38 c += 'a' - '9' - 1;
39 *pos++ = c;
40 }
41 }
42 *pos = 0;
43 *buf = pos;
44 }
45
46 /*
47 * printx() - print hexadecimal number to an u16 string
48 *
49 * @p: value to print
50 * @prec: minimum number of digits to print
51 * @buf: pointer to buffer address,
52 * on return position of terminating zero word
53 */
printx(u64 p,int prec,u16 ** buf)54 static void printx(u64 p, int prec, u16 **buf)
55 {
56 int i;
57 u16 c;
58 u16 *pos = *buf;
59
60 for (i = 2 * sizeof(p) - 1; i >= 0; --i) {
61 c = (p >> (4 * i)) & 0x0f;
62 if (c || pos != *buf || !i || i < prec) {
63 c += '0';
64 if (c > '9')
65 c += 'a' - '9' - 1;
66 *pos++ = c;
67 }
68 }
69 *pos = 0;
70 *buf = pos;
71 }
72
73 /**
74 * print_guid() - print GUID to an u16 string
75 *
76 * @p: GUID to print
77 * @buf: pointer to buffer address,
78 * on return position of terminating zero word
79 */
print_uuid(u8 * p,u16 ** buf)80 static void print_uuid(u8 *p, u16 **buf)
81 {
82 int i;
83 const u8 seq[] = {
84 3, 2, 1, 0, '-', 5, 4, '-', 7, 6, '-',
85 8, 9, 10, 11, 12, 13, 14, 15 };
86
87 for (i = 0; i < sizeof(seq); ++i) {
88 if (seq[i] == '-')
89 *(*buf)++ = u'-';
90 else
91 printx(p[seq[i]], 2, buf);
92 }
93 }
94
95 /*
96 * Print an unsigned 32bit value as decimal number to an u16 string
97 *
98 * @value: value to be printed
99 * @prec: minimum number of digits to display
100 * @buf: pointer to buffer address
101 * on return position of terminating zero word
102 */
uint2dec(u32 value,int prec,u16 ** buf)103 static void uint2dec(u32 value, int prec, u16 **buf)
104 {
105 u16 *pos = *buf;
106 int i;
107 u16 c;
108 u64 f;
109
110 /*
111 * Increment by .5 and multiply with
112 * (2 << 60) / 1,000,000,000 = 0x44B82FA0.9B5A52CC
113 * to move the first digit to bit 60-63.
114 */
115 f = 0x225C17D0;
116 f += (0x9B5A52DULL * value) >> 28;
117 f += 0x44B82FA0ULL * value;
118
119 for (i = 0; i < 10; ++i) {
120 /* Write current digit */
121 c = f >> 60;
122 if (c || pos != *buf || 10 - i <= prec)
123 *pos++ = c + '0';
124 /* Eliminate current digit */
125 f &= 0xfffffffffffffff;
126 /* Get next digit */
127 f *= 0xaULL;
128 }
129 if (pos == *buf)
130 *pos++ = '0';
131 *pos = 0;
132 *buf = pos;
133 }
134
135 /*
136 * Print a signed 32bit value as decimal number to an u16 string
137 *
138 * @value: value to be printed
139 * @prec: minimum number of digits to display
140 * @buf: pointer to buffer address
141 * on return position of terminating zero word
142 */
int2dec(s32 value,int prec,u16 ** buf)143 static void int2dec(s32 value, int prec, u16 **buf)
144 {
145 u32 u;
146 u16 *pos = *buf;
147
148 if (value < 0) {
149 *pos++ = '-';
150 u = -value;
151 } else {
152 u = value;
153 }
154 uint2dec(u, prec, &pos);
155 *buf = pos;
156 }
157
158 /*
159 * Print a colored formatted string to the EFI console
160 *
161 * @color color, see constants in efi_api.h, use -1 for no color
162 * @fmt format string
163 * @... optional arguments
164 */
efi_st_printc(int color,const char * fmt,...)165 void efi_st_printc(int color, const char *fmt, ...)
166 {
167 va_list args;
168 u16 buf[160];
169 const char *c;
170 u16 *pos = buf;
171 const char *s;
172 u16 *u;
173 int prec;
174
175 va_start(args, fmt);
176
177 if (color >= 0)
178 con_out->set_attribute(con_out, (unsigned long)color);
179 c = fmt;
180 for (; *c; ++c) {
181 switch (*c) {
182 case '\\':
183 ++c;
184 switch (*c) {
185 case '\0':
186 --c;
187 break;
188 case 'n':
189 *pos++ = '\n';
190 break;
191 case 'r':
192 *pos++ = '\r';
193 break;
194 case 't':
195 *pos++ = '\t';
196 break;
197 default:
198 *pos++ = *c;
199 }
200 break;
201 case '%':
202 ++c;
203 /* Parse precision */
204 if (*c == '.') {
205 ++c;
206 prec = *c - '0';
207 ++c;
208 } else {
209 prec = 0;
210 }
211 switch (*c) {
212 case '\0':
213 --c;
214 break;
215 case 'd':
216 int2dec(va_arg(args, s32), prec, &pos);
217 break;
218 case 'p':
219 ++c;
220 switch (*c) {
221 /* MAC address */
222 case 'm':
223 mac(va_arg(args, void*), &pos);
224 break;
225
226 /* u16 string */
227 case 's':
228 u = va_arg(args, u16*);
229 if (pos > buf) {
230 *pos = 0;
231 con_out->output_string(con_out,
232 buf);
233 }
234 con_out->output_string(con_out, u);
235 pos = buf;
236 break;
237 case 'U':
238 print_uuid(va_arg(args, void*), &pos);
239 break;
240 default:
241 --c;
242 printx((uintptr_t)va_arg(args, void *),
243 2 * sizeof(void *), &pos);
244 break;
245 }
246 break;
247 case 's':
248 s = va_arg(args, const char *);
249 for (; *s; ++s)
250 *pos++ = *s;
251 break;
252 case 'u':
253 uint2dec(va_arg(args, u32), prec, &pos);
254 break;
255 case 'x':
256 printx((u64)va_arg(args, unsigned int),
257 prec, &pos);
258 break;
259 default:
260 break;
261 }
262 break;
263 default:
264 *pos++ = *c;
265 }
266 }
267 va_end(args);
268 *pos = 0;
269 con_out->output_string(con_out, buf);
270 if (color >= 0)
271 con_out->set_attribute(con_out, EFI_LIGHTGRAY);
272 }
273
274 /*
275 * Reads an Unicode character from the input device.
276 *
277 * Return: Unicode character
278 */
efi_st_get_key(void)279 u16 efi_st_get_key(void)
280 {
281 struct efi_input_key input_key;
282 efi_status_t ret;
283
284 /* Wait for next key */
285 do {
286 ret = con_in->read_key_stroke(con_in, &input_key);
287 } while (ret == EFI_NOT_READY);
288 return input_key.unicode_char;
289 }
290