blob: e1649f48bc4bc874add10169a4e0a6cf41eb127a [file] [log] [blame]
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +02001/*
2 * EFI efi_selftest
3 *
4 * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de>
5 *
6 * SPDX-License-Identifier: GPL-2.0+
7 */
8
9#include <efi_selftest.h>
10#include <vsprintf.h>
11
12struct efi_simple_text_output_protocol *con_out;
13struct efi_simple_input_interface *con_in;
14
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 *
74 * @value: value to be printed
75 * @buf: pointer to buffer address
76 * on return position of terminating zero word
77 */
78static void uint2dec(u32 value, u16 **buf)
79{
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;
97 if (c || pos != *buf)
98 *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 *
113 * @value: value to be printed
114 * @buf: pointer to buffer address
115 * on return position of terminating zero word
116 */
117static void int2dec(s32 value, u16 **buf)
118{
119 u32 u;
120 u16 *pos = *buf;
121
122 if (value < 0) {
123 *pos++ = '-';
124 u = -value;
125 } else {
126 u = value;
127 }
128 uint2dec(u, &pos);
129 *buf = pos;
130}
131
132/*
Heinrich Schuchardt9137df82018-01-11 08:15:54 +0100133 * Print a colored formatted string to the EFI console
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200134 *
Heinrich Schuchardt9137df82018-01-11 08:15:54 +0100135 * @color color, see constants in efi_api.h, use -1 for no color
136 * @fmt format string
137 * @... optional arguments
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200138 */
Heinrich Schuchardt9137df82018-01-11 08:15:54 +0100139void efi_st_printc(int color, const char *fmt, ...)
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200140{
141 va_list args;
142 u16 buf[160];
143 const char *c;
144 u16 *pos = buf;
145 const char *s;
Heinrich Schuchardt7c7756e2017-12-22 19:21:04 +0100146 u16 *u;
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200147
148 va_start(args, fmt);
149
Heinrich Schuchardt9137df82018-01-11 08:15:54 +0100150 if (color >= 0)
151 con_out->set_attribute(con_out, (unsigned long)color);
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200152 c = fmt;
153 for (; *c; ++c) {
154 switch (*c) {
155 case '\\':
156 ++c;
157 switch (*c) {
158 case '\0':
159 --c;
160 break;
161 case 'n':
162 *pos++ = '\n';
163 break;
164 case 'r':
165 *pos++ = '\r';
166 break;
167 case 't':
168 *pos++ = '\t';
169 break;
170 default:
171 *pos++ = *c;
172 }
173 break;
174 case '%':
175 ++c;
176 switch (*c) {
177 case '\0':
178 --c;
179 break;
180 case 'd':
181 int2dec(va_arg(args, s32), &pos);
182 break;
183 case 'p':
Heinrich Schuchardt2cd42e82017-10-05 16:36:06 +0200184 ++c;
185 switch (*c) {
Heinrich Schuchardt02efd5d2017-10-18 18:13:13 +0200186 /* MAC address */
Heinrich Schuchardt2cd42e82017-10-05 16:36:06 +0200187 case 'm':
188 mac(va_arg(args, void*), &pos);
189 break;
Heinrich Schuchardt02efd5d2017-10-18 18:13:13 +0200190
191 /* u16 string */
192 case 's':
193 u = va_arg(args, u16*);
Heinrich Schuchardt7c7756e2017-12-22 19:21:04 +0100194 if (pos > buf) {
195 *pos = 0;
196 con_out->output_string(con_out,
197 buf);
198 }
199 con_out->output_string(con_out, u);
200 pos = buf;
Heinrich Schuchardt02efd5d2017-10-18 18:13:13 +0200201 break;
Heinrich Schuchardt2cd42e82017-10-05 16:36:06 +0200202 default:
203 --c;
204 pointer(va_arg(args, void*), &pos);
205 }
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200206 break;
207 case 's':
208 s = va_arg(args, const char *);
209 for (; *s; ++s)
210 *pos++ = *s;
211 break;
212 case 'u':
213 uint2dec(va_arg(args, u32), &pos);
214 break;
215 default:
216 break;
217 }
218 break;
219 default:
220 *pos++ = *c;
221 }
222 }
223 va_end(args);
224 *pos = 0;
225 con_out->output_string(con_out, buf);
Heinrich Schuchardt9137df82018-01-11 08:15:54 +0100226 if (color >= 0)
227 con_out->set_attribute(con_out, EFI_LIGHTGRAY);
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200228}
229
230/*
231 * Reads an Unicode character from the input device.
232 *
233 * @return: Unicode character
234 */
235u16 efi_st_get_key(void)
236{
237 struct efi_input_key input_key;
238 efi_status_t ret;
239
240 /* Wait for next key */
241 do {
242 ret = con_in->read_key_stroke(con_in, &input_key);
243 } while (ret == EFI_NOT_READY);
244 return input_key.unicode_char;
245}