blob: ffd88a1e26d1aef244c4a552c4cb5aa21fe378ba [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
73/*
74 * Print an unsigned 32bit value as decimal number to an u16 string
75 *
Heinrich Schuchardtfe3ae732018-07-07 23:39:15 +020076 * @value: value to be printed
77 * @prec: minimum number of digits to display
78 * @buf: pointer to buffer address
79 * on return position of terminating zero word
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +020080 */
Heinrich Schuchardtfe3ae732018-07-07 23:39:15 +020081static void uint2dec(u32 value, int prec, u16 **buf)
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +020082{
83 u16 *pos = *buf;
84 int i;
85 u16 c;
86 u64 f;
87
88 /*
89 * Increment by .5 and multiply with
90 * (2 << 60) / 1,000,000,000 = 0x44B82FA0.9B5A52CC
91 * to move the first digit to bit 60-63.
92 */
93 f = 0x225C17D0;
94 f += (0x9B5A52DULL * value) >> 28;
95 f += 0x44B82FA0ULL * value;
96
97 for (i = 0; i < 10; ++i) {
98 /* Write current digit */
99 c = f >> 60;
Heinrich Schuchardtfe3ae732018-07-07 23:39:15 +0200100 if (c || pos != *buf || 10 - i <= prec)
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200101 *pos++ = c + '0';
102 /* Eliminate current digit */
103 f &= 0xfffffffffffffff;
104 /* Get next digit */
105 f *= 0xaULL;
106 }
107 if (pos == *buf)
108 *pos++ = '0';
109 *pos = 0;
110 *buf = pos;
111}
112
113/*
114 * Print a signed 32bit value as decimal number to an u16 string
115 *
Heinrich Schuchardtfe3ae732018-07-07 23:39:15 +0200116 * @value: value to be printed
117 * @prec: minimum number of digits to display
118 * @buf: pointer to buffer address
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200119 * on return position of terminating zero word
120 */
Heinrich Schuchardtfe3ae732018-07-07 23:39:15 +0200121static void int2dec(s32 value, int prec, u16 **buf)
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200122{
123 u32 u;
124 u16 *pos = *buf;
125
126 if (value < 0) {
127 *pos++ = '-';
128 u = -value;
129 } else {
130 u = value;
131 }
Heinrich Schuchardtfe3ae732018-07-07 23:39:15 +0200132 uint2dec(u, prec, &pos);
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200133 *buf = pos;
134}
135
136/*
Heinrich Schuchardt9137df82018-01-11 08:15:54 +0100137 * Print a colored formatted string to the EFI console
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200138 *
Heinrich Schuchardt9137df82018-01-11 08:15:54 +0100139 * @color color, see constants in efi_api.h, use -1 for no color
140 * @fmt format string
141 * @... optional arguments
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200142 */
Heinrich Schuchardt9137df82018-01-11 08:15:54 +0100143void efi_st_printc(int color, const char *fmt, ...)
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200144{
145 va_list args;
146 u16 buf[160];
147 const char *c;
148 u16 *pos = buf;
149 const char *s;
Heinrich Schuchardt7c7756e2017-12-22 19:21:04 +0100150 u16 *u;
Heinrich Schuchardtfe3ae732018-07-07 23:39:15 +0200151 int prec;
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200152
153 va_start(args, fmt);
154
Heinrich Schuchardt9137df82018-01-11 08:15:54 +0100155 if (color >= 0)
156 con_out->set_attribute(con_out, (unsigned long)color);
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200157 c = fmt;
158 for (; *c; ++c) {
159 switch (*c) {
160 case '\\':
161 ++c;
162 switch (*c) {
163 case '\0':
164 --c;
165 break;
166 case 'n':
167 *pos++ = '\n';
168 break;
169 case 'r':
170 *pos++ = '\r';
171 break;
172 case 't':
173 *pos++ = '\t';
174 break;
175 default:
176 *pos++ = *c;
177 }
178 break;
179 case '%':
180 ++c;
Heinrich Schuchardtfe3ae732018-07-07 23:39:15 +0200181 /* Parse precision */
182 if (*c == '.') {
183 ++c;
184 prec = *c - '0';
185 ++c;
186 } else {
187 prec = 0;
188 }
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200189 switch (*c) {
190 case '\0':
191 --c;
192 break;
193 case 'd':
Heinrich Schuchardtfe3ae732018-07-07 23:39:15 +0200194 int2dec(va_arg(args, s32), prec, &pos);
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200195 break;
196 case 'p':
Heinrich Schuchardt2cd42e82017-10-05 16:36:06 +0200197 ++c;
198 switch (*c) {
Heinrich Schuchardt02efd5d2017-10-18 18:13:13 +0200199 /* MAC address */
Heinrich Schuchardt2cd42e82017-10-05 16:36:06 +0200200 case 'm':
201 mac(va_arg(args, void*), &pos);
202 break;
Heinrich Schuchardt02efd5d2017-10-18 18:13:13 +0200203
204 /* u16 string */
205 case 's':
206 u = va_arg(args, u16*);
Heinrich Schuchardt7c7756e2017-12-22 19:21:04 +0100207 if (pos > buf) {
208 *pos = 0;
209 con_out->output_string(con_out,
210 buf);
211 }
212 con_out->output_string(con_out, u);
213 pos = buf;
Heinrich Schuchardt02efd5d2017-10-18 18:13:13 +0200214 break;
Heinrich Schuchardt2cd42e82017-10-05 16:36:06 +0200215 default:
216 --c;
Heinrich Schuchardtcc8545c2020-10-03 13:12:03 +0200217 printx((uintptr_t)va_arg(args, void *),
218 2 * sizeof(void *), &pos);
219 break;
Heinrich Schuchardt2cd42e82017-10-05 16:36:06 +0200220 }
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200221 break;
222 case 's':
223 s = va_arg(args, const char *);
224 for (; *s; ++s)
225 *pos++ = *s;
226 break;
227 case 'u':
Heinrich Schuchardtfe3ae732018-07-07 23:39:15 +0200228 uint2dec(va_arg(args, u32), prec, &pos);
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200229 break;
Heinrich Schuchardtcc8545c2020-10-03 13:12:03 +0200230 case 'x':
231 printx((u64)va_arg(args, unsigned int),
232 prec, &pos);
233 break;
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200234 default:
235 break;
236 }
237 break;
238 default:
239 *pos++ = *c;
240 }
241 }
242 va_end(args);
243 *pos = 0;
244 con_out->output_string(con_out, buf);
Heinrich Schuchardt9137df82018-01-11 08:15:54 +0100245 if (color >= 0)
246 con_out->set_attribute(con_out, EFI_LIGHTGRAY);
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200247}
248
249/*
250 * Reads an Unicode character from the input device.
251 *
252 * @return: Unicode character
253 */
254u16 efi_st_get_key(void)
255{
256 struct efi_input_key input_key;
257 efi_status_t ret;
258
259 /* Wait for next key */
260 do {
261 ret = con_in->read_key_stroke(con_in, &input_key);
262 } while (ret == EFI_NOT_READY);
263 return input_key.unicode_char;
264}