diff --git a/src/boot/console.cpp b/src/boot/console.cpp index 23119d5..19d2525 100644 --- a/src/boot/console.cpp +++ b/src/boot/console.cpp @@ -1,4 +1,3 @@ -#include #include #include @@ -9,16 +8,55 @@ size_t ROWS = 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 -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_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"); const uint32_t modes = gfx_out_proto->Mode->MaxMode; @@ -53,39 +91,8 @@ con_pick_mode(EFI_BOOT_SERVICES *bootsvc) 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 -con_print_hex(uint32_t n) +console::print_hex(uint32_t n) const { wchar_t buffer[9]; wchar_t *p = buffer; @@ -94,12 +101,12 @@ con_print_hex(uint32_t n) *p++ = digits[nibble]; } *p = 0; - con_out->OutputString(con_out, buffer); + m_out->OutputString(m_out, buffer); return 8; } size_t -con_print_long_hex(uint64_t n) +console::print_long_hex(uint64_t n) const { wchar_t buffer[17]; wchar_t *p = buffer; @@ -108,12 +115,12 @@ con_print_long_hex(uint64_t n) *p++ = digits[nibble]; } *p = 0; - con_out->OutputString(con_out, buffer); + m_out->OutputString(m_out, buffer); return 16; } size_t -con_print_dec(uint32_t n) +console::print_dec(uint32_t n) const { wchar_t buffer[11]; wchar_t *p = buffer + 10; @@ -123,12 +130,12 @@ con_print_dec(uint32_t n) n /= 10; } while (n != 0); - con_out->OutputString(con_out, ++p); + m_out->OutputString(m_out, ++p); return 10 - (p - buffer); } size_t -con_print_long_dec(uint64_t n) +console::print_long_dec(uint64_t n) const { wchar_t buffer[21]; wchar_t *p = buffer + 20; @@ -138,21 +145,18 @@ con_print_long_dec(uint64_t n) n /= 10; } while (n != 0); - con_out->OutputString(con_out, ++p); + m_out->OutputString(m_out, ++p); return 20 - (p - buffer); } size_t -con_printf(const wchar_t *fmt, ...) +console::vprintf(const wchar_t *fmt, va_list args) const { wchar_t buffer[256]; const wchar_t *r = fmt; wchar_t *w = buffer; - va_list args; size_t count = 0; - va_start(args, fmt); - while (r && *r) { if (*r != L'%') { count++; @@ -161,43 +165,43 @@ con_printf(const wchar_t *fmt, ...) } *w = 0; - con_out->OutputString(con_out, buffer); + m_out->OutputString(m_out, buffer); w = buffer; r++; // chomp the % switch (*r++) { case L'%': - con_out->OutputString(con_out, const_cast(L"%")); + m_out->OutputString(m_out, const_cast(L"%")); count++; break; case L'x': - count += con_print_hex(va_arg(args, uint32_t)); + count += print_hex(va_arg(args, uint32_t)); break; case L'd': case L'u': - count += con_print_dec(va_arg(args, uint32_t)); + count += print_dec(va_arg(args, uint32_t)); break; case L's': { wchar_t *s = va_arg(args, wchar_t*); count += wstrlen(s); - con_out->OutputString(con_out, s); + m_out->OutputString(m_out, s); } break; case L'l': switch (*r++) { case L'x': - count += con_print_long_hex(va_arg(args, uint64_t)); + count += print_long_hex(va_arg(args, uint64_t)); break; case L'd': case L'u': - count += con_print_long_dec(va_arg(args, uint64_t)); + count += print_long_dec(va_arg(args, uint64_t)); break; default: @@ -211,44 +215,66 @@ con_printf(const wchar_t *fmt, ...) } *w = 0; - con_out->OutputString(con_out, buffer); - - va_end(args); + m_out->OutputString(m_out, buffer); return count; } -void -con_status_begin(const wchar_t *message) +size_t +console::printf(const wchar_t *fmt, ...) const { - con_out->SetAttribute(con_out, EFI_LIGHTGRAY); - con_out->OutputString(con_out, (wchar_t *)message); + va_list args; + 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 -con_status_ok() +console::status_begin(const wchar_t *message) const { - con_out->SetAttribute(con_out, EFI_LIGHTGRAY); - con_out->OutputString(con_out, (wchar_t *)L"["); - 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"); + m_out->SetAttribute(m_out, EFI_LIGHTGRAY); + m_out->OutputString(m_out, (wchar_t *)message); } void -con_status_fail(const wchar_t *error) +console::status_ok() const { - con_out->SetAttribute(con_out, EFI_LIGHTGRAY); - con_out->OutputString(con_out, (wchar_t *)L"["); - con_out->SetAttribute(con_out, EFI_LIGHTRED); - con_out->OutputString(con_out, (wchar_t *)L"failed"); - 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_GREEN); + m_out->OutputString(m_out, (wchar_t *)L" ok "); + m_out->SetAttribute(m_out, EFI_LIGHTGRAY); + m_out->OutputString(m_out, (wchar_t *)L"]\r\n"); +} - con_out->SetAttribute(con_out, EFI_RED); - con_out->OutputString(con_out, (wchar_t *)error); - con_out->SetAttribute(con_out, EFI_LIGHTGRAY); - con_out->OutputString(con_out, (wchar_t *)L"\r\n"); +void +console::status_fail(const wchar_t *error) const +{ + 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 diff --git a/src/boot/console.h b/src/boot/console.h index 7ecd4fd..c9fded0 100644 --- a/src/boot/console.h +++ b/src/boot/console.h @@ -1,12 +1,38 @@ #pragma once +#include #include #include -EFI_STATUS con_initialize(EFI_SYSTEM_TABLE *system_table, const wchar_t *version); -void con_status_begin(const wchar_t *message); -void con_status_ok(); -void con_status_fail(const wchar_t *error); -size_t con_printf(const wchar_t *fmt, ...); +class console +{ +public: + console(EFI_SYSTEM_TABLE *system_table); + + 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 con_get_framebuffer( diff --git a/src/boot/loader.cpp b/src/boot/loader.cpp index 011bc77..d6d2c13 100644 --- a/src/boot/loader.cpp +++ b/src/boot/loader.cpp @@ -141,7 +141,6 @@ loader_load_elf( struct elf_program_header prog_header; 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); CHECK_EFI_STATUS_OR_RETURN(status, L"Setting ELF file position"); @@ -161,11 +160,10 @@ loader_load_elf( data->kernel = addr; 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; 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); 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"); if ((sec_header.flags & ELF_SHF_ALLOC) == 0) { - con_debug(L"SHF_ALLOC section\r\n"); continue; } void *addr = (void *)(sec_header.addr - KERNEL_VIRT_ADDRESS); if (sec_header.type == ELF_ST_PROGBITS) { - con_debug(L"PROGBITS section\r\n"); status = file->SetPosition(file, sec_header.offset); CHECK_EFI_STATUS_OR_RETURN(status, L"Setting ELF file position"); @@ -189,12 +185,10 @@ loader_load_elf( status = file->Read(file, &length, addr); CHECK_EFI_STATUS_OR_RETURN(status, L"Reading file"); } else if (sec_header.type == ELF_ST_NOBITS) { - con_debug(L"NOBITS section\r\n"); 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); CHECK_EFI_STATUS_OR_RETURN(status, L"Closing file handle"); diff --git a/src/boot/main.cpp b/src/boot/main.cpp index ac99c05..51c0e51 100644 --- a/src/boot/main.cpp +++ b/src/boot/main.cpp @@ -39,10 +39,12 @@ efi_main(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *system_table) EFI_BOOT_SERVICES *bootsvc = system_table->BootServices; EFI_RUNTIME_SERVICES *runsvc = system_table->RuntimeServices; + console con(system_table); + // When checking console initialization, use CHECK_EFI_STATUS_OR_RETURN // because we can't be sure if the console was fully set up - status = con_initialize(system_table, GIT_VERSION_WIDE); - CHECK_EFI_STATUS_OR_RETURN(status, "con_initialize"); + status = con.initialize(GIT_VERSION_WIDE); + CHECK_EFI_STATUS_OR_RETURN(status, "console::initialize"); // From here on out, we can use CHECK_EFI_STATUS_OR_FAIL instead 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 // - con_printf(L"Loading kernel into memory...\r\n"); + console::print(L"Loading kernel into memory...\r\n"); struct loader_data load; load.data_length = data_length; status = loader_load_kernel(bootsvc, &load); CHECK_EFI_STATUS_OR_FAIL(status); - con_printf(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); - con_printf(L" %u data bytes at 0x%x\r\n", load.data_length, load.data); + console::print(L" %u image bytes at 0x%x\r\n", load.kernel_length, load.kernel); + console::print(L" %u initrd bytes at 0x%x\r\n", load.initrd_length, load.initrd); + 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; 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); } - 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->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 = reinterpret_cast(load.kernel_entry); diff --git a/src/boot/memory.cpp b/src/boot/memory.cpp index 5d11f88..f4ebc24 100644 --- a/src/boot/memory.cpp +++ b/src/boot/memory.cpp @@ -139,19 +139,19 @@ memory_dump_map(struct memory_map *map) const size_t count = map->length / map->size; - con_printf(L"Memory map:\n"); - con_printf(L"\t Descriptor Count: %d (%d bytes)\n", count, map->length); - con_printf(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"Memory map:\n"); + console::print(L"\t Descriptor Count: %d (%d bytes)\n", count, map->length); + console::print(L"\t Descriptor Size: %d bytes\n", map->size); + 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 *d = map->entries; while (d < end) { int runtime = (d->Attribute & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME; - con_printf(L"%s%s ", memory_type_name(d->Type), runtime ? L"*" : L" "); - con_printf(L"%lx ", d->PhysicalStart); - con_printf(L"%lx ", d->VirtualStart); - con_printf(L"[%4d]\n", d->NumberOfPages); + console::print(L"%s%s ", memory_type_name(d->Type), runtime ? L"*" : L" "); + console::print(L"%lx ", d->PhysicalStart); + console::print(L"%lx ", d->VirtualStart); + console::print(L"[%4d]\n", d->NumberOfPages); d = INCREMENT_DESC(d, map->size); } diff --git a/src/boot/utility.h b/src/boot/utility.h index 135684f..cb954ab 100644 --- a/src/boot/utility.h +++ b/src/boot/utility.h @@ -10,13 +10,13 @@ const wchar_t *util_error_message(EFI_STATUS status); #define CHECK_EFI_STATUS_OR_RETURN(s, msg, ...) \ 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); \ } #define CHECK_EFI_STATUS_OR_FAIL(s) \ if (EFI_ERROR((s))) { \ - con_status_fail(util_error_message(s)); \ + console::get().status_fail(util_error_message(s)); \ while (1) __asm__("hlt"); \ } @@ -34,7 +34,7 @@ const wchar_t *util_error_message(EFI_STATUS status); } #ifdef BOOTLOADER_DEBUG -#define con_debug(...) con_printf(L"DEBUG: " __VA_ARGS__) +#define con_debug(...) console::print(L"DEBUG: " __VA_ARGS__) #else #define con_debug(...) #endif