1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * EFI efi_selftest 4 * 5 * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de> 6 */ 7 8 #include <efi_selftest.h> 9 #include <vsprintf.h> 10 11 struct efi_simple_text_output_protocol *con_out; 12 struct efi_simple_input_interface *con_in; 13 14 /* 15 * Print a MAC address to an u16 string 16 * 17 * @pointer: mac address 18 * @buf: pointer to buffer address 19 * on return position of terminating zero word 20 */ 21 static void mac(void *pointer, u16 **buf) 22 { 23 int i, j; 24 u16 c; 25 u8 *p = (u8 *)pointer; 26 u8 byte; 27 u16 *pos = *buf; 28 29 for (i = 0; i < ARP_HLEN; ++i) { 30 if (i) 31 *pos++ = ':'; 32 byte = p[i]; 33 for (j = 4; j >= 0; j -= 4) { 34 c = (byte >> j) & 0x0f; 35 c += '0'; 36 if (c > '9') 37 c += 'a' - '9' - 1; 38 *pos++ = c; 39 } 40 } 41 *pos = 0; 42 *buf = pos; 43 } 44 45 /* 46 * Print a pointer to an u16 string 47 * 48 * @pointer: pointer 49 * @buf: pointer to buffer address 50 * on return position of terminating zero word 51 */ 52 static void pointer(void *pointer, u16 **buf) 53 { 54 int i; 55 u16 c; 56 uintptr_t p = (uintptr_t)pointer; 57 u16 *pos = *buf; 58 59 for (i = 8 * sizeof(p) - 4; i >= 0; i -= 4) { 60 c = (p >> i) & 0x0f; 61 c += '0'; 62 if (c > '9') 63 c += 'a' - '9' - 1; 64 *pos++ = c; 65 } 66 *pos = 0; 67 *buf = pos; 68 } 69 70 /* 71 * Print an unsigned 32bit value as decimal number to an u16 string 72 * 73 * @value: value to be printed 74 * @prec: minimum number of digits to display 75 * @buf: pointer to buffer address 76 * on return position of terminating zero word 77 */ 78 static void uint2dec(u32 value, int prec, 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 || 10 - i <= prec) 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 * @prec: minimum number of digits to display 115 * @buf: pointer to buffer address 116 * on return position of terminating zero word 117 */ 118 static void int2dec(s32 value, int prec, u16 **buf) 119 { 120 u32 u; 121 u16 *pos = *buf; 122 123 if (value < 0) { 124 *pos++ = '-'; 125 u = -value; 126 } else { 127 u = value; 128 } 129 uint2dec(u, prec, &pos); 130 *buf = pos; 131 } 132 133 /* 134 * Print a colored formatted string to the EFI console 135 * 136 * @color color, see constants in efi_api.h, use -1 for no color 137 * @fmt format string 138 * @... optional arguments 139 */ 140 void efi_st_printc(int color, const char *fmt, ...) 141 { 142 va_list args; 143 u16 buf[160]; 144 const char *c; 145 u16 *pos = buf; 146 const char *s; 147 u16 *u; 148 int prec; 149 150 va_start(args, fmt); 151 152 if (color >= 0) 153 con_out->set_attribute(con_out, (unsigned long)color); 154 c = fmt; 155 for (; *c; ++c) { 156 switch (*c) { 157 case '\\': 158 ++c; 159 switch (*c) { 160 case '\0': 161 --c; 162 break; 163 case 'n': 164 *pos++ = '\n'; 165 break; 166 case 'r': 167 *pos++ = '\r'; 168 break; 169 case 't': 170 *pos++ = '\t'; 171 break; 172 default: 173 *pos++ = *c; 174 } 175 break; 176 case '%': 177 ++c; 178 /* Parse precision */ 179 if (*c == '.') { 180 ++c; 181 prec = *c - '0'; 182 ++c; 183 } else { 184 prec = 0; 185 } 186 switch (*c) { 187 case '\0': 188 --c; 189 break; 190 case 'd': 191 int2dec(va_arg(args, s32), prec, &pos); 192 break; 193 case 'p': 194 ++c; 195 switch (*c) { 196 /* MAC address */ 197 case 'm': 198 mac(va_arg(args, void*), &pos); 199 break; 200 201 /* u16 string */ 202 case 's': 203 u = va_arg(args, u16*); 204 if (pos > buf) { 205 *pos = 0; 206 con_out->output_string(con_out, 207 buf); 208 } 209 con_out->output_string(con_out, u); 210 pos = buf; 211 break; 212 default: 213 --c; 214 pointer(va_arg(args, void*), &pos); 215 } 216 break; 217 case 's': 218 s = va_arg(args, const char *); 219 for (; *s; ++s) 220 *pos++ = *s; 221 break; 222 case 'u': 223 uint2dec(va_arg(args, u32), prec, &pos); 224 break; 225 default: 226 break; 227 } 228 break; 229 default: 230 *pos++ = *c; 231 } 232 } 233 va_end(args); 234 *pos = 0; 235 con_out->output_string(con_out, buf); 236 if (color >= 0) 237 con_out->set_attribute(con_out, EFI_LIGHTGRAY); 238 } 239 240 /* 241 * Reads an Unicode character from the input device. 242 * 243 * @return: Unicode character 244 */ 245 u16 efi_st_get_key(void) 246 { 247 struct efi_input_key input_key; 248 efi_status_t ret; 249 250 /* Wait for next key */ 251 do { 252 ret = con_in->read_key_stroke(con_in, &input_key); 253 } while (ret == EFI_NOT_READY); 254 return input_key.unicode_char; 255 } 256