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 }
188