blob: 42f51b652036ee31037226bc62f53f9e87515dfc [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>
9#include <vsprintf.h>
10
11struct efi_simple_text_output_protocol *con_out;
Heinrich Schuchardt3dabffd2018-09-08 10:20:10 +020012struct efi_simple_text_input_protocol *con_in;
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +020013
14/*
Heinrich Schuchardt2cd42e82017-10-05 16:36:06 +020015 * Print a MAC address to an u16 string
16 *
17 * @pointer: mac address
18 * @buf: pointer to buffer address
19 * on return position of terminating zero word
20 */
21static void mac(void *pointer, u16 **buf)
22{
23 int i, j;
24 u16 c;
25 u8 *p = (u8 *)pointer;
26 u8 byte;
27 u16 *pos = *buf;
28
29 for (i = 0; i < ARP_HLEN; ++i) {
30 if (i)
31 *pos++ = ':';
32 byte = p[i];
33 for (j = 4; j >= 0; j -= 4) {
34 c = (byte >> j) & 0x0f;
35 c += '0';
36 if (c > '9')
37 c += 'a' - '9' - 1;
38 *pos++ = c;
39 }
40 }
41 *pos = 0;
42 *buf = pos;
43}
44
45/*
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +020046 * Print a pointer to an u16 string
47 *
48 * @pointer: pointer
49 * @buf: pointer to buffer address
50 * on return position of terminating zero word
51 */
52static void pointer(void *pointer, u16 **buf)
53{
54 int i;
55 u16 c;
56 uintptr_t p = (uintptr_t)pointer;
57 u16 *pos = *buf;
58
59 for (i = 8 * sizeof(p) - 4; i >= 0; i -= 4) {
60 c = (p >> i) & 0x0f;
61 c += '0';
62 if (c > '9')
63 c += 'a' - '9' - 1;
64 *pos++ = c;
65 }
66 *pos = 0;
67 *buf = pos;
68}
69
70/*
71 * Print an unsigned 32bit value as decimal number to an u16 string
72 *
Heinrich Schuchardtfe3ae732018-07-07 23:39:15 +020073 * @value: value to be printed
74 * @prec: minimum number of digits to display
75 * @buf: pointer to buffer address
76 * on return position of terminating zero word
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +020077 */
Heinrich Schuchardtfe3ae732018-07-07 23:39:15 +020078static void uint2dec(u32 value, int prec, u16 **buf)
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +020079{
80 u16 *pos = *buf;
81 int i;
82 u16 c;
83 u64 f;
84
85 /*
86 * Increment by .5 and multiply with
87 * (2 << 60) / 1,000,000,000 = 0x44B82FA0.9B5A52CC
88 * to move the first digit to bit 60-63.
89 */
90 f = 0x225C17D0;
91 f += (0x9B5A52DULL * value) >> 28;
92 f += 0x44B82FA0ULL * value;
93
94 for (i = 0; i < 10; ++i) {
95 /* Write current digit */
96 c = f >> 60;
Heinrich Schuchardtfe3ae732018-07-07 23:39:15 +020097 if (c || pos != *buf || 10 - i <= prec)
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +020098 *pos++ = c + '0';
99 /* Eliminate current digit */
100 f &= 0xfffffffffffffff;
101 /* Get next digit */
102 f *= 0xaULL;
103 }
104 if (pos == *buf)
105 *pos++ = '0';
106 *pos = 0;
107 *buf = pos;
108}
109
110/*
111 * Print a signed 32bit value as decimal number to an u16 string
112 *
Heinrich Schuchardtfe3ae732018-07-07 23:39:15 +0200113 * @value: value to be printed
114 * @prec: minimum number of digits to display
115 * @buf: pointer to buffer address
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200116 * on return position of terminating zero word
117 */
Heinrich Schuchardtfe3ae732018-07-07 23:39:15 +0200118static void int2dec(s32 value, int prec, u16 **buf)
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200119{
120 u32 u;
121 u16 *pos = *buf;
122
123 if (value < 0) {
124 *pos++ = '-';
125 u = -value;
126 } else {
127 u = value;
128 }
Heinrich Schuchardtfe3ae732018-07-07 23:39:15 +0200129 uint2dec(u, prec, &pos);
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200130 *buf = pos;
131}
132
133/*
Heinrich Schuchardt9137df82018-01-11 08:15:54 +0100134 * Print a colored formatted string to the EFI console
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200135 *
Heinrich Schuchardt9137df82018-01-11 08:15:54 +0100136 * @color color, see constants in efi_api.h, use -1 for no color
137 * @fmt format string
138 * @... optional arguments
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200139 */
Heinrich Schuchardt9137df82018-01-11 08:15:54 +0100140void efi_st_printc(int color, const char *fmt, ...)
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200141{
142 va_list args;
143 u16 buf[160];
144 const char *c;
145 u16 *pos = buf;
146 const char *s;
Heinrich Schuchardt7c7756e2017-12-22 19:21:04 +0100147 u16 *u;
Heinrich Schuchardtfe3ae732018-07-07 23:39:15 +0200148 int prec;
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200149
150 va_start(args, fmt);
151
Heinrich Schuchardt9137df82018-01-11 08:15:54 +0100152 if (color >= 0)
153 con_out->set_attribute(con_out, (unsigned long)color);
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200154 c = fmt;
155 for (; *c; ++c) {
156 switch (*c) {
157 case '\\':
158 ++c;
159 switch (*c) {
160 case '\0':
161 --c;
162 break;
163 case 'n':
164 *pos++ = '\n';
165 break;
166 case 'r':
167 *pos++ = '\r';
168 break;
169 case 't':
170 *pos++ = '\t';
171 break;
172 default:
173 *pos++ = *c;
174 }
175 break;
176 case '%':
177 ++c;
Heinrich Schuchardtfe3ae732018-07-07 23:39:15 +0200178 /* Parse precision */
179 if (*c == '.') {
180 ++c;
181 prec = *c - '0';
182 ++c;
183 } else {
184 prec = 0;
185 }
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200186 switch (*c) {
187 case '\0':
188 --c;
189 break;
190 case 'd':
Heinrich Schuchardtfe3ae732018-07-07 23:39:15 +0200191 int2dec(va_arg(args, s32), prec, &pos);
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200192 break;
193 case 'p':
Heinrich Schuchardt2cd42e82017-10-05 16:36:06 +0200194 ++c;
195 switch (*c) {
Heinrich Schuchardt02efd5d2017-10-18 18:13:13 +0200196 /* MAC address */
Heinrich Schuchardt2cd42e82017-10-05 16:36:06 +0200197 case 'm':
198 mac(va_arg(args, void*), &pos);
199 break;
Heinrich Schuchardt02efd5d2017-10-18 18:13:13 +0200200
201 /* u16 string */
202 case 's':
203 u = va_arg(args, u16*);
Heinrich Schuchardt7c7756e2017-12-22 19:21:04 +0100204 if (pos > buf) {
205 *pos = 0;
206 con_out->output_string(con_out,
207 buf);
208 }
209 con_out->output_string(con_out, u);
210 pos = buf;
Heinrich Schuchardt02efd5d2017-10-18 18:13:13 +0200211 break;
Heinrich Schuchardt2cd42e82017-10-05 16:36:06 +0200212 default:
213 --c;
214 pointer(va_arg(args, void*), &pos);
215 }
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200216 break;
217 case 's':
218 s = va_arg(args, const char *);
219 for (; *s; ++s)
220 *pos++ = *s;
221 break;
222 case 'u':
Heinrich Schuchardtfe3ae732018-07-07 23:39:15 +0200223 uint2dec(va_arg(args, u32), prec, &pos);
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200224 break;
225 default:
226 break;
227 }
228 break;
229 default:
230 *pos++ = *c;
231 }
232 }
233 va_end(args);
234 *pos = 0;
235 con_out->output_string(con_out, buf);
Heinrich Schuchardt9137df82018-01-11 08:15:54 +0100236 if (color >= 0)
237 con_out->set_attribute(con_out, EFI_LIGHTGRAY);
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200238}
239
240/*
241 * Reads an Unicode character from the input device.
242 *
243 * @return: Unicode character
244 */
245u16 efi_st_get_key(void)
246{
247 struct efi_input_key input_key;
248 efi_status_t ret;
249
250 /* Wait for next key */
251 do {
252 ret = con_in->read_key_stroke(con_in, &input_key);
253 } while (ret == EFI_NOT_READY);
254 return input_key.unicode_char;
255}