u-boot-brain/lib/efi_selftest/efi_selftest_console.c
Heinrich Schuchardt 623b3a5797 efi_selftest: provide an EFI selftest application
A testing framework for the EFI API is provided.
It can be executed with the 'bootefi selftest' command.

It is coded in a way that at a later stage we may turn it
into a standalone EFI application. The current build system
does not allow this yet.

All tests use a driver model and are run in three phases:
setup, execute, teardown.

A test may be setup and executed at boottime,
it may be setup at boottime and executed at runtime,
or it may be setup and executed at runtime.

After executing all tests the system is reset.

Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
Signed-off-by: Alexander Graf <agraf@suse.de>
2017-09-18 23:53:57 +02:00

188 lines
3.1 KiB
C

/*
* EFI efi_selftest
*
* Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <efi_selftest.h>
#include <vsprintf.h>
struct efi_simple_text_output_protocol *con_out;
struct efi_simple_input_interface *con_in;
/*
* 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
* @buf: pointer to buffer address
* on return position of terminating zero word
*/
static void uint2dec(u32 value, 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)
*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
* @buf: pointer to buffer address
* on return position of terminating zero word
*/
static void int2dec(s32 value, u16 **buf)
{
u32 u;
u16 *pos = *buf;
if (value < 0) {
*pos++ = '-';
u = -value;
} else {
u = value;
}
uint2dec(u, &pos);
*buf = pos;
}
/*
* Print a formatted string to the EFI console
*
* @fmt: format string
* @...: optional arguments
*/
void efi_st_printf(const char *fmt, ...)
{
va_list args;
u16 buf[160];
const char *c;
u16 *pos = buf;
const char *s;
va_start(args, fmt);
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;
switch (*c) {
case '\0':
--c;
break;
case 'd':
int2dec(va_arg(args, s32), &pos);
break;
case 'p':
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), &pos);
break;
default:
break;
}
break;
default:
*pos++ = *c;
}
}
va_end(args);
*pos = 0;
con_out->output_string(con_out, buf);
}
/*
* 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;
}