[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 [[ 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 ( asm volatile (
"movq $0xeeeeeeebadbadbad, %%r8;" "movq $0xeeeeeeebadbadbad, %%r8;"
"movq %0, %%r9;" "movq %0, %%r9;"
"movq %1, %%r10;" "movq %1, %%r10;"
"movq %2, %%r11;"
"movq $0, %%rdx;" "movq $0, %%rdx;"
"divq %%rdx;" "divq %%rdx;"
: :
: "r"((uint64_t)s), "r"(message) : "r"((uint64_t)s), "r"(message), "r"(line)
: "rax", "rdx", "r8", "r9", "r10"); : "rax", "rdx", "r8", "r9", "r10");
while (1) asm("hlt"); while (1) asm("hlt");
} }
[[ noreturn ]] void [[ 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)) if(status_line::fail(message, status))
while (1) asm("hlt"); while (1) asm("hlt");
else else
cpu_assert(status, message); cpu_assert(status, message, line);
} }

View File

@@ -12,7 +12,7 @@ class console;
namespace error { namespace error {
/// Halt or exit the program with the given error status/message /// 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); const wchar_t * message(uefi::status status);
@@ -28,6 +28,6 @@ void debug_break();
#define try_or_raise(s, m) \ #define try_or_raise(s, m) \
do { \ do { \
uefi::status _s = (s); \ 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) } while(0)

View File

@@ -163,7 +163,7 @@ uefi_preboot(uefi::handle image, uefi::system_table *st)
memory::efi_mem_map memory::efi_mem_map
uefi_exit(args::header *args, uefi::handle image, uefi::boot_services *bs) 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::efi_mem_map map =
memory::build_kernel_mem_map(args, bs); memory::build_kernel_mem_map(args, bs);

View File

@@ -118,7 +118,7 @@ private:
if (!(parent_ent & 1)) { if (!(parent_ent & 1)) {
if (!m_cache_count--) 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); page_table *table = reinterpret_cast<page_table*>(m_page_cache);
m_page_cache = offset_ptr<void>(m_page_cache, page_size); 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::s_current_type = 0;
unsigned status_bar::s_count = 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_level(level_ok),
m_depth(0), m_depth(0),
m_outer(nullptr) 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_bar::status_bar(kernel::args::framebuffer const &fb) :
status(fb.size),
m_outer(nullptr) m_outer(nullptr)
{ {
m_size = (fb.vertical / num_boxes) - 1; m_size = (fb.vertical / num_boxes) - 1;

View File

@@ -17,6 +17,8 @@ namespace boot {
class status class status
{ {
public: 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_warn(const wchar_t *message, uefi::status status) = 0;
virtual void do_fail(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) { inline static bool warn(const wchar_t *message, uefi::status status = uefi::status::success) {
if (!s_current) return false; if (!s_current) return false;
s_current->do_warn(message, status); 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 /// 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) { inline static bool fail(const wchar_t *message, uefi::status status) {
if (!s_current) return false; if (!s_current) return false;
s_current->do_fail(message, status); s_current->do_fail(message, status);
return true; return s_current->m_fails_clean;
} }
protected: protected:
static status *s_current; static status *s_current;
static unsigned s_current_type; static unsigned s_current_type;
private:
bool m_fails_clean;
}; };
/// Scoped status line reporter. Prints a message and an "OK" if no errors /// Scoped status line reporter. Prints a message and an "OK" if no errors
@@ -59,7 +64,11 @@ public:
/// Constructor. /// Constructor.
/// \arg message Description of the operation in progress /// \arg message Description of the operation in progress
/// \arg context If non-null, printed after `message` and a colon /// \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(); ~status_line();
virtual void do_warn(const wchar_t *message, uefi::status status) override; virtual void do_warn(const wchar_t *message, uefi::status status) override;