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