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 146 va_start(args, fmt); 147 148 c = fmt; 149 for (; *c; ++c) { 150 switch (*c) { 151 case '\\': 152 ++c; 153 switch (*c) { 154 case '\0': 155 --c; 156 break; 157 case 'n': 158 *pos++ = '\n'; 159 break; 160 case 'r': 161 *pos++ = '\r'; 162 break; 163 case 't': 164 *pos++ = '\t'; 165 break; 166 default: 167 *pos++ = *c; 168 } 169 break; 170 case '%': 171 ++c; 172 switch (*c) { 173 case '\0': 174 --c; 175 break; 176 case 'd': 177 int2dec(va_arg(args, s32), &pos); 178 break; 179 case 'p': 180 ++c; 181 switch (*c) { 182 case 'm': 183 mac(va_arg(args, void*), &pos); 184 break; 185 default: 186 --c; 187 pointer(va_arg(args, void*), &pos); 188 } 189 break; 190 case 's': 191 s = va_arg(args, const char *); 192 for (; *s; ++s) 193 *pos++ = *s; 194 break; 195 case 'u': 196 uint2dec(va_arg(args, u32), &pos); 197 break; 198 default: 199 break; 200 } 201 break; 202 default: 203 *pos++ = *c; 204 } 205 } 206 va_end(args); 207 *pos = 0; 208 con_out->output_string(con_out, buf); 209 } 210 211 /* 212 * Reads an Unicode character from the input device. 213 * 214 * @return: Unicode character 215 */ 216 u16 efi_st_get_key(void) 217 { 218 struct efi_input_key input_key; 219 efi_status_t ret; 220 221 /* Wait for next key */ 222 do { 223 ret = con_in->read_key_stroke(con_in, &input_key); 224 } while (ret == EFI_NOT_READY); 225 return input_key.unicode_char; 226 } 227