]>
Commit | Line | Data |
---|---|---|
623b3a57 HS |
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 | ||
1b633259 HS |
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 | ||
623b3a57 HS |
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 | * @buf: pointer to buffer address | |
76 | * on return position of terminating zero word | |
77 | */ | |
78 | static 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 | */ | |
117 | static 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 | /* | |
853540c8 | 133 | * Print a colored formatted string to the EFI console |
623b3a57 | 134 | * |
853540c8 HS |
135 | * @color color, see constants in efi_api.h, use -1 for no color |
136 | * @fmt format string | |
137 | * @... optional arguments | |
623b3a57 | 138 | */ |
853540c8 | 139 | void efi_st_printc(int color, const char *fmt, ...) |
623b3a57 HS |
140 | { |
141 | va_list args; | |
142 | u16 buf[160]; | |
143 | const char *c; | |
144 | u16 *pos = buf; | |
145 | const char *s; | |
e0abeacc | 146 | u16 *u; |
623b3a57 HS |
147 | |
148 | va_start(args, fmt); | |
149 | ||
853540c8 HS |
150 | if (color >= 0) |
151 | con_out->set_attribute(con_out, (unsigned long)color); | |
623b3a57 HS |
152 | 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': | |
1b633259 HS |
184 | ++c; |
185 | switch (*c) { | |
d78e40d6 | 186 | /* MAC address */ |
1b633259 HS |
187 | case 'm': |
188 | mac(va_arg(args, void*), &pos); | |
189 | break; | |
d78e40d6 HS |
190 | |
191 | /* u16 string */ | |
192 | case 's': | |
193 | u = va_arg(args, u16*); | |
e0abeacc HS |
194 | 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; | |
d78e40d6 | 201 | break; |
1b633259 HS |
202 | default: |
203 | --c; | |
204 | pointer(va_arg(args, void*), &pos); | |
205 | } | |
623b3a57 HS |
206 | 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); | |
853540c8 HS |
226 | if (color >= 0) |
227 | con_out->set_attribute(con_out, EFI_LIGHTGRAY); | |
623b3a57 HS |
228 | } |
229 | ||
230 | /* | |
231 | * Reads an Unicode character from the input device. | |
232 | * | |
233 | * @return: Unicode character | |
234 | */ | |
235 | u16 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 | } |