blob: c3655a1fcc09b0b16e61b6d44d55d2745d28e7bc [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Heinrich Schuchardt623b3a52017-09-15 10:06:11 +02002/*
3 * EFI efi_selftest
4 *
5 * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de>
Heinrich Schuchardt623b3a52017-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;
12struct efi_simple_input_interface *con_in;
13
14/*
Heinrich Schuchardt1b6332592017-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 Schuchardt623b3a52017-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 *
73 * @value: value to be printed
74 * @buf: pointer to buffer address
75 * on return position of terminating zero word
76 */
77static void uint2dec(u32 value, u16 **buf)
78{
79 u16 *pos = *buf;
80 int i;
81 u16 c;
82 u64 f;
83
84 /*
85 * Increment by .5 and multiply with
86 * (2 << 60) / 1,000,000,000 = 0x44B82FA0.9B5A52CC
87 * to move the first digit to bit 60-63.
88 */
89 f = 0x225C17D0;
90 f += (0x9B5A52DULL * value) >> 28;
91 f += 0x44B82FA0ULL * value;
92
93 for (i = 0; i < 10; ++i) {
94 /* Write current digit */
95 c = f >> 60;
96 if (c || pos != *buf)
97 *pos++ = c + '0';
98 /* Eliminate current digit */
99 f &= 0xfffffffffffffff;
100 /* Get next digit */
101 f *= 0xaULL;
102 }
103 if (pos == *buf)
104 *pos++ = '0';
105 *pos = 0;
106 *buf = pos;
107}
108
109/*
110 * Print a signed 32bit value as decimal number to an u16 string
111 *
112 * @value: value to be printed
113 * @buf: pointer to buffer address
114 * on return position of terminating zero word
115 */
116static void int2dec(s32 value, u16 **buf)
117{
118 u32 u;
119 u16 *pos = *buf;
120
121 if (value < 0) {
122 *pos++ = '-';
123 u = -value;
124 } else {
125 u = value;
126 }
127 uint2dec(u, &pos);
128 *buf = pos;
129}
130
131/*
Heinrich Schuchardt853540c2018-01-11 08:15:54 +0100132 * Print a colored formatted string to the EFI console
Heinrich Schuchardt623b3a52017-09-15 10:06:11 +0200133 *
Heinrich Schuchardt853540c2018-01-11 08:15:54 +0100134 * @color color, see constants in efi_api.h, use -1 for no color
135 * @fmt format string
136 * @... optional arguments
Heinrich Schuchardt623b3a52017-09-15 10:06:11 +0200137 */
Heinrich Schuchardt853540c2018-01-11 08:15:54 +0100138void efi_st_printc(int color, const char *fmt, ...)
Heinrich Schuchardt623b3a52017-09-15 10:06:11 +0200139{
140 va_list args;
141 u16 buf[160];
142 const char *c;
143 u16 *pos = buf;
144 const char *s;
Heinrich Schuchardte0abeac2017-12-22 19:21:04 +0100145 u16 *u;
Heinrich Schuchardt623b3a52017-09-15 10:06:11 +0200146
147 va_start(args, fmt);
148
Heinrich Schuchardt853540c2018-01-11 08:15:54 +0100149 if (color >= 0)
150 con_out->set_attribute(con_out, (unsigned long)color);
Heinrich Schuchardt623b3a52017-09-15 10:06:11 +0200151 c = fmt;
152 for (; *c; ++c) {
153 switch (*c) {
154 case '\\':
155 ++c;
156 switch (*c) {
157 case '\0':
158 --c;
159 break;
160 case 'n':
161 *pos++ = '\n';
162 break;
163 case 'r':
164 *pos++ = '\r';
165 break;
166 case 't':
167 *pos++ = '\t';
168 break;
169 default:
170 *pos++ = *c;
171 }
172 break;
173 case '%':
174 ++c;
175 switch (*c) {
176 case '\0':
177 --c;
178 break;
179 case 'd':
180 int2dec(va_arg(args, s32), &pos);
181 break;
182 case 'p':
Heinrich Schuchardt1b6332592017-10-05 16:36:06 +0200183 ++c;
184 switch (*c) {
Heinrich Schuchardtd78e40d2017-10-18 18:13:13 +0200185 /* MAC address */
Heinrich Schuchardt1b6332592017-10-05 16:36:06 +0200186 case 'm':
187 mac(va_arg(args, void*), &pos);
188 break;
Heinrich Schuchardtd78e40d2017-10-18 18:13:13 +0200189
190 /* u16 string */
191 case 's':
192 u = va_arg(args, u16*);
Heinrich Schuchardte0abeac2017-12-22 19:21:04 +0100193 if (pos > buf) {
194 *pos = 0;
195 con_out->output_string(con_out,
196 buf);
197 }
198 con_out->output_string(con_out, u);
199 pos = buf;
Heinrich Schuchardtd78e40d2017-10-18 18:13:13 +0200200 break;
Heinrich Schuchardt1b6332592017-10-05 16:36:06 +0200201 default:
202 --c;
203 pointer(va_arg(args, void*), &pos);
204 }
Heinrich Schuchardt623b3a52017-09-15 10:06:11 +0200205 break;
206 case 's':
207 s = va_arg(args, const char *);
208 for (; *s; ++s)
209 *pos++ = *s;
210 break;
211 case 'u':
212 uint2dec(va_arg(args, u32), &pos);
213 break;
214 default:
215 break;
216 }
217 break;
218 default:
219 *pos++ = *c;
220 }
221 }
222 va_end(args);
223 *pos = 0;
224 con_out->output_string(con_out, buf);
Heinrich Schuchardt853540c2018-01-11 08:15:54 +0100225 if (color >= 0)
226 con_out->set_attribute(con_out, EFI_LIGHTGRAY);
Heinrich Schuchardt623b3a52017-09-15 10:06:11 +0200227}
228
229/*
230 * Reads an Unicode character from the input device.
231 *
232 * @return: Unicode character
233 */
234u16 efi_st_get_key(void)
235{
236 struct efi_input_key input_key;
237 efi_status_t ret;
238
239 /* Wait for next key */
240 do {
241 ret = con_in->read_key_stroke(con_in, &input_key);
242 } while (ret == EFI_NOT_READY);
243 return input_key.unicode_char;
244}