2018-12-11 21:54:06 +08:00
|
|
|
/*
|
2019-01-24 14:11:10 +08:00
|
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
|
|
*
|
|
|
|
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
|
2018-12-11 21:54:06 +08:00
|
|
|
*
|
|
|
|
* Authors:
|
|
|
|
* Anup Patel <anup.patel@wdc.com>
|
|
|
|
*/
|
|
|
|
|
2018-12-21 17:12:58 +08:00
|
|
|
#include <sbi/riscv_locks.h>
|
2020-03-27 14:46:16 +08:00
|
|
|
#include <sbi/sbi_console.h>
|
lib: sbi: Improve fatal error handling
BUG and BUG_ON are not informative and are rather lazy interfaces, only
telling the user that something went wrong in a given function, but not
what, requiring the user to find the sources corresponding to their
firmware (which may not be available) and figure out how that BUG(_ON)
was hit. Even SBI_ASSERT in its current form, which does include the
condition that triggered it in the output, isn't necessarily very
informative. In some cases, the error may be fixable by the user, but
they need to know the problem in order to have any hope of fixing it.
It's also a nuisance for developers, whose development trees may have
changed significantly since the release in question being used, and so
line numbers can make it harder for them to understand which error case
a user has hit.
This patch introduces a new sbi_panic function which is printf-like,
allowing detailed error messages to be printed to the console. BUG and
BUG_ON are removed, since the former is just a worse form of sbi_panic
and the latter is a worse version of SBI_ASSERT. Finally, SBI_ASSERT is
augmented to take a set of arguments to pass to sbi_panic on failure,
used like so (sbi_boot_print_hart's current error case, which currently
manually calls sbi_printf and sbi_hart_hang):
SBI_ASSERT(xlen >= 1, ("Error %d getting MISA XLEN\n", xlen));
The existing users of BUG are replaced with calls to sbi_panic along
with informative error messages. BUG_ON and SBI_ASSERT were unused (and,
in the case of SBI_ASSERT, remain unused).
Many existing users of sbi_hart_hang should be converted to use either
sbi_panic or SBI_ASSERT after this commit.
Signed-off-by: Jessica Clarke <jrtc27@jrtc27.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2021-11-22 01:30:22 +08:00
|
|
|
#include <sbi/sbi_hart.h>
|
2020-03-27 14:46:16 +08:00
|
|
|
#include <sbi/sbi_platform.h>
|
|
|
|
#include <sbi/sbi_scratch.h>
|
2022-11-23 15:02:06 +08:00
|
|
|
#include <sbi/sbi_string.h>
|
2018-12-11 21:54:06 +08:00
|
|
|
|
2023-01-13 17:23:53 +08:00
|
|
|
#define CONSOLE_TBUF_MAX 256
|
|
|
|
|
2021-04-21 20:33:50 +08:00
|
|
|
static const struct sbi_console_device *console_dev = NULL;
|
2023-01-13 17:23:53 +08:00
|
|
|
static char console_tbuf[CONSOLE_TBUF_MAX];
|
|
|
|
static u32 console_tbuf_len;
|
2019-04-11 08:41:52 +08:00
|
|
|
static spinlock_t console_out_lock = SPIN_LOCK_INITIALIZER;
|
2018-12-11 21:54:06 +08:00
|
|
|
|
|
|
|
bool sbi_isprintable(char c)
|
|
|
|
{
|
2019-04-11 08:41:52 +08:00
|
|
|
if (((31 < c) && (c < 127)) || (c == '\f') || (c == '\r') ||
|
|
|
|
(c == '\n') || (c == '\t')) {
|
2022-12-21 19:38:06 +08:00
|
|
|
return true;
|
2018-12-11 21:54:06 +08:00
|
|
|
}
|
2022-12-21 19:38:06 +08:00
|
|
|
return false;
|
2018-12-11 21:54:06 +08:00
|
|
|
}
|
|
|
|
|
2019-02-28 09:42:17 +08:00
|
|
|
int sbi_getc(void)
|
2018-12-11 21:54:06 +08:00
|
|
|
{
|
2021-04-21 20:33:50 +08:00
|
|
|
if (console_dev && console_dev->console_getc)
|
|
|
|
return console_dev->console_getc();
|
|
|
|
return -1;
|
2018-12-11 21:54:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void sbi_putc(char ch)
|
|
|
|
{
|
2021-04-21 20:33:50 +08:00
|
|
|
if (console_dev && console_dev->console_putc) {
|
|
|
|
if (ch == '\n')
|
|
|
|
console_dev->console_putc('\r');
|
|
|
|
console_dev->console_putc(ch);
|
|
|
|
}
|
2018-12-11 21:54:06 +08:00
|
|
|
}
|
|
|
|
|
2023-01-13 17:23:53 +08:00
|
|
|
static unsigned long nputs(const char *str, unsigned long len)
|
2018-12-11 21:54:06 +08:00
|
|
|
{
|
2023-01-13 17:23:53 +08:00
|
|
|
unsigned long i, ret;
|
2022-11-23 15:02:06 +08:00
|
|
|
|
|
|
|
if (console_dev && console_dev->console_puts) {
|
2023-01-13 17:23:53 +08:00
|
|
|
ret = console_dev->console_puts(str, len);
|
2022-11-23 15:02:06 +08:00
|
|
|
} else {
|
2023-01-13 17:23:53 +08:00
|
|
|
for (i = 0; i < len; i++)
|
|
|
|
sbi_putc(str[i]);
|
|
|
|
ret = len;
|
2018-12-11 21:54:06 +08:00
|
|
|
}
|
2023-01-13 17:23:53 +08:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void nputs_all(const char *str, unsigned long len)
|
|
|
|
{
|
|
|
|
unsigned long p = 0;
|
|
|
|
|
|
|
|
while (p < len)
|
|
|
|
p += nputs(&str[p], len - p);
|
|
|
|
}
|
|
|
|
|
|
|
|
void sbi_puts(const char *str)
|
|
|
|
{
|
|
|
|
unsigned long len = sbi_strlen(str);
|
|
|
|
|
|
|
|
spin_lock(&console_out_lock);
|
|
|
|
nputs_all(str, len);
|
2018-12-21 17:12:58 +08:00
|
|
|
spin_unlock(&console_out_lock);
|
2018-12-11 21:54:06 +08:00
|
|
|
}
|
|
|
|
|
2022-07-22 18:58:21 +08:00
|
|
|
unsigned long sbi_nputs(const char *str, unsigned long len)
|
|
|
|
{
|
2023-01-13 17:23:53 +08:00
|
|
|
unsigned long ret;
|
2022-07-22 18:58:21 +08:00
|
|
|
|
|
|
|
spin_lock(&console_out_lock);
|
2023-01-13 17:23:53 +08:00
|
|
|
ret = nputs(str, len);
|
2022-07-22 18:58:21 +08:00
|
|
|
spin_unlock(&console_out_lock);
|
|
|
|
|
2022-11-23 15:02:06 +08:00
|
|
|
return ret;
|
2022-07-22 18:58:21 +08:00
|
|
|
}
|
|
|
|
|
2018-12-11 21:54:06 +08:00
|
|
|
void sbi_gets(char *s, int maxwidth, char endchar)
|
|
|
|
{
|
2019-02-28 09:42:17 +08:00
|
|
|
int ch;
|
|
|
|
char *retval = s;
|
2018-12-21 17:12:58 +08:00
|
|
|
|
2019-02-28 09:42:17 +08:00
|
|
|
while ((ch = sbi_getc()) != endchar && ch >= 0 && maxwidth > 1) {
|
2019-04-11 08:41:52 +08:00
|
|
|
*retval = (char)ch;
|
2018-12-11 21:54:06 +08:00
|
|
|
retval++;
|
|
|
|
maxwidth--;
|
|
|
|
}
|
|
|
|
*retval = '\0';
|
|
|
|
}
|
|
|
|
|
2023-01-04 20:06:29 +08:00
|
|
|
unsigned long sbi_ngets(char *str, unsigned long len)
|
|
|
|
{
|
|
|
|
int ch;
|
|
|
|
unsigned long i;
|
|
|
|
|
|
|
|
for (i = 0; i < len; i++) {
|
|
|
|
ch = sbi_getc();
|
|
|
|
if (ch < 0)
|
|
|
|
break;
|
|
|
|
str[i] = ch;
|
|
|
|
}
|
|
|
|
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
2019-04-11 08:41:52 +08:00
|
|
|
#define PAD_RIGHT 1
|
|
|
|
#define PAD_ZERO 2
|
|
|
|
#define PAD_ALTERNATE 4
|
|
|
|
#define PRINT_BUF_LEN 64
|
2018-12-11 21:54:06 +08:00
|
|
|
|
2019-04-11 08:41:52 +08:00
|
|
|
#define va_start(v, l) __builtin_va_start((v), l)
|
|
|
|
#define va_end __builtin_va_end
|
|
|
|
#define va_arg __builtin_va_arg
|
|
|
|
typedef __builtin_va_list va_list;
|
2018-12-11 21:54:06 +08:00
|
|
|
|
|
|
|
static void printc(char **out, u32 *out_len, char ch)
|
|
|
|
{
|
2022-07-27 22:17:47 +08:00
|
|
|
if (!out) {
|
2018-12-11 21:54:06 +08:00
|
|
|
sbi_putc(ch);
|
2022-07-27 22:17:47 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The *printf entry point functions have enforced that (*out) can
|
|
|
|
* only be null when out_len is non-null and its value is zero.
|
|
|
|
*/
|
|
|
|
if (!out_len || *out_len > 1) {
|
|
|
|
*(*out)++ = ch;
|
|
|
|
**out = '\0';
|
2018-12-11 21:54:06 +08:00
|
|
|
}
|
2022-07-27 22:17:47 +08:00
|
|
|
|
|
|
|
if (out_len && *out_len > 0)
|
|
|
|
--(*out_len);
|
2018-12-11 21:54:06 +08:00
|
|
|
}
|
|
|
|
|
2019-04-11 08:41:52 +08:00
|
|
|
static int prints(char **out, u32 *out_len, const char *string, int width,
|
|
|
|
int flags)
|
2018-12-11 21:54:06 +08:00
|
|
|
{
|
2019-04-11 08:41:52 +08:00
|
|
|
int pc = 0;
|
2018-12-11 21:54:06 +08:00
|
|
|
char padchar = ' ';
|
|
|
|
|
|
|
|
if (width > 0) {
|
|
|
|
int len = 0;
|
|
|
|
const char *ptr;
|
|
|
|
for (ptr = string; *ptr; ++ptr)
|
|
|
|
++len;
|
|
|
|
if (len >= width)
|
|
|
|
width = 0;
|
|
|
|
else
|
|
|
|
width -= len;
|
|
|
|
if (flags & PAD_ZERO)
|
|
|
|
padchar = '0';
|
|
|
|
}
|
|
|
|
if (!(flags & PAD_RIGHT)) {
|
|
|
|
for (; width > 0; --width) {
|
|
|
|
printc(out, out_len, padchar);
|
|
|
|
++pc;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (; *string; ++string) {
|
|
|
|
printc(out, out_len, *string);
|
|
|
|
++pc;
|
|
|
|
}
|
|
|
|
for (; width > 0; --width) {
|
|
|
|
printc(out, out_len, padchar);
|
|
|
|
++pc;
|
|
|
|
}
|
|
|
|
|
|
|
|
return pc;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int printi(char **out, u32 *out_len, long long i, int b, int sg,
|
|
|
|
int width, int flags, int letbase)
|
|
|
|
{
|
|
|
|
char print_buf[PRINT_BUF_LEN];
|
|
|
|
char *s;
|
|
|
|
int neg = 0, pc = 0;
|
|
|
|
u64 t;
|
|
|
|
unsigned long long u = i;
|
|
|
|
|
|
|
|
if (sg && b == 10 && i < 0) {
|
|
|
|
neg = 1;
|
2019-04-11 08:41:52 +08:00
|
|
|
u = -i;
|
2018-12-11 21:54:06 +08:00
|
|
|
}
|
|
|
|
|
2019-04-11 08:41:52 +08:00
|
|
|
s = print_buf + PRINT_BUF_LEN - 1;
|
2018-12-11 21:54:06 +08:00
|
|
|
*s = '\0';
|
|
|
|
|
|
|
|
if (!u) {
|
|
|
|
*--s = '0';
|
|
|
|
} else {
|
|
|
|
while (u) {
|
|
|
|
t = u % b;
|
|
|
|
u = u / b;
|
|
|
|
if (t >= 10)
|
|
|
|
t += letbase - '0' - 10;
|
|
|
|
*--s = t + '0';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (flags & PAD_ALTERNATE) {
|
|
|
|
if ((b == 16) && (letbase == 'A')) {
|
|
|
|
*--s = 'X';
|
|
|
|
} else if ((b == 16) && (letbase == 'a')) {
|
|
|
|
*--s = 'x';
|
|
|
|
}
|
|
|
|
*--s = '0';
|
|
|
|
}
|
|
|
|
|
|
|
|
if (neg) {
|
|
|
|
if (width && (flags & PAD_ZERO)) {
|
|
|
|
printc(out, out_len, '-');
|
|
|
|
++pc;
|
|
|
|
--width;
|
|
|
|
} else {
|
|
|
|
*--s = '-';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return pc + prints(out, out_len, s, width, flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int print(char **out, u32 *out_len, const char *format, va_list args)
|
|
|
|
{
|
2023-01-13 17:23:53 +08:00
|
|
|
int width, flags, pc = 0;
|
|
|
|
char scr[2], *tout;
|
|
|
|
bool use_tbuf = (!out) ? true : false;
|
2018-12-11 21:54:06 +08:00
|
|
|
unsigned long long tmp;
|
|
|
|
|
2023-01-13 17:23:53 +08:00
|
|
|
/*
|
|
|
|
* The console_tbuf is protected by console_out_lock and
|
|
|
|
* print() is always called with console_out_lock held
|
|
|
|
* when out == NULL.
|
|
|
|
*/
|
|
|
|
if (use_tbuf) {
|
|
|
|
console_tbuf_len = CONSOLE_TBUF_MAX;
|
|
|
|
tout = console_tbuf;
|
|
|
|
out = &tout;
|
|
|
|
out_len = &console_tbuf_len;
|
|
|
|
}
|
|
|
|
|
2018-12-11 21:54:06 +08:00
|
|
|
for (; *format != 0; ++format) {
|
2023-01-13 17:23:53 +08:00
|
|
|
if (use_tbuf && !console_tbuf_len) {
|
|
|
|
nputs_all(console_tbuf, CONSOLE_TBUF_MAX);
|
|
|
|
console_tbuf_len = CONSOLE_TBUF_MAX;
|
|
|
|
tout = console_tbuf;
|
|
|
|
}
|
|
|
|
|
2018-12-11 21:54:06 +08:00
|
|
|
if (*format == '%') {
|
|
|
|
++format;
|
|
|
|
width = flags = 0;
|
|
|
|
if (*format == '\0')
|
|
|
|
break;
|
|
|
|
if (*format == '%')
|
2022-07-27 22:17:47 +08:00
|
|
|
goto literal;
|
2018-12-11 21:54:06 +08:00
|
|
|
/* Get flags */
|
|
|
|
if (*format == '-') {
|
|
|
|
++format;
|
|
|
|
flags = PAD_RIGHT;
|
|
|
|
}
|
|
|
|
if (*format == '#') {
|
|
|
|
++format;
|
|
|
|
flags |= PAD_ALTERNATE;
|
|
|
|
}
|
|
|
|
while (*format == '0') {
|
|
|
|
++format;
|
|
|
|
flags |= PAD_ZERO;
|
|
|
|
}
|
|
|
|
/* Get width */
|
|
|
|
for (; *format >= '0' && *format <= '9'; ++format) {
|
|
|
|
width *= 10;
|
|
|
|
width += *format - '0';
|
|
|
|
}
|
|
|
|
if (*format == 's') {
|
|
|
|
char *s = va_arg(args, char *);
|
2019-04-11 08:41:52 +08:00
|
|
|
pc += prints(out, out_len, s ? s : "(null)",
|
|
|
|
width, flags);
|
2018-12-11 21:54:06 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if ((*format == 'd') || (*format == 'i')) {
|
2019-04-11 08:41:52 +08:00
|
|
|
pc += printi(out, out_len, va_arg(args, int),
|
|
|
|
10, 1, width, flags, '0');
|
2018-12-11 21:54:06 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (*format == 'x') {
|
|
|
|
pc += printi(out, out_len,
|
2019-04-11 08:41:52 +08:00
|
|
|
va_arg(args, unsigned int), 16, 0,
|
|
|
|
width, flags, 'a');
|
2018-12-11 21:54:06 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (*format == 'X') {
|
|
|
|
pc += printi(out, out_len,
|
2019-04-11 08:41:52 +08:00
|
|
|
va_arg(args, unsigned int), 16, 0,
|
|
|
|
width, flags, 'A');
|
2018-12-11 21:54:06 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (*format == 'u') {
|
|
|
|
pc += printi(out, out_len,
|
2019-04-11 08:41:52 +08:00
|
|
|
va_arg(args, unsigned int), 10, 0,
|
|
|
|
width, flags, 'a');
|
2018-12-11 21:54:06 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (*format == 'p') {
|
|
|
|
pc += printi(out, out_len,
|
2019-04-11 08:41:52 +08:00
|
|
|
va_arg(args, unsigned long), 16, 0,
|
|
|
|
width, flags, 'a');
|
2018-12-11 21:54:06 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (*format == 'P') {
|
|
|
|
pc += printi(out, out_len,
|
2019-04-11 08:41:52 +08:00
|
|
|
va_arg(args, unsigned long), 16, 0,
|
|
|
|
width, flags, 'A');
|
2018-12-11 21:54:06 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (*format == 'l' && *(format + 1) == 'l') {
|
2022-07-28 00:30:05 +08:00
|
|
|
tmp = va_arg(args, unsigned long long);
|
2018-12-11 21:54:06 +08:00
|
|
|
if (*(format + 2) == 'u') {
|
|
|
|
format += 2;
|
2019-04-11 08:41:52 +08:00
|
|
|
pc += printi(out, out_len, tmp, 10, 0,
|
|
|
|
width, flags, 'a');
|
2018-12-11 21:54:06 +08:00
|
|
|
} else if (*(format + 2) == 'x') {
|
|
|
|
format += 2;
|
2019-04-11 08:41:52 +08:00
|
|
|
pc += printi(out, out_len, tmp, 16, 0,
|
|
|
|
width, flags, 'a');
|
2018-12-11 21:54:06 +08:00
|
|
|
} else if (*(format + 2) == 'X') {
|
|
|
|
format += 2;
|
2019-04-11 08:41:52 +08:00
|
|
|
pc += printi(out, out_len, tmp, 16, 0,
|
|
|
|
width, flags, 'A');
|
2018-12-11 21:54:06 +08:00
|
|
|
} else {
|
|
|
|
format += 1;
|
2019-04-11 08:41:52 +08:00
|
|
|
pc += printi(out, out_len, tmp, 10, 1,
|
|
|
|
width, flags, '0');
|
2018-12-11 21:54:06 +08:00
|
|
|
}
|
|
|
|
continue;
|
|
|
|
} else if (*format == 'l') {
|
2018-12-20 09:32:46 +08:00
|
|
|
if (*(format + 1) == 'u') {
|
|
|
|
format += 1;
|
2019-04-11 08:41:52 +08:00
|
|
|
pc += printi(
|
|
|
|
out, out_len,
|
|
|
|
va_arg(args, unsigned long), 10,
|
|
|
|
0, width, flags, 'a');
|
2018-12-20 09:32:46 +08:00
|
|
|
} else if (*(format + 1) == 'x') {
|
2018-12-11 21:54:06 +08:00
|
|
|
format += 1;
|
2019-04-11 08:41:52 +08:00
|
|
|
pc += printi(
|
|
|
|
out, out_len,
|
|
|
|
va_arg(args, unsigned long), 16,
|
|
|
|
0, width, flags, 'a');
|
2018-12-11 21:54:06 +08:00
|
|
|
} else if (*(format + 1) == 'X') {
|
|
|
|
format += 1;
|
2019-04-11 08:41:52 +08:00
|
|
|
pc += printi(
|
|
|
|
out, out_len,
|
|
|
|
va_arg(args, unsigned long), 16,
|
|
|
|
0, width, flags, 'A');
|
2018-12-11 21:54:06 +08:00
|
|
|
} else {
|
|
|
|
pc += printi(out, out_len,
|
2019-04-11 08:41:52 +08:00
|
|
|
va_arg(args, long), 10, 1,
|
|
|
|
width, flags, '0');
|
2018-12-11 21:54:06 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (*format == 'c') {
|
|
|
|
/* char are converted to int then pushed on the stack */
|
|
|
|
scr[0] = va_arg(args, int);
|
|
|
|
scr[1] = '\0';
|
|
|
|
pc += prints(out, out_len, scr, width, flags);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
} else {
|
2022-07-27 22:17:47 +08:00
|
|
|
literal:
|
2018-12-11 21:54:06 +08:00
|
|
|
printc(out, out_len, *format);
|
|
|
|
++pc;
|
|
|
|
}
|
|
|
|
}
|
2019-01-18 12:45:08 +08:00
|
|
|
|
2023-01-13 17:23:53 +08:00
|
|
|
if (use_tbuf && console_tbuf_len < CONSOLE_TBUF_MAX)
|
|
|
|
nputs_all(console_tbuf, CONSOLE_TBUF_MAX - console_tbuf_len);
|
|
|
|
|
2018-12-11 21:54:06 +08:00
|
|
|
return pc;
|
|
|
|
}
|
|
|
|
|
|
|
|
int sbi_sprintf(char *out, const char *format, ...)
|
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
int retval;
|
2019-01-18 12:45:08 +08:00
|
|
|
|
2022-07-27 22:17:47 +08:00
|
|
|
if (unlikely(!out))
|
|
|
|
sbi_panic("sbi_sprintf called with NULL output string\n");
|
|
|
|
|
2018-12-11 21:54:06 +08:00
|
|
|
va_start(args, format);
|
|
|
|
retval = print(&out, NULL, format, args);
|
|
|
|
va_end(args);
|
2019-01-18 12:45:08 +08:00
|
|
|
|
2018-12-11 21:54:06 +08:00
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
int sbi_snprintf(char *out, u32 out_sz, const char *format, ...)
|
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
int retval;
|
2019-01-18 12:45:08 +08:00
|
|
|
|
2022-07-27 22:17:47 +08:00
|
|
|
if (unlikely(!out && out_sz != 0))
|
|
|
|
sbi_panic("sbi_snprintf called with NULL output string and "
|
|
|
|
"output size is not zero\n");
|
|
|
|
|
2018-12-11 21:54:06 +08:00
|
|
|
va_start(args, format);
|
|
|
|
retval = print(&out, &out_sz, format, args);
|
|
|
|
va_end(args);
|
2019-01-18 12:45:08 +08:00
|
|
|
|
2018-12-11 21:54:06 +08:00
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
int sbi_printf(const char *format, ...)
|
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
int retval;
|
2018-12-21 17:12:58 +08:00
|
|
|
|
|
|
|
spin_lock(&console_out_lock);
|
2018-12-11 21:54:06 +08:00
|
|
|
va_start(args, format);
|
|
|
|
retval = print(NULL, NULL, format, args);
|
|
|
|
va_end(args);
|
2018-12-21 17:12:58 +08:00
|
|
|
spin_unlock(&console_out_lock);
|
|
|
|
|
2018-12-11 21:54:06 +08:00
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2020-03-27 14:46:16 +08:00
|
|
|
int sbi_dprintf(const char *format, ...)
|
2019-08-08 14:40:22 +08:00
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
int retval = 0;
|
2020-03-27 14:46:16 +08:00
|
|
|
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
|
2019-08-08 14:40:22 +08:00
|
|
|
|
|
|
|
va_start(args, format);
|
2021-08-28 14:45:02 +08:00
|
|
|
if (scratch->options & SBI_SCRATCH_DEBUG_PRINTS) {
|
|
|
|
spin_lock(&console_out_lock);
|
2019-08-08 14:40:22 +08:00
|
|
|
retval = print(NULL, NULL, format, args);
|
2021-08-28 14:45:02 +08:00
|
|
|
spin_unlock(&console_out_lock);
|
|
|
|
}
|
2019-08-08 14:40:22 +08:00
|
|
|
va_end(args);
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
lib: sbi: Improve fatal error handling
BUG and BUG_ON are not informative and are rather lazy interfaces, only
telling the user that something went wrong in a given function, but not
what, requiring the user to find the sources corresponding to their
firmware (which may not be available) and figure out how that BUG(_ON)
was hit. Even SBI_ASSERT in its current form, which does include the
condition that triggered it in the output, isn't necessarily very
informative. In some cases, the error may be fixable by the user, but
they need to know the problem in order to have any hope of fixing it.
It's also a nuisance for developers, whose development trees may have
changed significantly since the release in question being used, and so
line numbers can make it harder for them to understand which error case
a user has hit.
This patch introduces a new sbi_panic function which is printf-like,
allowing detailed error messages to be printed to the console. BUG and
BUG_ON are removed, since the former is just a worse form of sbi_panic
and the latter is a worse version of SBI_ASSERT. Finally, SBI_ASSERT is
augmented to take a set of arguments to pass to sbi_panic on failure,
used like so (sbi_boot_print_hart's current error case, which currently
manually calls sbi_printf and sbi_hart_hang):
SBI_ASSERT(xlen >= 1, ("Error %d getting MISA XLEN\n", xlen));
The existing users of BUG are replaced with calls to sbi_panic along
with informative error messages. BUG_ON and SBI_ASSERT were unused (and,
in the case of SBI_ASSERT, remain unused).
Many existing users of sbi_hart_hang should be converted to use either
sbi_panic or SBI_ASSERT after this commit.
Signed-off-by: Jessica Clarke <jrtc27@jrtc27.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2021-11-22 01:30:22 +08:00
|
|
|
void sbi_panic(const char *format, ...)
|
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
|
|
|
|
spin_lock(&console_out_lock);
|
|
|
|
va_start(args, format);
|
|
|
|
print(NULL, NULL, format, args);
|
|
|
|
va_end(args);
|
|
|
|
spin_unlock(&console_out_lock);
|
|
|
|
|
|
|
|
sbi_hart_hang();
|
|
|
|
}
|
|
|
|
|
2021-04-21 20:33:50 +08:00
|
|
|
const struct sbi_console_device *sbi_console_get_device(void)
|
|
|
|
{
|
|
|
|
return console_dev;
|
|
|
|
}
|
|
|
|
|
|
|
|
void sbi_console_set_device(const struct sbi_console_device *dev)
|
2018-12-11 21:54:06 +08:00
|
|
|
{
|
2021-04-21 20:33:50 +08:00
|
|
|
if (!dev || console_dev)
|
|
|
|
return;
|
2018-12-11 21:54:06 +08:00
|
|
|
|
2021-04-21 20:33:50 +08:00
|
|
|
console_dev = dev;
|
|
|
|
}
|
|
|
|
|
|
|
|
int sbi_console_init(struct sbi_scratch *scratch)
|
|
|
|
{
|
|
|
|
return sbi_platform_console_init(sbi_platform_ptr(scratch));
|
2018-12-11 21:54:06 +08:00
|
|
|
}
|