blob: 0219bd70e05c5cdddd800a31bbab3aac10101a4b [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 Schuchardtcc8545c2020-10-03 13:12:03 +020049 * @pointer: pointer
50 * @prec: minimum number of digits to print
51 * @buf: pointer to buffer address,
52 * on return position of terminating zero word
53 * @size: size of value to be printed in bytes
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +020054 */
Heinrich Schuchardtcc8545c2020-10-03 13:12:03 +020055static void printx(u64 p, int prec, u16 **buf)
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +020056{
57 int i;
58 u16 c;
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +020059 u16 *pos = *buf;
60
Heinrich Schuchardtcc8545c2020-10-03 13:12:03 +020061 for (i = 2 * sizeof(p) - 1; i >= 0; --i) {
62 c = (p >> (4 * i)) & 0x0f;
63 if (c || pos != *buf || !i || i < prec) {
64 c += '0';
65 if (c > '9')
66 c += 'a' - '9' - 1;
67 *pos++ = c;
68 }
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +020069 }
70 *pos = 0;
71 *buf = pos;
72}
73
74/*
75 * Print an unsigned 32bit value as decimal number to an u16 string
76 *
Heinrich Schuchardtfe3ae732018-07-07 23:39:15 +020077 * @value: value to be printed
78 * @prec: minimum number of digits to display
79 * @buf: pointer to buffer address
80 * on return position of terminating zero word
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +020081 */
Heinrich Schuchardtfe3ae732018-07-07 23:39:15 +020082static void uint2dec(u32 value, int prec, u16 **buf)
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +020083{
84 u16 *pos = *buf;
85 int i;
86 u16 c;
87 u64 f;
88
89 /*
90 * Increment by .5 and multiply with
91 * (2 << 60) / 1,000,000,000 = 0x44B82FA0.9B5A52CC
92 * to move the first digit to bit 60-63.
93 */
94 f = 0x225C17D0;
95 f += (0x9B5A52DULL * value) >> 28;
96 f += 0x44B82FA0ULL * value;
97
98 for (i = 0; i < 10; ++i) {
99 /* Write current digit */
100 c = f >> 60;
Heinrich Schuchardtfe3ae732018-07-07 23:39:15 +0200101 if (c || pos != *buf || 10 - i <= prec)
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200102 *pos++ = c + '0';
103 /* Eliminate current digit */
104 f &= 0xfffffffffffffff;
105 /* Get next digit */
106 f *= 0xaULL;
107 }
108 if (pos == *buf)
109 *pos++ = '0';
110 *pos = 0;
111 *buf = pos;
112}
113
114/*
115 * Print a signed 32bit value as decimal number to an u16 string
116 *
Heinrich Schuchardtfe3ae732018-07-07 23:39:15 +0200117 * @value: value to be printed
118 * @prec: minimum number of digits to display
119 * @buf: pointer to buffer address
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200120 * on return position of terminating zero word
121 */
Heinrich Schuchardtfe3ae732018-07-07 23:39:15 +0200122static void int2dec(s32 value, int prec, u16 **buf)
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200123{
124 u32 u;
125 u16 *pos = *buf;
126
127 if (value < 0) {
128 *pos++ = '-';
129 u = -value;
130 } else {
131 u = value;
132 }
Heinrich Schuchardtfe3ae732018-07-07 23:39:15 +0200133 uint2dec(u, prec, &pos);
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200134 *buf = pos;
135}
136
137/*
Heinrich Schuchardt9137df82018-01-11 08:15:54 +0100138 * Print a colored formatted string to the EFI console
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200139 *
Heinrich Schuchardt9137df82018-01-11 08:15:54 +0100140 * @color color, see constants in efi_api.h, use -1 for no color
141 * @fmt format string
142 * @... optional arguments
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200143 */
Heinrich Schuchardt9137df82018-01-11 08:15:54 +0100144void efi_st_printc(int color, const char *fmt, ...)
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200145{
146 va_list args;
147 u16 buf[160];
148 const char *c;
149 u16 *pos = buf;
150 const char *s;
Heinrich Schuchardt7c7756e2017-12-22 19:21:04 +0100151 u16 *u;
Heinrich Schuchardtfe3ae732018-07-07 23:39:15 +0200152 int prec;
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200153
154 va_start(args, fmt);
155
Heinrich Schuchardt9137df82018-01-11 08:15:54 +0100156 if (color >= 0)
157 con_out->set_attribute(con_out, (unsigned long)color);
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200158 c = fmt;
159 for (; *c; ++c) {
160 switch (*c) {
161 case '\\':
162 ++c;
163 switch (*c) {
164 case '\0':
165 --c;
166 break;
167 case 'n':
168 *pos++ = '\n';
169 break;
170 case 'r':
171 *pos++ = '\r';
172 break;
173 case 't':
174 *pos++ = '\t';
175 break;
176 default:
177 *pos++ = *c;
178 }
179 break;
180 case '%':
181 ++c;
Heinrich Schuchardtfe3ae732018-07-07 23:39:15 +0200182 /* Parse precision */
183 if (*c == '.') {
184 ++c;
185 prec = *c - '0';
186 ++c;
187 } else {
188 prec = 0;
189 }
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200190 switch (*c) {
191 case '\0':
192 --c;
193 break;
194 case 'd':
Heinrich Schuchardtfe3ae732018-07-07 23:39:15 +0200195 int2dec(va_arg(args, s32), prec, &pos);
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200196 break;
197 case 'p':
Heinrich Schuchardt2cd42e82017-10-05 16:36:06 +0200198 ++c;
199 switch (*c) {
Heinrich Schuchardt02efd5d2017-10-18 18:13:13 +0200200 /* MAC address */
Heinrich Schuchardt2cd42e82017-10-05 16:36:06 +0200201 case 'm':
202 mac(va_arg(args, void*), &pos);
203 break;
Heinrich Schuchardt02efd5d2017-10-18 18:13:13 +0200204
205 /* u16 string */
206 case 's':
207 u = va_arg(args, u16*);
Heinrich Schuchardt7c7756e2017-12-22 19:21:04 +0100208 if (pos > buf) {
209 *pos = 0;
210 con_out->output_string(con_out,
211 buf);
212 }
213 con_out->output_string(con_out, u);
214 pos = buf;
Heinrich Schuchardt02efd5d2017-10-18 18:13:13 +0200215 break;
Heinrich Schuchardt2cd42e82017-10-05 16:36:06 +0200216 default:
217 --c;
Heinrich Schuchardtcc8545c2020-10-03 13:12:03 +0200218 printx((uintptr_t)va_arg(args, void *),
219 2 * sizeof(void *), &pos);
220 break;
Heinrich Schuchardt2cd42e82017-10-05 16:36:06 +0200221 }
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200222 break;
223 case 's':
224 s = va_arg(args, const char *);
225 for (; *s; ++s)
226 *pos++ = *s;
227 break;
228 case 'u':
Heinrich Schuchardtfe3ae732018-07-07 23:39:15 +0200229 uint2dec(va_arg(args, u32), prec, &pos);
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200230 break;
Heinrich Schuchardtcc8545c2020-10-03 13:12:03 +0200231 case 'x':
232 printx((u64)va_arg(args, unsigned int),
233 prec, &pos);
234 break;
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200235 default:
236 break;
237 }
238 break;
239 default:
240 *pos++ = *c;
241 }
242 }
243 va_end(args);
244 *pos = 0;
245 con_out->output_string(con_out, buf);
Heinrich Schuchardt9137df82018-01-11 08:15:54 +0100246 if (color >= 0)
247 con_out->set_attribute(con_out, EFI_LIGHTGRAY);
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200248}
249
250/*
251 * Reads an Unicode character from the input device.
252 *
253 * @return: Unicode character
254 */
255u16 efi_st_get_key(void)
256{
257 struct efi_input_key input_key;
258 efi_status_t ret;
259
260 /* Wait for next key */
261 do {
262 ret = con_in->read_key_stroke(con_in, &input_key);
263 } while (ret == EFI_NOT_READY);
264 return input_key.unicode_char;
265}