1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * EFI efi_selftest
4 *
5 * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de>
6 */
7
8 #include <efi_selftest.h>
9 #include <vsprintf.h>
10
11 struct efi_simple_text_output_protocol *con_out;
12 struct efi_simple_input_interface *con_in;
13
14 /*
15 * 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 */
mac(void * pointer,u16 ** buf)21 static 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 /*
46 * 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 */
pointer(void * pointer,u16 ** buf)52 static 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 */
uint2dec(u32 value,u16 ** buf)77 static 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 */
int2dec(s32 value,u16 ** buf)116 static 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 /*
132 * Print a colored formatted string to the EFI console
133 *
134 * @color color, see constants in efi_api.h, use -1 for no color
135 * @fmt format string
136 * @... optional arguments
137 */
efi_st_printc(int color,const char * fmt,...)138 void efi_st_printc(int color, const char *fmt, ...)
139 {
140 va_list args;
141 u16 buf[160];
142 const char *c;
143 u16 *pos = buf;
144 const char *s;
145 u16 *u;
146
147 va_start(args, fmt);
148
149 if (color >= 0)
150 con_out->set_attribute(con_out, (unsigned long)color);
151 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':
183 ++c;
184 switch (*c) {
185 /* MAC address */
186 case 'm':
187 mac(va_arg(args, void*), &pos);
188 break;
189
190 /* u16 string */
191 case 's':
192 u = va_arg(args, u16*);
193 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;
200 break;
201 default:
202 --c;
203 pointer(va_arg(args, void*), &pos);
204 }
205 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);
225 if (color >= 0)
226 con_out->set_attribute(con_out, EFI_LIGHTGRAY);
227 }
228
229 /*
230 * Reads an Unicode character from the input device.
231 *
232 * @return: Unicode character
233 */
efi_st_get_key(void)234 u16 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 }
245