mirror of https://github.com/Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
255 lines
4.5 KiB
255 lines
4.5 KiB
// SPDX-License-Identifier: GPL-2.0+ |
|
/* |
|
* EFI efi_selftest |
|
* |
|
* Copyright (c) 2017 Heinrich Schuchardt <[email protected]> |
|
*/ |
|
|
|
#include <efi_selftest.h> |
|
#include <vsprintf.h> |
|
|
|
struct efi_simple_text_output_protocol *con_out; |
|
struct efi_simple_text_input_protocol *con_in; |
|
|
|
/* |
|
* Print a MAC address to an u16 string |
|
* |
|
* @pointer: mac address |
|
* @buf: pointer to buffer address |
|
* on return position of terminating zero word |
|
*/ |
|
static void mac(void *pointer, u16 **buf) |
|
{ |
|
int i, j; |
|
u16 c; |
|
u8 *p = (u8 *)pointer; |
|
u8 byte; |
|
u16 *pos = *buf; |
|
|
|
for (i = 0; i < ARP_HLEN; ++i) { |
|
if (i) |
|
*pos++ = ':'; |
|
byte = p[i]; |
|
for (j = 4; j >= 0; j -= 4) { |
|
c = (byte >> j) & 0x0f; |
|
c += '0'; |
|
if (c > '9') |
|
c += 'a' - '9' - 1; |
|
*pos++ = c; |
|
} |
|
} |
|
*pos = 0; |
|
*buf = pos; |
|
} |
|
|
|
/* |
|
* Print a pointer to an u16 string |
|
* |
|
* @pointer: pointer |
|
* @buf: pointer to buffer address |
|
* on return position of terminating zero word |
|
*/ |
|
static void pointer(void *pointer, u16 **buf) |
|
{ |
|
int i; |
|
u16 c; |
|
uintptr_t p = (uintptr_t)pointer; |
|
u16 *pos = *buf; |
|
|
|
for (i = 8 * sizeof(p) - 4; i >= 0; i -= 4) { |
|
c = (p >> i) & 0x0f; |
|
c += '0'; |
|
if (c > '9') |
|
c += 'a' - '9' - 1; |
|
*pos++ = c; |
|
} |
|
*pos = 0; |
|
*buf = pos; |
|
} |
|
|
|
/* |
|
* Print an unsigned 32bit value as decimal number to an u16 string |
|
* |
|
* @value: value to be printed |
|
* @prec: minimum number of digits to display |
|
* @buf: pointer to buffer address |
|
* on return position of terminating zero word |
|
*/ |
|
static void uint2dec(u32 value, int prec, u16 **buf) |
|
{ |
|
u16 *pos = *buf; |
|
int i; |
|
u16 c; |
|
u64 f; |
|
|
|
/* |
|
* Increment by .5 and multiply with |
|
* (2 << 60) / 1,000,000,000 = 0x44B82FA0.9B5A52CC |
|
* to move the first digit to bit 60-63. |
|
*/ |
|
f = 0x225C17D0; |
|
f += (0x9B5A52DULL * value) >> 28; |
|
f += 0x44B82FA0ULL * value; |
|
|
|
for (i = 0; i < 10; ++i) { |
|
/* Write current digit */ |
|
c = f >> 60; |
|
if (c || pos != *buf || 10 - i <= prec) |
|
*pos++ = c + '0'; |
|
/* Eliminate current digit */ |
|
f &= 0xfffffffffffffff; |
|
/* Get next digit */ |
|
f *= 0xaULL; |
|
} |
|
if (pos == *buf) |
|
*pos++ = '0'; |
|
*pos = 0; |
|
*buf = pos; |
|
} |
|
|
|
/* |
|
* Print a signed 32bit value as decimal number to an u16 string |
|
* |
|
* @value: value to be printed |
|
* @prec: minimum number of digits to display |
|
* @buf: pointer to buffer address |
|
* on return position of terminating zero word |
|
*/ |
|
static void int2dec(s32 value, int prec, u16 **buf) |
|
{ |
|
u32 u; |
|
u16 *pos = *buf; |
|
|
|
if (value < 0) { |
|
*pos++ = '-'; |
|
u = -value; |
|
} else { |
|
u = value; |
|
} |
|
uint2dec(u, prec, &pos); |
|
*buf = pos; |
|
} |
|
|
|
/* |
|
* Print a colored formatted string to the EFI console |
|
* |
|
* @color color, see constants in efi_api.h, use -1 for no color |
|
* @fmt format string |
|
* @... optional arguments |
|
*/ |
|
void efi_st_printc(int color, const char *fmt, ...) |
|
{ |
|
va_list args; |
|
u16 buf[160]; |
|
const char *c; |
|
u16 *pos = buf; |
|
const char *s; |
|
u16 *u; |
|
int prec; |
|
|
|
va_start(args, fmt); |
|
|
|
if (color >= 0) |
|
con_out->set_attribute(con_out, (unsigned long)color); |
|
c = fmt; |
|
for (; *c; ++c) { |
|
switch (*c) { |
|
case '\\': |
|
++c; |
|
switch (*c) { |
|
case '\0': |
|
--c; |
|
break; |
|
case 'n': |
|
*pos++ = '\n'; |
|
break; |
|
case 'r': |
|
*pos++ = '\r'; |
|
break; |
|
case 't': |
|
*pos++ = '\t'; |
|
break; |
|
default: |
|
*pos++ = *c; |
|
} |
|
break; |
|
case '%': |
|
++c; |
|
/* Parse precision */ |
|
if (*c == '.') { |
|
++c; |
|
prec = *c - '0'; |
|
++c; |
|
} else { |
|
prec = 0; |
|
} |
|
switch (*c) { |
|
case '\0': |
|
--c; |
|
break; |
|
case 'd': |
|
int2dec(va_arg(args, s32), prec, &pos); |
|
break; |
|
case 'p': |
|
++c; |
|
switch (*c) { |
|
/* MAC address */ |
|
case 'm': |
|
mac(va_arg(args, void*), &pos); |
|
break; |
|
|
|
/* u16 string */ |
|
case 's': |
|
u = va_arg(args, u16*); |
|
if (pos > buf) { |
|
*pos = 0; |
|
con_out->output_string(con_out, |
|
buf); |
|
} |
|
con_out->output_string(con_out, u); |
|
pos = buf; |
|
break; |
|
default: |
|
--c; |
|
pointer(va_arg(args, void*), &pos); |
|
} |
|
break; |
|
case 's': |
|
s = va_arg(args, const char *); |
|
for (; *s; ++s) |
|
*pos++ = *s; |
|
break; |
|
case 'u': |
|
uint2dec(va_arg(args, u32), prec, &pos); |
|
break; |
|
default: |
|
break; |
|
} |
|
break; |
|
default: |
|
*pos++ = *c; |
|
} |
|
} |
|
va_end(args); |
|
*pos = 0; |
|
con_out->output_string(con_out, buf); |
|
if (color >= 0) |
|
con_out->set_attribute(con_out, EFI_LIGHTGRAY); |
|
} |
|
|
|
/* |
|
* Reads an Unicode character from the input device. |
|
* |
|
* @return: Unicode character |
|
*/ |
|
u16 efi_st_get_key(void) |
|
{ |
|
struct efi_input_key input_key; |
|
efi_status_t ret; |
|
|
|
/* Wait for next key */ |
|
do { |
|
ret = con_in->read_key_stroke(con_in, &input_key); |
|
} while (ret == EFI_NOT_READY); |
|
return input_key.unicode_char; |
|
}
|
|
|