blob: 7b5b724a617892d70e6a2b410accf8c7b62f4c20 [file] [log] [blame]
Heinrich Schuchardt623b3a52017-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/*
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 */
22static 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 */
47static 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 */
86static 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 */
107void 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 */
177u16 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}