efi_selftest: provide an EFI selftest application
[platform/kernel/u-boot.git] / lib / efi_selftest / efi_selftest_console.c
1 /*
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
12 struct efi_simple_text_output_protocol *con_out;
13 struct efi_simple_input_interface *con_in;
14
15 /*
16  * Print a pointer to an u16 string
17  *
18  * @pointer: pointer
19  * @buf: pointer to buffer address
20  * on return position of terminating zero word
21  */
22 static void pointer(void *pointer, u16 **buf)
23 {
24         int i;
25         u16 c;
26         uintptr_t p = (uintptr_t)pointer;
27         u16 *pos = *buf;
28
29         for (i = 8 * sizeof(p) - 4; i >= 0; i -= 4) {
30                 c = (p >> i) & 0x0f;
31                 c += '0';
32                 if (c > '9')
33                         c += 'a' - '9' - 1;
34                 *pos++ = c;
35         }
36         *pos = 0;
37         *buf = pos;
38 }
39
40 /*
41  * Print an unsigned 32bit value as decimal number to an u16 string
42  *
43  * @value: value to be printed
44  * @buf: pointer to buffer address
45  * on return position of terminating zero word
46  */
47 static void uint2dec(u32 value, u16 **buf)
48 {
49         u16 *pos = *buf;
50         int i;
51         u16 c;
52         u64 f;
53
54         /*
55          * Increment by .5 and multiply with
56          * (2 << 60) / 1,000,000,000 = 0x44B82FA0.9B5A52CC
57          * to move the first digit to bit 60-63.
58          */
59         f = 0x225C17D0;
60         f += (0x9B5A52DULL * value) >> 28;
61         f += 0x44B82FA0ULL * value;
62
63         for (i = 0; i < 10; ++i) {
64                 /* Write current digit */
65                 c = f >> 60;
66                 if (c || pos != *buf)
67                         *pos++ = c + '0';
68                 /* Eliminate current digit */
69                 f &= 0xfffffffffffffff;
70                 /* Get next digit */
71                 f *= 0xaULL;
72         }
73         if (pos == *buf)
74                 *pos++ = '0';
75         *pos = 0;
76         *buf = pos;
77 }
78
79 /*
80  * Print a signed 32bit value as decimal number to an u16 string
81  *
82  * @value: value to be printed
83  * @buf: pointer to buffer address
84  * on return position of terminating zero word
85  */
86 static void int2dec(s32 value, u16 **buf)
87 {
88         u32 u;
89         u16 *pos = *buf;
90
91         if (value < 0) {
92                 *pos++ = '-';
93                 u = -value;
94         } else {
95                 u = value;
96         }
97         uint2dec(u, &pos);
98         *buf = pos;
99 }
100
101 /*
102  * Print a formatted string to the EFI console
103  *
104  * @fmt: format string
105  * @...: optional arguments
106  */
107 void efi_st_printf(const char *fmt, ...)
108 {
109         va_list args;
110         u16 buf[160];
111         const char *c;
112         u16 *pos = buf;
113         const char *s;
114
115         va_start(args, fmt);
116
117         c = fmt;
118         for (; *c; ++c) {
119                 switch (*c) {
120                 case '\\':
121                         ++c;
122                         switch (*c) {
123                         case '\0':
124                                 --c;
125                                 break;
126                         case 'n':
127                                 *pos++ = '\n';
128                                 break;
129                         case 'r':
130                                 *pos++ = '\r';
131                                 break;
132                         case 't':
133                                 *pos++ = '\t';
134                                 break;
135                         default:
136                                 *pos++ = *c;
137                         }
138                         break;
139                 case '%':
140                         ++c;
141                         switch (*c) {
142                         case '\0':
143                                 --c;
144                                 break;
145                         case 'd':
146                                 int2dec(va_arg(args, s32), &pos);
147                                 break;
148                         case 'p':
149                                 pointer(va_arg(args, void*), &pos);
150                                 break;
151                         case 's':
152                                 s = va_arg(args, const char *);
153                                 for (; *s; ++s)
154                                         *pos++ = *s;
155                                 break;
156                         case 'u':
157                                 uint2dec(va_arg(args, u32), &pos);
158                                 break;
159                         default:
160                                 break;
161                         }
162                         break;
163                 default:
164                         *pos++ = *c;
165                 }
166         }
167         va_end(args);
168         *pos = 0;
169         con_out->output_string(con_out, buf);
170 }
171
172 /*
173  * Reads an Unicode character from the input device.
174  *
175  * @return: Unicode character
176  */
177 u16 efi_st_get_key(void)
178 {
179         struct efi_input_key input_key;
180         efi_status_t ret;
181
182         /* Wait for next key */
183         do {
184                 ret = con_in->read_key_stroke(con_in, &input_key);
185         } while (ret == EFI_NOT_READY);
186         return input_key.unicode_char;
187 }