Turning console into a class

This commit is contained in:
Justin C. Miller
2019-02-04 00:48:18 -08:00
parent d19cedb12a
commit 863e5bda15
6 changed files with 161 additions and 113 deletions

View File

@@ -1,4 +1,3 @@
#include <stdarg.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
@@ -9,16 +8,55 @@
size_t ROWS = 0; size_t ROWS = 0;
size_t COLS = 0; size_t COLS = 0;
static EFI_SIMPLE_TEXT_OUT_PROTOCOL *con_out = 0; static EFI_SIMPLE_TEXT_OUT_PROTOCOL *m_out = 0;
const wchar_t digits[] = {u'0', u'1', u'2', u'3', u'4', u'5', u'6', u'7', u'8', u'9', u'a', u'b', u'c', u'd', u'e', u'f'}; static const wchar_t digits[] = {u'0', u'1', u'2', u'3', u'4', u'5',
u'6', u'7', u'8', u'9', u'a', u'b', u'c', u'd', u'e', u'f'};
console::console(EFI_SYSTEM_TABLE *system_table) :
m_rows(0),
m_cols(0),
m_out(nullptr)
{
s_console = this;
m_boot = system_table->BootServices;
m_out = system_table->ConOut;
}
EFI_STATUS EFI_STATUS
con_pick_mode(EFI_BOOT_SERVICES *bootsvc) console::initialize(const wchar_t *version)
{
EFI_STATUS status;
// Might not find a video device at all, so ignore not found errors
status = pick_mode();
if (status != EFI_NOT_FOUND)
CHECK_EFI_STATUS_OR_FAIL(status);
status = m_out->QueryMode(m_out, m_out->Mode->Mode, &m_cols, &m_rows);
CHECK_EFI_STATUS_OR_RETURN(status, "QueryMode");
status = m_out->ClearScreen(m_out);
CHECK_EFI_STATUS_OR_RETURN(status, "ClearScreen");
m_out->SetAttribute(m_out, EFI_LIGHTCYAN);
m_out->OutputString(m_out, (wchar_t *)L"Popcorn loader ");
m_out->SetAttribute(m_out, EFI_LIGHTMAGENTA);
m_out->OutputString(m_out, (wchar_t *)version);
m_out->SetAttribute(m_out, EFI_LIGHTGRAY);
m_out->OutputString(m_out, (wchar_t *)L" booting...\r\n\n");
return status;
}
EFI_STATUS
console::pick_mode()
{ {
EFI_STATUS status; EFI_STATUS status;
EFI_GRAPHICS_OUTPUT_PROTOCOL *gfx_out_proto; EFI_GRAPHICS_OUTPUT_PROTOCOL *gfx_out_proto;
status = bootsvc->LocateProtocol(&guid_gfx_out, NULL, (void **)&gfx_out_proto); status = m_boot->LocateProtocol(&guid_gfx_out, NULL, (void **)&gfx_out_proto);
CHECK_EFI_STATUS_OR_RETURN(status, "LocateProtocol gfx"); CHECK_EFI_STATUS_OR_RETURN(status, "LocateProtocol gfx");
const uint32_t modes = gfx_out_proto->Mode->MaxMode; const uint32_t modes = gfx_out_proto->Mode->MaxMode;
@@ -53,39 +91,8 @@ con_pick_mode(EFI_BOOT_SERVICES *bootsvc)
return EFI_SUCCESS; return EFI_SUCCESS;
} }
EFI_STATUS
con_initialize(EFI_SYSTEM_TABLE *system_table, const wchar_t *version)
{
EFI_STATUS status;
EFI_BOOT_SERVICES *bootsvc = system_table->BootServices;
con_out = system_table->ConOut;
// Might not find a video device at all, so ignore not found errors
status = con_pick_mode(bootsvc);
if (status != EFI_NOT_FOUND)
CHECK_EFI_STATUS_OR_RETURN(status, "con_pick_mode");
status = con_out->QueryMode(con_out, con_out->Mode->Mode, &COLS, &ROWS);
CHECK_EFI_STATUS_OR_RETURN(status, "QueryMode");
status = con_out->ClearScreen(con_out);
CHECK_EFI_STATUS_OR_RETURN(status, "ClearScreen");
con_out->SetAttribute(con_out, EFI_LIGHTCYAN);
con_out->OutputString(con_out, (wchar_t *)L"Popcorn loader ");
con_out->SetAttribute(con_out, EFI_LIGHTMAGENTA);
con_out->OutputString(con_out, (wchar_t *)version);
con_out->SetAttribute(con_out, EFI_LIGHTGRAY);
con_out->OutputString(con_out, (wchar_t *)L" booting...\r\n\n");
return status;
}
size_t size_t
con_print_hex(uint32_t n) console::print_hex(uint32_t n) const
{ {
wchar_t buffer[9]; wchar_t buffer[9];
wchar_t *p = buffer; wchar_t *p = buffer;
@@ -94,12 +101,12 @@ con_print_hex(uint32_t n)
*p++ = digits[nibble]; *p++ = digits[nibble];
} }
*p = 0; *p = 0;
con_out->OutputString(con_out, buffer); m_out->OutputString(m_out, buffer);
return 8; return 8;
} }
size_t size_t
con_print_long_hex(uint64_t n) console::print_long_hex(uint64_t n) const
{ {
wchar_t buffer[17]; wchar_t buffer[17];
wchar_t *p = buffer; wchar_t *p = buffer;
@@ -108,12 +115,12 @@ con_print_long_hex(uint64_t n)
*p++ = digits[nibble]; *p++ = digits[nibble];
} }
*p = 0; *p = 0;
con_out->OutputString(con_out, buffer); m_out->OutputString(m_out, buffer);
return 16; return 16;
} }
size_t size_t
con_print_dec(uint32_t n) console::print_dec(uint32_t n) const
{ {
wchar_t buffer[11]; wchar_t buffer[11];
wchar_t *p = buffer + 10; wchar_t *p = buffer + 10;
@@ -123,12 +130,12 @@ con_print_dec(uint32_t n)
n /= 10; n /= 10;
} while (n != 0); } while (n != 0);
con_out->OutputString(con_out, ++p); m_out->OutputString(m_out, ++p);
return 10 - (p - buffer); return 10 - (p - buffer);
} }
size_t size_t
con_print_long_dec(uint64_t n) console::print_long_dec(uint64_t n) const
{ {
wchar_t buffer[21]; wchar_t buffer[21];
wchar_t *p = buffer + 20; wchar_t *p = buffer + 20;
@@ -138,21 +145,18 @@ con_print_long_dec(uint64_t n)
n /= 10; n /= 10;
} while (n != 0); } while (n != 0);
con_out->OutputString(con_out, ++p); m_out->OutputString(m_out, ++p);
return 20 - (p - buffer); return 20 - (p - buffer);
} }
size_t size_t
con_printf(const wchar_t *fmt, ...) console::vprintf(const wchar_t *fmt, va_list args) const
{ {
wchar_t buffer[256]; wchar_t buffer[256];
const wchar_t *r = fmt; const wchar_t *r = fmt;
wchar_t *w = buffer; wchar_t *w = buffer;
va_list args;
size_t count = 0; size_t count = 0;
va_start(args, fmt);
while (r && *r) { while (r && *r) {
if (*r != L'%') { if (*r != L'%') {
count++; count++;
@@ -161,43 +165,43 @@ con_printf(const wchar_t *fmt, ...)
} }
*w = 0; *w = 0;
con_out->OutputString(con_out, buffer); m_out->OutputString(m_out, buffer);
w = buffer; w = buffer;
r++; // chomp the % r++; // chomp the %
switch (*r++) { switch (*r++) {
case L'%': case L'%':
con_out->OutputString(con_out, const_cast<wchar_t*>(L"%")); m_out->OutputString(m_out, const_cast<wchar_t*>(L"%"));
count++; count++;
break; break;
case L'x': case L'x':
count += con_print_hex(va_arg(args, uint32_t)); count += print_hex(va_arg(args, uint32_t));
break; break;
case L'd': case L'd':
case L'u': case L'u':
count += con_print_dec(va_arg(args, uint32_t)); count += print_dec(va_arg(args, uint32_t));
break; break;
case L's': case L's':
{ {
wchar_t *s = va_arg(args, wchar_t*); wchar_t *s = va_arg(args, wchar_t*);
count += wstrlen(s); count += wstrlen(s);
con_out->OutputString(con_out, s); m_out->OutputString(m_out, s);
} }
break; break;
case L'l': case L'l':
switch (*r++) { switch (*r++) {
case L'x': case L'x':
count += con_print_long_hex(va_arg(args, uint64_t)); count += print_long_hex(va_arg(args, uint64_t));
break; break;
case L'd': case L'd':
case L'u': case L'u':
count += con_print_long_dec(va_arg(args, uint64_t)); count += print_long_dec(va_arg(args, uint64_t));
break; break;
default: default:
@@ -211,44 +215,66 @@ con_printf(const wchar_t *fmt, ...)
} }
*w = 0; *w = 0;
con_out->OutputString(con_out, buffer); m_out->OutputString(m_out, buffer);
va_end(args);
return count; return count;
} }
void size_t
con_status_begin(const wchar_t *message) console::printf(const wchar_t *fmt, ...) const
{ {
con_out->SetAttribute(con_out, EFI_LIGHTGRAY); va_list args;
con_out->OutputString(con_out, (wchar_t *)message); va_start(args, fmt);
size_t result = vprintf(fmt, args);
va_end(args);
return result;
}
size_t
console::print(const wchar_t *fmt, ...)
{
va_list args;
va_start(args, fmt);
size_t result = get().vprintf(fmt, args);
va_end(args);
return result;
} }
void void
con_status_ok() console::status_begin(const wchar_t *message) const
{ {
con_out->SetAttribute(con_out, EFI_LIGHTGRAY); m_out->SetAttribute(m_out, EFI_LIGHTGRAY);
con_out->OutputString(con_out, (wchar_t *)L"["); m_out->OutputString(m_out, (wchar_t *)message);
con_out->SetAttribute(con_out, EFI_GREEN);
con_out->OutputString(con_out, (wchar_t *)L" ok ");
con_out->SetAttribute(con_out, EFI_LIGHTGRAY);
con_out->OutputString(con_out, (wchar_t *)L"]\r\n");
} }
void void
con_status_fail(const wchar_t *error) console::status_ok() const
{ {
con_out->SetAttribute(con_out, EFI_LIGHTGRAY); m_out->SetAttribute(m_out, EFI_LIGHTGRAY);
con_out->OutputString(con_out, (wchar_t *)L"["); m_out->OutputString(m_out, (wchar_t *)L"[");
con_out->SetAttribute(con_out, EFI_LIGHTRED); m_out->SetAttribute(m_out, EFI_GREEN);
con_out->OutputString(con_out, (wchar_t *)L"failed"); m_out->OutputString(m_out, (wchar_t *)L" ok ");
con_out->SetAttribute(con_out, EFI_LIGHTGRAY); m_out->SetAttribute(m_out, EFI_LIGHTGRAY);
con_out->OutputString(con_out, (wchar_t *)L"]\r\n"); m_out->OutputString(m_out, (wchar_t *)L"]\r\n");
}
con_out->SetAttribute(con_out, EFI_RED); void
con_out->OutputString(con_out, (wchar_t *)error); console::status_fail(const wchar_t *error) const
con_out->SetAttribute(con_out, EFI_LIGHTGRAY); {
con_out->OutputString(con_out, (wchar_t *)L"\r\n"); m_out->SetAttribute(m_out, EFI_LIGHTGRAY);
m_out->OutputString(m_out, (wchar_t *)L"[");
m_out->SetAttribute(m_out, EFI_LIGHTRED);
m_out->OutputString(m_out, (wchar_t *)L"failed");
m_out->SetAttribute(m_out, EFI_LIGHTGRAY);
m_out->OutputString(m_out, (wchar_t *)L"]\r\n");
m_out->SetAttribute(m_out, EFI_RED);
m_out->OutputString(m_out, (wchar_t *)error);
m_out->SetAttribute(m_out, EFI_LIGHTGRAY);
m_out->OutputString(m_out, (wchar_t *)L"\r\n");
} }
EFI_STATUS EFI_STATUS

View File

@@ -1,12 +1,38 @@
#pragma once #pragma once
#include <stdarg.h>
#include <stddef.h> #include <stddef.h>
#include <efi/efi.h> #include <efi/efi.h>
EFI_STATUS con_initialize(EFI_SYSTEM_TABLE *system_table, const wchar_t *version); class console
void con_status_begin(const wchar_t *message); {
void con_status_ok(); public:
void con_status_fail(const wchar_t *error); console(EFI_SYSTEM_TABLE *system_table);
size_t con_printf(const wchar_t *fmt, ...);
EFI_STATUS initialize(const wchar_t *version);
void status_begin(const wchar_t *message) const;
void status_fail(const wchar_t *error) const;
void status_ok() const;
size_t print_hex(uint32_t n) const;
size_t print_dec(uint32_t n) const;
size_t print_long_hex(uint64_t n) const;
size_t print_long_dec(uint64_t n) const;
size_t printf(const wchar_t *fmt, ...) const;
static const console & get() { return *s_console; }
static size_t print(const wchar_t *fmt, ...);
private:
EFI_STATUS pick_mode();
size_t vprintf(const wchar_t *fmt, va_list args) const;
size_t m_rows, m_cols;
EFI_BOOT_SERVICES *m_boot;
EFI_SIMPLE_TEXT_OUT_PROTOCOL *m_out;
static console *s_console;
};
EFI_STATUS EFI_STATUS
con_get_framebuffer( con_get_framebuffer(

View File

@@ -141,7 +141,6 @@ loader_load_elf(
struct elf_program_header prog_header; struct elf_program_header prog_header;
for (int i = 0; i < header.ph_num; ++i) { for (int i = 0; i < header.ph_num; ++i) {
con_debug(L"Reading ELF program header %d\r\n", i);
status = file->SetPosition(file, header.ph_offset + i * header.ph_entsize); status = file->SetPosition(file, header.ph_offset + i * header.ph_entsize);
CHECK_EFI_STATUS_OR_RETURN(status, L"Setting ELF file position"); CHECK_EFI_STATUS_OR_RETURN(status, L"Setting ELF file position");
@@ -161,11 +160,10 @@ loader_load_elf(
data->kernel = addr; data->kernel = addr;
data->kernel_length = (uint64_t)addr + length - (uint64_t)data->kernel; data->kernel_length = (uint64_t)addr + length - (uint64_t)data->kernel;
} }
con_debug(L"Read %d ELF program headers\r\n", header.ph_num);
struct elf_section_header sec_header; struct elf_section_header sec_header;
for (int i = 0; i < header.sh_num; ++i) { for (int i = 0; i < header.sh_num; ++i) {
con_debug(L"Reading ELF section header %d ", i);
status = file->SetPosition(file, header.sh_offset + i * header.sh_entsize); status = file->SetPosition(file, header.sh_offset + i * header.sh_entsize);
CHECK_EFI_STATUS_OR_RETURN(status, L"Setting ELF file position"); CHECK_EFI_STATUS_OR_RETURN(status, L"Setting ELF file position");
@@ -174,14 +172,12 @@ loader_load_elf(
CHECK_EFI_STATUS_OR_RETURN(status, L"Reading ELF section header"); CHECK_EFI_STATUS_OR_RETURN(status, L"Reading ELF section header");
if ((sec_header.flags & ELF_SHF_ALLOC) == 0) { if ((sec_header.flags & ELF_SHF_ALLOC) == 0) {
con_debug(L"SHF_ALLOC section\r\n");
continue; continue;
} }
void *addr = (void *)(sec_header.addr - KERNEL_VIRT_ADDRESS); void *addr = (void *)(sec_header.addr - KERNEL_VIRT_ADDRESS);
if (sec_header.type == ELF_ST_PROGBITS) { if (sec_header.type == ELF_ST_PROGBITS) {
con_debug(L"PROGBITS section\r\n");
status = file->SetPosition(file, sec_header.offset); status = file->SetPosition(file, sec_header.offset);
CHECK_EFI_STATUS_OR_RETURN(status, L"Setting ELF file position"); CHECK_EFI_STATUS_OR_RETURN(status, L"Setting ELF file position");
@@ -189,12 +185,10 @@ loader_load_elf(
status = file->Read(file, &length, addr); status = file->Read(file, &length, addr);
CHECK_EFI_STATUS_OR_RETURN(status, L"Reading file"); CHECK_EFI_STATUS_OR_RETURN(status, L"Reading file");
} else if (sec_header.type == ELF_ST_NOBITS) { } else if (sec_header.type == ELF_ST_NOBITS) {
con_debug(L"NOBITS section\r\n");
bootsvc->SetMem(addr, sec_header.size, 0); bootsvc->SetMem(addr, sec_header.size, 0);
} else {
con_debug(L"other section\r\n");
} }
} }
con_debug(L"Read %d ELF section headers\r\n", header.ph_num);
status = file->Close(file); status = file->Close(file);
CHECK_EFI_STATUS_OR_RETURN(status, L"Closing file handle"); CHECK_EFI_STATUS_OR_RETURN(status, L"Closing file handle");

View File

@@ -39,10 +39,12 @@ efi_main(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *system_table)
EFI_BOOT_SERVICES *bootsvc = system_table->BootServices; EFI_BOOT_SERVICES *bootsvc = system_table->BootServices;
EFI_RUNTIME_SERVICES *runsvc = system_table->RuntimeServices; EFI_RUNTIME_SERVICES *runsvc = system_table->RuntimeServices;
console con(system_table);
// When checking console initialization, use CHECK_EFI_STATUS_OR_RETURN // When checking console initialization, use CHECK_EFI_STATUS_OR_RETURN
// because we can't be sure if the console was fully set up // because we can't be sure if the console was fully set up
status = con_initialize(system_table, GIT_VERSION_WIDE); status = con.initialize(GIT_VERSION_WIDE);
CHECK_EFI_STATUS_OR_RETURN(status, "con_initialize"); CHECK_EFI_STATUS_OR_RETURN(status, "console::initialize");
// From here on out, we can use CHECK_EFI_STATUS_OR_FAIL instead // From here on out, we can use CHECK_EFI_STATUS_OR_FAIL instead
memory_init_pointer_fixup(bootsvc, runsvc); memory_init_pointer_fixup(bootsvc, runsvc);
@@ -77,27 +79,27 @@ efi_main(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *system_table)
// Load the kernel image from disk and check it // Load the kernel image from disk and check it
// //
con_printf(L"Loading kernel into memory...\r\n"); console::print(L"Loading kernel into memory...\r\n");
struct loader_data load; struct loader_data load;
load.data_length = data_length; load.data_length = data_length;
status = loader_load_kernel(bootsvc, &load); status = loader_load_kernel(bootsvc, &load);
CHECK_EFI_STATUS_OR_FAIL(status); CHECK_EFI_STATUS_OR_FAIL(status);
con_printf(L" %u image bytes at 0x%x\r\n", load.kernel_length, load.kernel); console::print(L" %u image bytes at 0x%x\r\n", load.kernel_length, load.kernel);
con_printf(L" %u initrd bytes at 0x%x\r\n", load.initrd_length, load.initrd); console::print(L" %u initrd bytes at 0x%x\r\n", load.initrd_length, load.initrd);
con_printf(L" %u data bytes at 0x%x\r\n", load.data_length, load.data); console::print(L" %u data bytes at 0x%x\r\n", load.data_length, load.data);
struct kernel_header *version = (struct kernel_header *)load.kernel; struct kernel_header *version = (struct kernel_header *)load.kernel;
if (version->magic != KERNEL_HEADER_MAGIC) { if (version->magic != KERNEL_HEADER_MAGIC) {
con_printf(L" bad magic %x\r\n", version->magic); console::print(L" bad magic %x\r\n", version->magic);
CHECK_EFI_STATUS_OR_FAIL(EFI_CRC_ERROR); CHECK_EFI_STATUS_OR_FAIL(EFI_CRC_ERROR);
} }
con_printf(L" Kernel version %d.%d.%d %x%s\r\n", console::print(L" Kernel version %d.%d.%d %x%s\r\n",
version->major, version->minor, version->patch, version->gitsha & 0x0fffffff, version->major, version->minor, version->patch, version->gitsha & 0x0fffffff,
version->gitsha & 0xf0000000 ? "*" : ""); version->gitsha & 0xf0000000 ? "*" : "");
con_printf(L" Entrypoint 0x%x\r\n", load.kernel_entry); console::print(L" Entrypoint 0x%x\r\n", load.kernel_entry);
kernel_entry kernel_main = kernel_entry kernel_main =
reinterpret_cast<kernel_entry>(load.kernel_entry); reinterpret_cast<kernel_entry>(load.kernel_entry);

View File

@@ -139,19 +139,19 @@ memory_dump_map(struct memory_map *map)
const size_t count = map->length / map->size; const size_t count = map->length / map->size;
con_printf(L"Memory map:\n"); console::print(L"Memory map:\n");
con_printf(L"\t Descriptor Count: %d (%d bytes)\n", count, map->length); console::print(L"\t Descriptor Count: %d (%d bytes)\n", count, map->length);
con_printf(L"\t Descriptor Size: %d bytes\n", map->size); console::print(L"\t Descriptor Size: %d bytes\n", map->size);
con_printf(L"\t Type offset: %d\n\n", offsetof(EFI_MEMORY_DESCRIPTOR, Type)); console::print(L"\t Type offset: %d\n\n", offsetof(EFI_MEMORY_DESCRIPTOR, Type));
EFI_MEMORY_DESCRIPTOR *end = INCREMENT_DESC(map->entries, map->length); EFI_MEMORY_DESCRIPTOR *end = INCREMENT_DESC(map->entries, map->length);
EFI_MEMORY_DESCRIPTOR *d = map->entries; EFI_MEMORY_DESCRIPTOR *d = map->entries;
while (d < end) { while (d < end) {
int runtime = (d->Attribute & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME; int runtime = (d->Attribute & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME;
con_printf(L"%s%s ", memory_type_name(d->Type), runtime ? L"*" : L" "); console::print(L"%s%s ", memory_type_name(d->Type), runtime ? L"*" : L" ");
con_printf(L"%lx ", d->PhysicalStart); console::print(L"%lx ", d->PhysicalStart);
con_printf(L"%lx ", d->VirtualStart); console::print(L"%lx ", d->VirtualStart);
con_printf(L"[%4d]\n", d->NumberOfPages); console::print(L"[%4d]\n", d->NumberOfPages);
d = INCREMENT_DESC(d, map->size); d = INCREMENT_DESC(d, map->size);
} }

View File

@@ -10,13 +10,13 @@ const wchar_t *util_error_message(EFI_STATUS status);
#define CHECK_EFI_STATUS_OR_RETURN(s, msg, ...) \ #define CHECK_EFI_STATUS_OR_RETURN(s, msg, ...) \
if (EFI_ERROR((s))) { \ if (EFI_ERROR((s))) { \
con_printf(L"ERROR: " msg L": %s\r\n", ##__VA_ARGS__, util_error_message(s)); \ console::print(L"ERROR: " msg L": %s\r\n", ##__VA_ARGS__, util_error_message(s)); \
return (s); \ return (s); \
} }
#define CHECK_EFI_STATUS_OR_FAIL(s) \ #define CHECK_EFI_STATUS_OR_FAIL(s) \
if (EFI_ERROR((s))) { \ if (EFI_ERROR((s))) { \
con_status_fail(util_error_message(s)); \ console::get().status_fail(util_error_message(s)); \
while (1) __asm__("hlt"); \ while (1) __asm__("hlt"); \
} }
@@ -34,7 +34,7 @@ const wchar_t *util_error_message(EFI_STATUS status);
} }
#ifdef BOOTLOADER_DEBUG #ifdef BOOTLOADER_DEBUG
#define con_debug(...) con_printf(L"DEBUG: " __VA_ARGS__) #define con_debug(...) console::print(L"DEBUG: " __VA_ARGS__)
#else #else
#define con_debug(...) #define con_debug(...)
#endif #endif