Prepare v2023.10
[platform/kernel/u-boot.git] / lib / efi_selftest / efi_selftest_console.c
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 <net.h>
10 #include <vsprintf.h>
11
12 struct efi_simple_text_output_protocol *con_out;
13 struct efi_simple_text_input_protocol *con_in;
14
15 /*
16  * 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  */
22 static 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 /*
47  * printx() - print hexadecimal number to an u16 string
48  *
49  * @p:          value to print
50  * @prec:       minimum number of digits to print
51  * @buf:        pointer to buffer address,
52  *              on return position of terminating zero word
53  */
54 static void printx(u64 p, int prec, u16 **buf)
55 {
56         int i;
57         u16 c;
58         u16 *pos = *buf;
59
60         for (i = 2 * sizeof(p) - 1; i >= 0; --i) {
61                 c = (p >> (4 * i)) & 0x0f;
62                 if (c || pos != *buf || !i || i < prec) {
63                         c += '0';
64                         if (c > '9')
65                                 c += 'a' - '9' - 1;
66                         *pos++ = c;
67                 }
68         }
69         *pos = 0;
70         *buf = pos;
71 }
72
73 /**
74  * print_guid() - print GUID to an u16 string
75  *
76  * @p:          GUID to print
77  * @buf:        pointer to buffer address,
78  *              on return position of terminating zero word
79  */
80 static void print_uuid(u8 *p, u16 **buf)
81 {
82         int i;
83         const u8 seq[] = {
84                 3, 2, 1, 0, '-', 5, 4, '-', 7, 6, '-',
85                 8, 9, 10, 11, 12, 13, 14, 15 };
86
87         for (i = 0; i < sizeof(seq); ++i) {
88                 if (seq[i] == '-')
89                         *(*buf)++ = u'-';
90                 else
91                         printx(p[seq[i]], 2, buf);
92         }
93 }
94
95 /*
96  * Print an unsigned 32bit value as decimal number to an u16 string
97  *
98  * @value:      value to be printed
99  * @prec:       minimum number of digits to display
100  * @buf:        pointer to buffer address
101  *              on return position of terminating zero word
102  */
103 static void uint2dec(u32 value, int prec, u16 **buf)
104 {
105         u16 *pos = *buf;
106         int i;
107         u16 c;
108         u64 f;
109
110         /*
111          * Increment by .5 and multiply with
112          * (2 << 60) / 1,000,000,000 = 0x44B82FA0.9B5A52CC
113          * to move the first digit to bit 60-63.
114          */
115         f = 0x225C17D0;
116         f += (0x9B5A52DULL * value) >> 28;
117         f += 0x44B82FA0ULL * value;
118
119         for (i = 0; i < 10; ++i) {
120                 /* Write current digit */
121                 c = f >> 60;
122                 if (c || pos != *buf || 10 - i <= prec)
123                         *pos++ = c + '0';
124                 /* Eliminate current digit */
125                 f &= 0xfffffffffffffff;
126                 /* Get next digit */
127                 f *= 0xaULL;
128         }
129         if (pos == *buf)
130                 *pos++ = '0';
131         *pos = 0;
132         *buf = pos;
133 }
134
135 /*
136  * Print a signed 32bit value as decimal number to an u16 string
137  *
138  * @value:      value to be printed
139  * @prec:       minimum number of digits to display
140  * @buf:        pointer to buffer address
141  * on return position of terminating zero word
142  */
143 static void int2dec(s32 value, int prec, u16 **buf)
144 {
145         u32 u;
146         u16 *pos = *buf;
147
148         if (value < 0) {
149                 *pos++ = '-';
150                 u = -value;
151         } else {
152                 u = value;
153         }
154         uint2dec(u, prec, &pos);
155         *buf = pos;
156 }
157
158 /*
159  * Print a colored formatted string to the EFI console
160  *
161  * @color       color, see constants in efi_api.h, use -1 for no color
162  * @fmt         format string
163  * @...         optional arguments
164  */
165 void efi_st_printc(int color, const char *fmt, ...)
166 {
167         va_list args;
168         u16 buf[160];
169         const char *c;
170         u16 *pos = buf;
171         const char *s;
172         u16 *u;
173         int prec;
174
175         va_start(args, fmt);
176
177         if (color >= 0)
178                 con_out->set_attribute(con_out, (unsigned long)color);
179         c = fmt;
180         for (; *c; ++c) {
181                 switch (*c) {
182                 case '\\':
183                         ++c;
184                         switch (*c) {
185                         case '\0':
186                                 --c;
187                                 break;
188                         case 'n':
189                                 *pos++ = '\n';
190                                 break;
191                         case 'r':
192                                 *pos++ = '\r';
193                                 break;
194                         case 't':
195                                 *pos++ = '\t';
196                                 break;
197                         default:
198                                 *pos++ = *c;
199                         }
200                         break;
201                 case '%':
202                         ++c;
203                         /* Parse precision */
204                         if (*c == '.') {
205                                 ++c;
206                                 prec = *c - '0';
207                                 ++c;
208                         } else {
209                                 prec = 0;
210                         }
211                         switch (*c) {
212                         case '\0':
213                                 --c;
214                                 break;
215                         case 'd':
216                                 int2dec(va_arg(args, s32), prec, &pos);
217                                 break;
218                         case 'p':
219                                 ++c;
220                                 switch (*c) {
221                                 /* MAC address */
222                                 case 'm':
223                                         mac(va_arg(args, void*), &pos);
224                                         break;
225
226                                 /* u16 string */
227                                 case 's':
228                                         u = va_arg(args, u16*);
229                                         if (pos > buf) {
230                                                 *pos = 0;
231                                                 con_out->output_string(con_out,
232                                                                        buf);
233                                         }
234                                         con_out->output_string(con_out, u);
235                                         pos = buf;
236                                         break;
237                                 case 'U':
238                                         print_uuid(va_arg(args, void*), &pos);
239                                         break;
240                                 default:
241                                         --c;
242                                         printx((uintptr_t)va_arg(args, void *),
243                                                2 * sizeof(void *), &pos);
244                                         break;
245                                 }
246                                 break;
247                         case 's':
248                                 s = va_arg(args, const char *);
249                                 for (; *s; ++s)
250                                         *pos++ = *s;
251                                 break;
252                         case 'u':
253                                 uint2dec(va_arg(args, u32), prec, &pos);
254                                 break;
255                         case 'x':
256                                 printx((u64)va_arg(args, unsigned int),
257                                        prec, &pos);
258                                 break;
259                         default:
260                                 break;
261                         }
262                         break;
263                 default:
264                         *pos++ = *c;
265                 }
266         }
267         va_end(args);
268         *pos = 0;
269         con_out->output_string(con_out, buf);
270         if (color >= 0)
271                 con_out->set_attribute(con_out, EFI_LIGHTGRAY);
272 }
273
274 /*
275  * Reads an Unicode character from the input device.
276  *
277  * Return: Unicode character
278  */
279 u16 efi_st_get_key(void)
280 {
281         struct efi_input_key input_key;
282         efi_status_t ret;
283
284         /* Wait for next key */
285         do {
286                 ret = con_in->read_key_stroke(con_in, &input_key);
287         } while (ret == EFI_NOT_READY);
288         return input_key.unicode_char;
289 }