The symbol table needs to be passed to the panic handler very early in the kernel, loading it in init is far less useful. Return it to the boot directory and remove it from the initrd.
287 lines
6.8 KiB
C++
287 lines
6.8 KiB
C++
#include <uefi/types.h>
|
|
#include <uefi/graphics.h>
|
|
#include <uefi/protos/simple_text_output.h>
|
|
|
|
#include "console.h"
|
|
#include "error.h"
|
|
#include "status.h"
|
|
#include "video.h"
|
|
|
|
constexpr int num_boxes = 30;
|
|
|
|
namespace boot {
|
|
|
|
static constexpr int level_ok = 1;
|
|
static constexpr int level_warn = 2;
|
|
static constexpr int level_fail = 3;
|
|
|
|
static const wchar_t *level_tags[] = {
|
|
L" ",
|
|
L" ok ",
|
|
L" warn ",
|
|
L"failed"
|
|
};
|
|
|
|
static const uefi::attribute level_colors[] = {
|
|
uefi::attribute::green,
|
|
uefi::attribute::green,
|
|
uefi::attribute::brown,
|
|
uefi::attribute::light_red
|
|
};
|
|
|
|
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, bool fails_clean) :
|
|
status(fails_clean),
|
|
m_level(0),
|
|
m_depth(0),
|
|
m_outer(nullptr)
|
|
{
|
|
if (status::s_current_type == status_line::type) {
|
|
m_outer = static_cast<status_line*>(s_current);
|
|
m_depth = (m_outer ? 1 + m_outer->m_depth : 0);
|
|
}
|
|
s_current = this;
|
|
s_current_type = status_line::type;
|
|
|
|
auto out = console::get().m_out;
|
|
m_line = out->mode->cursor_row;
|
|
|
|
int indent = 2 * m_depth;
|
|
out->set_cursor_position(indent, m_line);
|
|
out->set_attribute(uefi::attribute::light_gray);
|
|
out->output_string(message);
|
|
|
|
if (context) {
|
|
out->output_string(L": ");
|
|
out->output_string(context);
|
|
}
|
|
|
|
out->output_string(L"\r\n");
|
|
print_status_tag();
|
|
}
|
|
|
|
status_line::~status_line()
|
|
{
|
|
if (s_current != this)
|
|
error::raise(uefi::status::unsupported, L"Destroying non-current status_line");
|
|
|
|
if (m_outer && m_level > m_outer->m_level) {
|
|
m_outer->m_level = m_level;
|
|
m_outer->print_status_tag();
|
|
}
|
|
|
|
if (m_level < level_ok) {
|
|
m_level = level_ok;
|
|
print_status_tag();
|
|
}
|
|
|
|
s_current = m_outer;
|
|
}
|
|
|
|
void
|
|
status_line::print_status_tag()
|
|
{
|
|
auto out = console::get().m_out;
|
|
int row = out->mode->cursor_row;
|
|
int col = out->mode->cursor_column;
|
|
|
|
uefi::attribute color = level_colors[m_level];
|
|
const wchar_t *tag = level_tags[m_level];
|
|
|
|
out->set_cursor_position(50, m_line);
|
|
|
|
out->set_attribute(uefi::attribute::light_gray);
|
|
out->output_string(L"[");
|
|
out->set_attribute(color);
|
|
out->output_string(tag);
|
|
out->set_attribute(uefi::attribute::light_gray);
|
|
out->output_string(L"]\r\n");
|
|
|
|
out->set_cursor_position(col, row);
|
|
}
|
|
|
|
void
|
|
status_line::do_warn(const wchar_t *message, uefi::status status)
|
|
{
|
|
auto out = console::get().m_out;
|
|
int row = out->mode->cursor_row;
|
|
|
|
if (m_level < level_warn) {
|
|
m_level = level_warn;
|
|
print_status_tag();
|
|
}
|
|
|
|
int indent = 2 + 2 * m_depth;
|
|
out->set_cursor_position(indent, row);
|
|
out->set_attribute(uefi::attribute::yellow);
|
|
out->output_string(message);
|
|
|
|
const wchar_t *error = error::message(status);
|
|
if (error) {
|
|
out->output_string(L": ");
|
|
out->output_string(error);
|
|
}
|
|
|
|
out->set_attribute(uefi::attribute::light_gray);
|
|
out->output_string(L"\r\n");
|
|
}
|
|
|
|
void
|
|
status_line::do_fail(const wchar_t *message, uefi::status status)
|
|
{
|
|
auto out = console::get().m_out;
|
|
int row = out->mode->cursor_row;
|
|
|
|
if (m_level < level_fail) {
|
|
m_level = level_fail;
|
|
print_status_tag();
|
|
}
|
|
|
|
int indent = 2 + 2 * m_depth;
|
|
out->set_cursor_position(indent, row);
|
|
out->set_attribute(uefi::attribute::red);
|
|
out->output_string(message);
|
|
|
|
const wchar_t *error = error::message(status);
|
|
if (error) {
|
|
out->output_string(L": ");
|
|
out->output_string(error);
|
|
}
|
|
|
|
out->set_attribute(uefi::attribute::light_gray);
|
|
out->output_string(L"\r\n");
|
|
}
|
|
|
|
void
|
|
status_line::do_blank()
|
|
{
|
|
m_level = level_ok; // Keep print_status_tag from happening in dtor
|
|
|
|
auto out = console::get().m_out;
|
|
int row = out->mode->cursor_row;
|
|
|
|
out->set_cursor_position(0, row);
|
|
out->output_string(L"\r\n\r\n");
|
|
}
|
|
|
|
|
|
|
|
status_bar::status_bar(video::screen *screen) :
|
|
status(),
|
|
m_outer(nullptr)
|
|
{
|
|
m_size = (screen->mode.vertical / num_boxes) - 1;
|
|
m_top = screen->mode.vertical - m_size;
|
|
m_horiz = screen->mode.horizontal;
|
|
m_fb = reinterpret_cast<uint32_t*>(screen->framebuffer.pointer);
|
|
m_type = static_cast<uint16_t>(screen->mode.layout);
|
|
next();
|
|
|
|
if (status::s_current_type == status_bar::type)
|
|
m_outer = static_cast<status_bar*>(s_current);
|
|
s_current = this;
|
|
s_current_type = status_bar::type;
|
|
}
|
|
|
|
status_bar::~status_bar()
|
|
{
|
|
if (s_current != this)
|
|
error::raise(uefi::status::unsupported, L"Destroying non-current status_bar");
|
|
draw_box();
|
|
s_current = m_outer;
|
|
}
|
|
|
|
void
|
|
status_bar::do_warn(const wchar_t *message, uefi::status status)
|
|
{
|
|
m_status = status;
|
|
if (m_level < level_warn) {
|
|
m_level = level_warn;
|
|
draw_box();
|
|
}
|
|
}
|
|
|
|
void
|
|
status_bar::do_fail(const wchar_t *message, uefi::status status)
|
|
{
|
|
m_status = status;
|
|
if (m_level < level_fail) {
|
|
m_level = level_fail;
|
|
draw_box();
|
|
}
|
|
}
|
|
|
|
static uint32_t
|
|
make_color(uint8_t r, uint8_t g, uint8_t b, uint16_t type)
|
|
{
|
|
switch (static_cast<video::layout>(type)) {
|
|
case video::layout::bgr8:
|
|
return
|
|
(static_cast<uint32_t>(b) << 0) |
|
|
(static_cast<uint32_t>(g) << 8) |
|
|
(static_cast<uint32_t>(r) << 16);
|
|
|
|
case video::layout::rgb8:
|
|
return
|
|
(static_cast<uint32_t>(r) << 0) |
|
|
(static_cast<uint32_t>(g) << 8) |
|
|
(static_cast<uint32_t>(b) << 16);
|
|
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
void
|
|
status_bar::draw_box()
|
|
{
|
|
static const uint32_t colors[] = {0x909090, 0xf0f0f0};
|
|
constexpr unsigned ncolors = sizeof(colors) / sizeof(uint32_t);
|
|
|
|
if (m_fb == nullptr)
|
|
return;
|
|
|
|
unsigned x0 = m_current * m_size;
|
|
unsigned x1 = x0 + m_size - 3;
|
|
unsigned y0 = m_top;
|
|
unsigned y1 = m_top + m_size - 3;
|
|
|
|
uint32_t color = 0;
|
|
switch (m_level) {
|
|
case level_ok:
|
|
color = colors[m_current % ncolors];
|
|
break;
|
|
case level_warn:
|
|
color = make_color(0xff, 0xb2, 0x34, m_type);
|
|
break;
|
|
case level_fail:
|
|
color = make_color(0xfb, 0x0a, 0x1e, m_type);
|
|
break;
|
|
default:
|
|
color = 0;
|
|
}
|
|
|
|
for (unsigned y = y0; y < y1; ++y)
|
|
for (unsigned x = x0; x < x1; ++x)
|
|
m_fb[y * m_horiz + x] = color;
|
|
|
|
if (m_level > level_ok) {
|
|
unsigned nbars = static_cast<uint64_t>(m_status) & 0xffff;
|
|
constexpr unsigned bar_height = 4;
|
|
|
|
for (unsigned i = 1; i <= nbars; ++i) {
|
|
y0 = m_top - 2 * i * bar_height;
|
|
y1 = y0 + bar_height;
|
|
|
|
for (unsigned y = y0; y < y1; ++y)
|
|
for (unsigned x = x0; x < x1; ++x)
|
|
m_fb[y * m_horiz + x] = color;
|
|
}
|
|
}
|
|
}
|
|
|
|
} // namespace boot
|