efi_loader: validate load option
[oweals/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  * 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  */
53 static 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  * @prec:       minimum number of digits to display
76  * @buf:        pointer to buffer address
77  *              on return position of terminating zero word
78  */
79 static void uint2dec(u32 value, int prec, u16 **buf)
80 {
81         u16 *pos = *buf;
82         int i;
83         u16 c;
84         u64 f;
85
86         /*
87          * Increment by .5 and multiply with
88          * (2 << 60) / 1,000,000,000 = 0x44B82FA0.9B5A52CC
89          * to move the first digit to bit 60-63.
90          */
91         f = 0x225C17D0;
92         f += (0x9B5A52DULL * value) >> 28;
93         f += 0x44B82FA0ULL * value;
94
95         for (i = 0; i < 10; ++i) {
96                 /* Write current digit */
97                 c = f >> 60;
98                 if (c || pos != *buf || 10 - i <= prec)
99                         *pos++ = c + '0';
100                 /* Eliminate current digit */
101                 f &= 0xfffffffffffffff;
102                 /* Get next digit */
103                 f *= 0xaULL;
104         }
105         if (pos == *buf)
106                 *pos++ = '0';
107         *pos = 0;
108         *buf = pos;
109 }
110
111 /*
112  * Print a signed 32bit value as decimal number to an u16 string
113  *
114  * @value:      value to be printed
115  * @prec:       minimum number of digits to display
116  * @buf:        pointer to buffer address
117  * on return position of terminating zero word
118  */
119 static void int2dec(s32 value, int prec, u16 **buf)
120 {
121         u32 u;
122         u16 *pos = *buf;
123
124         if (value < 0) {
125                 *pos++ = '-';
126                 u = -value;
127         } else {
128                 u = value;
129         }
130         uint2dec(u, prec, &pos);
131         *buf = pos;
132 }
133
134 /*
135  * Print a colored formatted string to the EFI console
136  *
137  * @color       color, see constants in efi_api.h, use -1 for no color
138  * @fmt         format string
139  * @...         optional arguments
140  */
141 void efi_st_printc(int color, const char *fmt, ...)
142 {
143         va_list args;
144         u16 buf[160];
145         const char *c;
146         u16 *pos = buf;
147         const char *s;
148         u16 *u;
149         int prec;
150
151         va_start(args, fmt);
152
153         if (color >= 0)
154                 con_out->set_attribute(con_out, (unsigned long)color);
155         c = fmt;
156         for (; *c; ++c) {
157                 switch (*c) {
158                 case '\\':
159                         ++c;
160                         switch (*c) {
161                         case '\0':
162                                 --c;
163                                 break;
164                         case 'n':
165                                 *pos++ = '\n';
166                                 break;
167                         case 'r':
168                                 *pos++ = '\r';
169                                 break;
170                         case 't':
171                                 *pos++ = '\t';
172                                 break;
173                         default:
174                                 *pos++ = *c;
175                         }
176                         break;
177                 case '%':
178                         ++c;
179                         /* Parse precision */
180                         if (*c == '.') {
181                                 ++c;
182                                 prec = *c - '0';
183                                 ++c;
184                         } else {
185                                 prec = 0;
186                         }
187                         switch (*c) {
188                         case '\0':
189                                 --c;
190                                 break;
191                         case 'd':
192                                 int2dec(va_arg(args, s32), prec, &pos);
193                                 break;
194                         case 'p':
195                                 ++c;
196                                 switch (*c) {
197                                 /* MAC address */
198                                 case 'm':
199                                         mac(va_arg(args, void*), &pos);
200                                         break;
201
202                                 /* u16 string */
203                                 case 's':
204                                         u = va_arg(args, u16*);
205                                         if (pos > buf) {
206                                                 *pos = 0;
207                                                 con_out->output_string(con_out,
208                                                                        buf);
209                                         }
210                                         con_out->output_string(con_out, u);
211                                         pos = buf;
212                                         break;
213                                 default:
214                                         --c;
215                                         pointer(va_arg(args, void*), &pos);
216                                 }
217                                 break;
218                         case 's':
219                                 s = va_arg(args, const char *);
220                                 for (; *s; ++s)
221                                         *pos++ = *s;
222                                 break;
223                         case 'u':
224                                 uint2dec(va_arg(args, u32), prec, &pos);
225                                 break;
226                         default:
227                                 break;
228                         }
229                         break;
230                 default:
231                         *pos++ = *c;
232                 }
233         }
234         va_end(args);
235         *pos = 0;
236         con_out->output_string(con_out, buf);
237         if (color >= 0)
238                 con_out->set_attribute(con_out, EFI_LIGHTGRAY);
239 }
240
241 /*
242  * Reads an Unicode character from the input device.
243  *
244  * @return: Unicode character
245  */
246 u16 efi_st_get_key(void)
247 {
248         struct efi_input_key input_key;
249         efi_status_t ret;
250
251         /* Wait for next key */
252         do {
253                 ret = con_in->read_key_stroke(con_in, &input_key);
254         } while (ret == EFI_NOT_READY);
255         return input_key.unicode_char;
256 }