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 * @buf: pointer to buffer address 75 * on return position of terminating zero word 76 */ 77 static void uint2dec(u32 value, u16 **buf) 78 { 79 u16 *pos = *buf; 80 int i; 81 u16 c; 82 u64 f; 83 84 /* 85 * Increment by .5 and multiply with 86 * (2 << 60) / 1,000,000,000 = 0x44B82FA0.9B5A52CC 87 * to move the first digit to bit 60-63. 88 */ 89 f = 0x225C17D0; 90 f += (0x9B5A52DULL * value) >> 28; 91 f += 0x44B82FA0ULL * value; 92 93 for (i = 0; i < 10; ++i) { 94 /* Write current digit */ 95 c = f >> 60; 96 if (c || pos != *buf) 97 *pos++ = c + '0'; 98 /* Eliminate current digit */ 99 f &= 0xfffffffffffffff; 100 /* Get next digit */ 101 f *= 0xaULL; 102 } 103 if (pos == *buf) 104 *pos++ = '0'; 105 *pos = 0; 106 *buf = pos; 107 } 108 109 /* 110 * Print a signed 32bit value as decimal number to an u16 string 111 * 112 * @value: value to be printed 113 * @buf: pointer to buffer address 114 * on return position of terminating zero word 115 */ 116 static void int2dec(s32 value, u16 **buf) 117 { 118 u32 u; 119 u16 *pos = *buf; 120 121 if (value < 0) { 122 *pos++ = '-'; 123 u = -value; 124 } else { 125 u = value; 126 } 127 uint2dec(u, &pos); 128 *buf = pos; 129 } 130 131 /* 132 * Print a colored formatted string to the EFI console 133 * 134 * @color color, see constants in efi_api.h, use -1 for no color 135 * @fmt format string 136 * @... optional arguments 137 */ 138 void efi_st_printc(int color, 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 u16 *u; 146 147 va_start(args, fmt); 148 149 if (color >= 0) 150 con_out->set_attribute(con_out, (unsigned long)color); 151 c = fmt; 152 for (; *c; ++c) { 153 switch (*c) { 154 case '\\': 155 ++c; 156 switch (*c) { 157 case '\0': 158 --c; 159 break; 160 case 'n': 161 *pos++ = '\n'; 162 break; 163 case 'r': 164 *pos++ = '\r'; 165 break; 166 case 't': 167 *pos++ = '\t'; 168 break; 169 default: 170 *pos++ = *c; 171 } 172 break; 173 case '%': 174 ++c; 175 switch (*c) { 176 case '\0': 177 --c; 178 break; 179 case 'd': 180 int2dec(va_arg(args, s32), &pos); 181 break; 182 case 'p': 183 ++c; 184 switch (*c) { 185 /* MAC address */ 186 case 'm': 187 mac(va_arg(args, void*), &pos); 188 break; 189 190 /* u16 string */ 191 case 's': 192 u = va_arg(args, u16*); 193 if (pos > buf) { 194 *pos = 0; 195 con_out->output_string(con_out, 196 buf); 197 } 198 con_out->output_string(con_out, u); 199 pos = buf; 200 break; 201 default: 202 --c; 203 pointer(va_arg(args, void*), &pos); 204 } 205 break; 206 case 's': 207 s = va_arg(args, const char *); 208 for (; *s; ++s) 209 *pos++ = *s; 210 break; 211 case 'u': 212 uint2dec(va_arg(args, u32), &pos); 213 break; 214 default: 215 break; 216 } 217 break; 218 default: 219 *pos++ = *c; 220 } 221 } 222 va_end(args); 223 *pos = 0; 224 con_out->output_string(con_out, buf); 225 if (color >= 0) 226 con_out->set_attribute(con_out, EFI_LIGHTGRAY); 227 } 228 229 /* 230 * Reads an Unicode character from the input device. 231 * 232 * @return: Unicode character 233 */ 234 u16 efi_st_get_key(void) 235 { 236 struct efi_input_key input_key; 237 efi_status_t ret; 238 239 /* Wait for next key */ 240 do { 241 ret = con_in->read_key_stroke(con_in, &input_key); 242 } while (ret == EFI_NOT_READY); 243 return input_key.unicode_char; 244 } 245