blob: 13f3ee6bc19fe59c553aa3a5bdff92d77797404b [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 Schuchardtd33ae3e2017-09-15 10:06:11 +020047 * Print a pointer to an u16 string
48 *
49 * @pointer: pointer
50 * @buf: pointer to buffer address
51 * on return position of terminating zero word
52 */
53static void pointer(void *pointer, u16 **buf)
54{
55 int i;
56 u16 c;
57 uintptr_t p = (uintptr_t)pointer;
58 u16 *pos = *buf;
59
60 for (i = 8 * sizeof(p) - 4; i >= 0; i -= 4) {
61 c = (p >> i) & 0x0f;
62 c += '0';
63 if (c > '9')
64 c += 'a' - '9' - 1;
65 *pos++ = c;
66 }
67 *pos = 0;
68 *buf = pos;
69}
70
71/*
72 * Print an unsigned 32bit value as decimal number to an u16 string
73 *
Heinrich Schuchardtfe3ae732018-07-07 23:39:15 +020074 * @value: value to be printed
75 * @prec: minimum number of digits to display
76 * @buf: pointer to buffer address
77 * on return position of terminating zero word
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +020078 */
Heinrich Schuchardtfe3ae732018-07-07 23:39:15 +020079static void uint2dec(u32 value, int prec, u16 **buf)
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +020080{
81 u16 *pos = *buf;
82 int i;
83 u16 c;
84 u64 f;
85
86 /*
87 * Increment by .5 and multiply with
88 * (2 << 60) / 1,000,000,000 = 0x44B82FA0.9B5A52CC
89 * to move the first digit to bit 60-63.
90 */
91 f = 0x225C17D0;
92 f += (0x9B5A52DULL * value) >> 28;
93 f += 0x44B82FA0ULL * value;
94
95 for (i = 0; i < 10; ++i) {
96 /* Write current digit */
97 c = f >> 60;
Heinrich Schuchardtfe3ae732018-07-07 23:39:15 +020098 if (c || pos != *buf || 10 - i <= prec)
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +020099 *pos++ = c + '0';
100 /* Eliminate current digit */
101 f &= 0xfffffffffffffff;
102 /* Get next digit */
103 f *= 0xaULL;
104 }
105 if (pos == *buf)
106 *pos++ = '0';
107 *pos = 0;
108 *buf = pos;
109}
110
111/*
112 * Print a signed 32bit value as decimal number to an u16 string
113 *
Heinrich Schuchardtfe3ae732018-07-07 23:39:15 +0200114 * @value: value to be printed
115 * @prec: minimum number of digits to display
116 * @buf: pointer to buffer address
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200117 * on return position of terminating zero word
118 */
Heinrich Schuchardtfe3ae732018-07-07 23:39:15 +0200119static void int2dec(s32 value, int prec, u16 **buf)
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200120{
121 u32 u;
122 u16 *pos = *buf;
123
124 if (value < 0) {
125 *pos++ = '-';
126 u = -value;
127 } else {
128 u = value;
129 }
Heinrich Schuchardtfe3ae732018-07-07 23:39:15 +0200130 uint2dec(u, prec, &pos);
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200131 *buf = pos;
132}
133
134/*
Heinrich Schuchardt9137df82018-01-11 08:15:54 +0100135 * Print a colored formatted string to the EFI console
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200136 *
Heinrich Schuchardt9137df82018-01-11 08:15:54 +0100137 * @color color, see constants in efi_api.h, use -1 for no color
138 * @fmt format string
139 * @... optional arguments
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200140 */
Heinrich Schuchardt9137df82018-01-11 08:15:54 +0100141void efi_st_printc(int color, const char *fmt, ...)
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200142{
143 va_list args;
144 u16 buf[160];
145 const char *c;
146 u16 *pos = buf;
147 const char *s;
Heinrich Schuchardt7c7756e2017-12-22 19:21:04 +0100148 u16 *u;
Heinrich Schuchardtfe3ae732018-07-07 23:39:15 +0200149 int prec;
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200150
151 va_start(args, fmt);
152
Heinrich Schuchardt9137df82018-01-11 08:15:54 +0100153 if (color >= 0)
154 con_out->set_attribute(con_out, (unsigned long)color);
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200155 c = fmt;
156 for (; *c; ++c) {
157 switch (*c) {
158 case '\\':
159 ++c;
160 switch (*c) {
161 case '\0':
162 --c;
163 break;
164 case 'n':
165 *pos++ = '\n';
166 break;
167 case 'r':
168 *pos++ = '\r';
169 break;
170 case 't':
171 *pos++ = '\t';
172 break;
173 default:
174 *pos++ = *c;
175 }
176 break;
177 case '%':
178 ++c;
Heinrich Schuchardtfe3ae732018-07-07 23:39:15 +0200179 /* Parse precision */
180 if (*c == '.') {
181 ++c;
182 prec = *c - '0';
183 ++c;
184 } else {
185 prec = 0;
186 }
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200187 switch (*c) {
188 case '\0':
189 --c;
190 break;
191 case 'd':
Heinrich Schuchardtfe3ae732018-07-07 23:39:15 +0200192 int2dec(va_arg(args, s32), prec, &pos);
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200193 break;
194 case 'p':
Heinrich Schuchardt2cd42e82017-10-05 16:36:06 +0200195 ++c;
196 switch (*c) {
Heinrich Schuchardt02efd5d2017-10-18 18:13:13 +0200197 /* MAC address */
Heinrich Schuchardt2cd42e82017-10-05 16:36:06 +0200198 case 'm':
199 mac(va_arg(args, void*), &pos);
200 break;
Heinrich Schuchardt02efd5d2017-10-18 18:13:13 +0200201
202 /* u16 string */
203 case 's':
204 u = va_arg(args, u16*);
Heinrich Schuchardt7c7756e2017-12-22 19:21:04 +0100205 if (pos > buf) {
206 *pos = 0;
207 con_out->output_string(con_out,
208 buf);
209 }
210 con_out->output_string(con_out, u);
211 pos = buf;
Heinrich Schuchardt02efd5d2017-10-18 18:13:13 +0200212 break;
Heinrich Schuchardt2cd42e82017-10-05 16:36:06 +0200213 default:
214 --c;
215 pointer(va_arg(args, void*), &pos);
216 }
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200217 break;
218 case 's':
219 s = va_arg(args, const char *);
220 for (; *s; ++s)
221 *pos++ = *s;
222 break;
223 case 'u':
Heinrich Schuchardtfe3ae732018-07-07 23:39:15 +0200224 uint2dec(va_arg(args, u32), prec, &pos);
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200225 break;
226 default:
227 break;
228 }
229 break;
230 default:
231 *pos++ = *c;
232 }
233 }
234 va_end(args);
235 *pos = 0;
236 con_out->output_string(con_out, buf);
Heinrich Schuchardt9137df82018-01-11 08:15:54 +0100237 if (color >= 0)
238 con_out->set_attribute(con_out, EFI_LIGHTGRAY);
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200239}
240
241/*
242 * Reads an Unicode character from the input device.
243 *
244 * @return: Unicode character
245 */
246u16 efi_st_get_key(void)
247{
248 struct efi_input_key input_key;
249 efi_status_t ret;
250
251 /* Wait for next key */
252 do {
253 ret = con_in->read_key_stroke(con_in, &input_key);
254 } while (ret == EFI_NOT_READY);
255 return input_key.unicode_char;
256}