Home | History | Annotate | Download | only in efi_selftest
      1 // SPDX-License-Identifier: GPL-2.0+
      2 /*
      3  * EFI efi_selftest
      4  *
      5  * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk (at) 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