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 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 * @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 /* 133 * Print a formatted string to the EFI console 134 * 135 * @fmt: format string 136 * @...: optional arguments 137 */ 138 void efi_st_printf(const char *fmt, ...) 139 { 140 va_list args; 141 u16 buf[160]; 142 const char *c; 143 u16 *pos = buf; 144 const char *s; 145 const u16 *u; 146 147 va_start(args, fmt); 148 149 c = fmt; 150 for (; *c; ++c) { 151 switch (*c) { 152 case '\\': 153 ++c; 154 switch (*c) { 155 case '\0': 156 --c; 157 break; 158 case 'n': 159 *pos++ = '\n'; 160 break; 161 case 'r': 162 *pos++ = '\r'; 163 break; 164 case 't': 165 *pos++ = '\t'; 166 break; 167 default: 168 *pos++ = *c; 169 } 170 break; 171 case '%': 172 ++c; 173 switch (*c) { 174 case '\0': 175 --c; 176 break; 177 case 'd': 178 int2dec(va_arg(args, s32), &pos); 179 break; 180 case 'p': 181 ++c; 182 switch (*c) { 183 /* MAC address */ 184 case 'm': 185 mac(va_arg(args, void*), &pos); 186 break; 187 188 /* u16 string */ 189 case 's': 190 u = va_arg(args, u16*); 191 /* Ensure string fits into buffer */ 192 for (; *u && pos < buf + 120; ++u) 193 *pos++ = *u; 194 break; 195 default: 196 --c; 197 pointer(va_arg(args, void*), &pos); 198 } 199 break; 200 case 's': 201 s = va_arg(args, const char *); 202 for (; *s; ++s) 203 *pos++ = *s; 204 break; 205 case 'u': 206 uint2dec(va_arg(args, u32), &pos); 207 break; 208 default: 209 break; 210 } 211 break; 212 default: 213 *pos++ = *c; 214 } 215 } 216 va_end(args); 217 *pos = 0; 218 con_out->output_string(con_out, buf); 219 } 220 221 /* 222 * Reads an Unicode character from the input device. 223 * 224 * @return: Unicode character 225 */ 226 u16 efi_st_get_key(void) 227 { 228 struct efi_input_key input_key; 229 efi_status_t ret; 230 231 /* Wait for next key */ 232 do { 233 ret = con_in->read_key_stroke(con_in, &input_key); 234 } while (ret == EFI_NOT_READY); 235 return input_key.unicode_char; 236 } 237