[boot] Improve non-printing error handling

Add an implicit __LINE__ to the try_or_raise macro, which gets set in
r11 on cpu_assert. Also made status lines smarter about when to call
cpu_assert.
This commit is contained in:
Justin C. Miller
2021-01-20 01:18:31 -08:00
parent 847d7ab38d
commit 14aad62e02
6 changed files with 24 additions and 12 deletions

View File

@@ -35,27 +35,28 @@ message(uefi::status status)
}
[[ noreturn ]] static void
cpu_assert(uefi::status s, const wchar_t *message)
cpu_assert(uefi::status s, const wchar_t *message, size_t line)
{
asm volatile (
"movq $0xeeeeeeebadbadbad, %%r8;"
"movq %0, %%r9;"
"movq %1, %%r10;"
"movq %2, %%r11;"
"movq $0, %%rdx;"
"divq %%rdx;"
:
: "r"((uint64_t)s), "r"(message)
: "r"((uint64_t)s), "r"(message), "r"(line)
: "rax", "rdx", "r8", "r9", "r10");
while (1) asm("hlt");
}
[[ noreturn ]] void
raise(uefi::status status, const wchar_t *message)
raise(uefi::status status, const wchar_t *message, size_t line)
{
if(status_line::fail(message, status))
while (1) asm("hlt");
else
cpu_assert(status, message);
cpu_assert(status, message, line);
}

View File

@@ -12,7 +12,7 @@ class console;
namespace error {
/// Halt or exit the program with the given error status/message
[[ noreturn ]] void raise(uefi::status status, const wchar_t *message);
[[ noreturn ]] void raise(uefi::status status, const wchar_t *message, size_t line = 0);
const wchar_t * message(uefi::status status);
@@ -28,6 +28,6 @@ void debug_break();
#define try_or_raise(s, m) \
do { \
uefi::status _s = (s); \
if (uefi::is_error(_s)) ::boot::error::raise(_s, (m)); \
if (uefi::is_error(_s)) ::boot::error::raise(_s, (m), __LINE__); \
} while(0)

View File

@@ -163,7 +163,7 @@ uefi_preboot(uefi::handle image, uefi::system_table *st)
memory::efi_mem_map
uefi_exit(args::header *args, uefi::handle image, uefi::boot_services *bs)
{
status_line status {L"Exiting UEFI"};
status_line status {L"Exiting UEFI", nullptr, false};
memory::efi_mem_map map =
memory::build_kernel_mem_map(args, bs);

View File

@@ -118,7 +118,7 @@ private:
if (!(parent_ent & 1)) {
if (!m_cache_count--)
error::raise(uefi::status::out_of_resources, L"Page table cache empty");
error::raise(uefi::status::out_of_resources, L"Page table cache empty", 0x7ab1e5);
page_table *table = reinterpret_cast<page_table*>(m_page_cache);
m_page_cache = offset_ptr<void>(m_page_cache, page_size);

View File

@@ -30,7 +30,8 @@ status *status::s_current = nullptr;
unsigned status::s_current_type = 0;
unsigned status_bar::s_count = 0;
status_line::status_line(const wchar_t *message, const wchar_t *context) :
status_line::status_line(const wchar_t *message, const wchar_t *context, bool fails_clean) :
status(fails_clean),
m_level(level_ok),
m_depth(0),
m_outer(nullptr)
@@ -148,6 +149,7 @@ status_line::do_fail(const wchar_t *message, uefi::status status)
status_bar::status_bar(kernel::args::framebuffer const &fb) :
status(fb.size),
m_outer(nullptr)
{
m_size = (fb.vertical / num_boxes) - 1;

View File

@@ -17,6 +17,8 @@ namespace boot {
class status
{
public:
status(bool fails_clean = true) : m_fails_clean(fails_clean) {}
virtual void do_warn(const wchar_t *message, uefi::status status) = 0;
virtual void do_fail(const wchar_t *message, uefi::status status) = 0;
@@ -28,7 +30,7 @@ public:
inline static bool warn(const wchar_t *message, uefi::status status = uefi::status::success) {
if (!s_current) return false;
s_current->do_warn(message, status);
return true;
return s_current->m_fails_clean;
}
/// Set the state to error, and print a message. If the state is already at
@@ -39,12 +41,15 @@ public:
inline static bool fail(const wchar_t *message, uefi::status status) {
if (!s_current) return false;
s_current->do_fail(message, status);
return true;
return s_current->m_fails_clean;
}
protected:
static status *s_current;
static unsigned s_current_type;
private:
bool m_fails_clean;
};
/// Scoped status line reporter. Prints a message and an "OK" if no errors
@@ -59,7 +64,11 @@ public:
/// Constructor.
/// \arg message Description of the operation in progress
/// \arg context If non-null, printed after `message` and a colon
status_line(const wchar_t *message, const wchar_t *context = nullptr);
/// \arg fails_clean If true, this object can handle printing failure
status_line(
const wchar_t *message,
const wchar_t *context = nullptr,
bool fails_clean = true);
~status_line();
virtual void do_warn(const wchar_t *message, uefi::status status) override;