blob: fd2b3d09abc25598c78e88124f40fd16e76a047b [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +02002/*
3 * EFI efi_selftest
4 *
5 * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de>
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +02006 */
7
8#include <efi_selftest.h>
Simon Glass274e0b02020-05-10 11:39:56 -06009#include <net.h>
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +020010#include <vsprintf.h>
11
12struct efi_simple_text_output_protocol *con_out;
Heinrich Schuchardt3dabffd2018-09-08 10:20:10 +020013struct efi_simple_text_input_protocol *con_in;
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +020014
15/*
Heinrich Schuchardt2cd42e82017-10-05 16:36:06 +020016 * 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 */
22static 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/*
Heinrich Schuchardtcc8545c2020-10-03 13:12:03 +020047 * printx() - print hexadecimal number to an u16 string
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +020048 *
Heinrich Schuchardtc4392d92021-01-17 07:30:26 +010049 * @p: value to print
Heinrich Schuchardtcc8545c2020-10-03 13:12:03 +020050 * @prec: minimum number of digits to print
51 * @buf: pointer to buffer address,
52 * on return position of terminating zero word
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +020053 */
Heinrich Schuchardtcc8545c2020-10-03 13:12:03 +020054static void printx(u64 p, int prec, u16 **buf)
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +020055{
56 int i;
57 u16 c;
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +020058 u16 *pos = *buf;
59
Heinrich Schuchardtcc8545c2020-10-03 13:12:03 +020060 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 }
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +020068 }
69 *pos = 0;
70 *buf = pos;
71}
72
Heinrich Schuchardt513bb3d2022-01-16 15:49:17 +010073/**
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 */
80static 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
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +020095/*
96 * Print an unsigned 32bit value as decimal number to an u16 string
97 *
Heinrich Schuchardtfe3ae732018-07-07 23:39:15 +020098 * @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
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200102 */
Heinrich Schuchardtfe3ae732018-07-07 23:39:15 +0200103static void uint2dec(u32 value, int prec, u16 **buf)
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200104{
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;
Heinrich Schuchardtfe3ae732018-07-07 23:39:15 +0200122 if (c || pos != *buf || 10 - i <= prec)
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200123 *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 *
Heinrich Schuchardtfe3ae732018-07-07 23:39:15 +0200138 * @value: value to be printed
139 * @prec: minimum number of digits to display
140 * @buf: pointer to buffer address
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200141 * on return position of terminating zero word
142 */
Heinrich Schuchardtfe3ae732018-07-07 23:39:15 +0200143static void int2dec(s32 value, int prec, u16 **buf)
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200144{
145 u32 u;
146 u16 *pos = *buf;
147
148 if (value < 0) {
149 *pos++ = '-';
150 u = -value;
151 } else {
152 u = value;
153 }
Heinrich Schuchardtfe3ae732018-07-07 23:39:15 +0200154 uint2dec(u, prec, &pos);
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200155 *buf = pos;
156}
157
158/*
Heinrich Schuchardt9137df82018-01-11 08:15:54 +0100159 * Print a colored formatted string to the EFI console
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200160 *
Heinrich Schuchardt9137df82018-01-11 08:15:54 +0100161 * @color color, see constants in efi_api.h, use -1 for no color
162 * @fmt format string
163 * @... optional arguments
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200164 */
Heinrich Schuchardt9137df82018-01-11 08:15:54 +0100165void efi_st_printc(int color, const char *fmt, ...)
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200166{
167 va_list args;
168 u16 buf[160];
169 const char *c;
170 u16 *pos = buf;
171 const char *s;
Heinrich Schuchardt7c7756e2017-12-22 19:21:04 +0100172 u16 *u;
Heinrich Schuchardtfe3ae732018-07-07 23:39:15 +0200173 int prec;
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200174
175 va_start(args, fmt);
176
Heinrich Schuchardt9137df82018-01-11 08:15:54 +0100177 if (color >= 0)
178 con_out->set_attribute(con_out, (unsigned long)color);
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200179 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;
Heinrich Schuchardtfe3ae732018-07-07 23:39:15 +0200203 /* Parse precision */
204 if (*c == '.') {
205 ++c;
206 prec = *c - '0';
207 ++c;
208 } else {
209 prec = 0;
210 }
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200211 switch (*c) {
212 case '\0':
213 --c;
214 break;
215 case 'd':
Heinrich Schuchardtfe3ae732018-07-07 23:39:15 +0200216 int2dec(va_arg(args, s32), prec, &pos);
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200217 break;
218 case 'p':
Heinrich Schuchardt2cd42e82017-10-05 16:36:06 +0200219 ++c;
220 switch (*c) {
Heinrich Schuchardt02efd5d2017-10-18 18:13:13 +0200221 /* MAC address */
Heinrich Schuchardt2cd42e82017-10-05 16:36:06 +0200222 case 'm':
223 mac(va_arg(args, void*), &pos);
224 break;
Heinrich Schuchardt02efd5d2017-10-18 18:13:13 +0200225
226 /* u16 string */
227 case 's':
228 u = va_arg(args, u16*);
Heinrich Schuchardt7c7756e2017-12-22 19:21:04 +0100229 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;
Heinrich Schuchardt02efd5d2017-10-18 18:13:13 +0200236 break;
Heinrich Schuchardt513bb3d2022-01-16 15:49:17 +0100237 case 'U':
238 print_uuid(va_arg(args, void*), &pos);
239 break;
Heinrich Schuchardt2cd42e82017-10-05 16:36:06 +0200240 default:
241 --c;
Heinrich Schuchardtcc8545c2020-10-03 13:12:03 +0200242 printx((uintptr_t)va_arg(args, void *),
243 2 * sizeof(void *), &pos);
244 break;
Heinrich Schuchardt2cd42e82017-10-05 16:36:06 +0200245 }
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200246 break;
247 case 's':
248 s = va_arg(args, const char *);
249 for (; *s; ++s)
250 *pos++ = *s;
251 break;
252 case 'u':
Heinrich Schuchardtfe3ae732018-07-07 23:39:15 +0200253 uint2dec(va_arg(args, u32), prec, &pos);
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200254 break;
Heinrich Schuchardtcc8545c2020-10-03 13:12:03 +0200255 case 'x':
256 printx((u64)va_arg(args, unsigned int),
257 prec, &pos);
258 break;
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200259 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);
Heinrich Schuchardt9137df82018-01-11 08:15:54 +0100270 if (color >= 0)
271 con_out->set_attribute(con_out, EFI_LIGHTGRAY);
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200272}
273
274/*
275 * Reads an Unicode character from the input device.
276 *
Heinrich Schuchardtfbe90212022-01-20 19:48:20 +0100277 * Return: Unicode character
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200278 */
279u16 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}