From f627ea7de04041603823b1c4c9eacf4a3914d6e2 Mon Sep 17 00:00:00 2001 From: "Justin C. Miller" Date: Sat, 22 Feb 2020 14:57:28 -0800 Subject: [PATCH] Re-add functionality to boot with new UEFI headers - Pointer fixup event - ACPI searching - Move CHECK_* to using try_or_raise() --- modules.yaml | 1 + src/boot/console.cpp | 110 ++++++++++++++++++++++++------------------- src/boot/console.h | 8 ++-- src/boot/error.cpp | 30 +++++++++++- src/boot/error.h | 7 +++ src/boot/main.cpp | 109 +++++++++++++++++++++++------------------- src/boot/memory.cpp | 70 +++++++++++++++++---------- src/boot/memory.h | 21 ++++++--- src/boot/utility.cpp | 28 ----------- src/boot/utility.h | 26 ---------- 10 files changed, 220 insertions(+), 190 deletions(-) diff --git a/modules.yaml b/modules.yaml index 82aad4d..66b78d7 100644 --- a/modules.yaml +++ b/modules.yaml @@ -58,6 +58,7 @@ modules: - src/boot/main.cpp - src/boot/console.cpp - src/boot/error.cpp + - src/boot/memory.cpp - src/boot/utility.cpp nulldrv: diff --git a/src/boot/console.cpp b/src/boot/console.cpp index 35a7d4d..9012deb 100644 --- a/src/boot/console.cpp +++ b/src/boot/console.cpp @@ -8,9 +8,13 @@ #include #include "console.h" -//#include "guids.h" +#include "error.h" #include "utility.h" +#ifndef GIT_VERSION_WIDE +#define GIT_VERSION_WIDE L"no version" +#endif + namespace boot { size_t ROWS = 0; @@ -24,50 +28,44 @@ static const wchar_t digits[] = {u'0', u'1', u'2', u'3', u'4', u'5', console::console(uefi::system_table *system_table) : m_rows(0), m_cols(0), - m_current_status_line(0), - m_out(nullptr) -{ - s_console = this; - m_boot = system_table->boot_services; - m_out = system_table->con_out; -} - -uefi::status -console::initialize(const wchar_t *version) + m_current_status_line(0) { uefi::status status; - // Might not find a video device at all, so ignore not found errors - status = pick_mode(); - if (status != uefi::status::not_found) - CHECK_EFI_STATUS_OR_FAIL(status); + s_console = this; + m_boot = system_table->boot_services; + m_out = system_table->con_out; - status = m_out->query_mode(m_out->mode->mode, &m_cols, &m_rows); - CHECK_EFI_STATUS_OR_RETURN(status, "QueryMode"); + pick_mode(); - status = m_out->clear_screen(); - CHECK_EFI_STATUS_OR_RETURN(status, "ClearScreen"); + try_or_raise( + m_out->query_mode(m_out->mode->mode, &m_cols, &m_rows), + L"Failed to get text output mode."); + + try_or_raise( + m_out->clear_screen(), + L"Failed to clear screen"); m_out->set_attribute(uefi::attribute::light_cyan); - m_out->output_string((wchar_t *)L"jsix loader "); + m_out->output_string(L"jsix loader "); m_out->set_attribute(uefi::attribute::light_magenta); - m_out->output_string((wchar_t *)version); + m_out->output_string(GIT_VERSION_WIDE); m_out->set_attribute(uefi::attribute::light_gray); - m_out->output_string((wchar_t *)L" booting...\r\n\n"); - - return status; + m_out->output_string(L" booting...\r\n\n"); } -uefi::status +void console::pick_mode() { uefi::status status; uefi::protos::graphics_output *gfx_out_proto; uefi::guid guid = uefi::protos::graphics_output::guid; - status = m_boot->locate_protocol(&guid, nullptr, (void **)&gfx_out_proto); - CHECK_EFI_STATUS_OR_RETURN(status, "LocateProtocol gfx"); + + try_or_raise( + m_boot->locate_protocol(&guid, nullptr, (void **)&gfx_out_proto), + L"Failed to find a Graphics Output Protocol handle"); const uint32_t modes = gfx_out_proto->mode->max_mode; uint32_t best = gfx_out_proto->mode->mode; @@ -80,8 +78,10 @@ console::pick_mode() for (uint32_t i = 0; i < modes; ++i) { size_t size = 0; - status = gfx_out_proto->query_mode(i, &size, &info); - CHECK_EFI_STATUS_OR_RETURN(status, "QueryMode"); + + try_or_raise( + gfx_out_proto->query_mode(i, &size, &info), + L"Failed to find a graphics mode the driver claimed to support"); #ifdef MAX_HRES if (info->horizontal_resolution > MAX_HRES) continue; @@ -96,9 +96,9 @@ console::pick_mode() } } - status = gfx_out_proto->set_mode(best); - CHECK_EFI_STATUS_OR_RETURN(status, "SetMode %d/%d", best, modes); - return uefi::status::success; + try_or_raise( + gfx_out_proto->set_mode(best), + L"Failed to set graphics mode"); } size_t @@ -259,8 +259,8 @@ console::status_begin(const wchar_t *message) m_current_status_line = m_out->mode->cursor_row; m_out->set_cursor_position(0, m_current_status_line); m_out->set_attribute(uefi::attribute::light_gray); - m_out->output_string((wchar_t *)message); - m_out->output_string((wchar_t *)L"\r\n"); + m_out->output_string(message); + m_out->output_string(L"\r\n"); } void @@ -272,55 +272,67 @@ console::status_ok() const m_out->set_cursor_position(50, m_current_status_line); m_out->set_attribute(uefi::attribute::light_gray); - m_out->output_string((wchar_t *)L"["); + m_out->output_string(L"["); m_out->set_attribute(uefi::attribute::green); - m_out->output_string((wchar_t *)L" ok "); + m_out->output_string(L" ok "); m_out->set_attribute(uefi::attribute::light_gray); - m_out->output_string((wchar_t *)L"]\r\n"); + m_out->output_string(L"]\r\n"); m_out->set_cursor_position(col, row); } void -console::status_fail(const wchar_t *error) const +console::status_fail(const wchar_t *message, const wchar_t *error) const { int row = m_out->mode->cursor_row; m_out->set_cursor_position(50, m_current_status_line); m_out->set_attribute(uefi::attribute::light_gray); - m_out->output_string((wchar_t *)L"["); + m_out->output_string(L"["); m_out->set_attribute(uefi::attribute::light_red); - m_out->output_string((wchar_t *)L"failed"); + m_out->output_string(L"failed"); m_out->set_attribute(uefi::attribute::light_gray); - m_out->output_string((wchar_t *)L"]"); + m_out->output_string(L"]"); m_out->set_cursor_position(4, row); m_out->set_attribute(uefi::attribute::red); - m_out->output_string((wchar_t *)error); + m_out->output_string(message); + + if (error) { + m_out->output_string(L": "); + m_out->output_string(error); + } + m_out->set_attribute(uefi::attribute::light_gray); - m_out->output_string((wchar_t *)L"\r\n"); + m_out->output_string(L"\r\n"); } void -console::status_warn(const wchar_t *error) const +console::status_warn(const wchar_t *message, const wchar_t *error) const { int row = m_out->mode->cursor_row; m_out->set_cursor_position(50, m_current_status_line); m_out->set_attribute(uefi::attribute::light_gray); - m_out->output_string((wchar_t *)L"["); + m_out->output_string(L"["); m_out->set_attribute(uefi::attribute::brown); - m_out->output_string((wchar_t *)L" warn "); + m_out->output_string(L" warn "); m_out->set_attribute(uefi::attribute::light_gray); - m_out->output_string((wchar_t *)L"]"); + m_out->output_string(L"]"); m_out->set_cursor_position(4, row); m_out->set_attribute(uefi::attribute::yellow); - m_out->output_string((wchar_t *)error); + m_out->output_string(message); + + if (error) { + m_out->output_string(L": "); + m_out->output_string(error); + } + m_out->set_attribute(uefi::attribute::light_gray); - m_out->output_string((wchar_t *)L"\r\n"); + m_out->output_string(L"\r\n"); } /* diff --git a/src/boot/console.h b/src/boot/console.h index 7e43d6f..6e2af6b 100644 --- a/src/boot/console.h +++ b/src/boot/console.h @@ -10,11 +10,9 @@ class console public: console(uefi::system_table *system_table); - uefi::status initialize(const wchar_t *version); - void status_begin(const wchar_t *message); - void status_fail(const wchar_t *error) const; - void status_warn(const wchar_t *error) const; + void status_fail(const wchar_t *message, const wchar_t *error=nullptr) const; + void status_warn(const wchar_t *message, const wchar_t *error=nullptr) const; void status_ok() const; size_t print_hex(uint32_t n) const; @@ -27,7 +25,7 @@ public: static size_t print(const wchar_t *fmt, ...); private: - uefi::status pick_mode(); + void pick_mode(); size_t vprintf(const wchar_t *fmt, va_list args) const; size_t m_rows, m_cols; diff --git a/src/boot/error.cpp b/src/boot/error.cpp index 97d7ff2..c93ae65 100644 --- a/src/boot/error.cpp +++ b/src/boot/error.cpp @@ -6,6 +6,34 @@ namespace error { handler *handler::s_current = nullptr; +struct error_code_desc { + uefi::status code; + const wchar_t *name; +}; + +struct error_code_desc error_table[] = { +#define STATUS_ERROR(name, num) { uefi::status::name, L#name }, +#define STATUS_WARNING(name, num) { uefi::status::name, L#name }, +#include "uefi/errors.inc" +#undef STATUS_ERROR +#undef STATUS_WARNING + { uefi::status::success, nullptr } +}; + +static const wchar_t * +error_message(uefi::status status) +{ + int32_t i = -1; + while (error_table[++i].name != nullptr) { + if (error_table[i].code == status) return error_table[i].name; + } + + if (uefi::is_error(status)) + return L"Unknown Error"; + else + return L"Unknown Warning"; +} + [[ noreturn ]] void raise(uefi::status status, const wchar_t *message) { @@ -38,7 +66,7 @@ uefi_handler::uefi_handler(console &con) : [[ noreturn ]] void uefi_handler::handle(uefi::status s, const wchar_t *message) { - m_con.status_fail(message); + m_con.status_fail(message, error_message(s)); while (1) asm("hlt"); } diff --git a/src/boot/error.h b/src/boot/error.h index 24c562f..931d1da 100644 --- a/src/boot/error.h +++ b/src/boot/error.h @@ -51,3 +51,10 @@ public: } // namespace error } // namespace boot + +#define try_or_raise(s, m) \ + do { \ + uefi::status _s = (s); \ + if (uefi::is_error(_s)) ::boot::error::raise(_s, (m)); \ + } while(0) + diff --git a/src/boot/main.cpp b/src/boot/main.cpp index 3fb7b5e..fbf826b 100644 --- a/src/boot/main.cpp +++ b/src/boot/main.cpp @@ -9,25 +9,17 @@ #include "console.h" #include "error.h" +#include "memory.h" /* #include "guids.h" #include "kernel_args.h" #include "loader.h" -#include "memory.h" #include "utility.h" #ifndef SCRATCH_PAGES #define SCRATCH_PAGES 64 #endif -*/ -#ifndef GIT_VERSION_WIDE -#define GIT_VERSION_WIDE L"no version" -#endif - -using namespace boot; - -/* #define KERNEL_HEADER_MAGIC 0x600db007 #define KERNEL_HEADER_VERSION 1 @@ -43,9 +35,13 @@ struct kernel_header { uint32_t gitsha; }; #pragma pack(pop) - using kernel_entry = void (*)(kernel_args *); +*/ +namespace boot { + + +/* static void type_to_wchar(wchar_t *into, uint32_t type) { @@ -91,30 +87,54 @@ detect_debug_mode(EFI_RUNTIME_SERVICES *run, kernel_args *header) { } */ -extern "C" uefi::status -efi_main(uefi::handle image_handle, uefi::system_table *st) +uefi::status +bootloader_main_uefi(uefi::system_table *st, console &con) { - error::cpu_assert_handler handler; + error::uefi_handler handler(con); uefi::boot_services *bs = st->boot_services; uefi::runtime_services *rs = st->runtime_services; - console con(st); - con.initialize(GIT_VERSION_WIDE); + /* + con.status_begin(L"Trying to do a harder thing..."); + con.status_warn(L"First warning"); + con.status_warn(L"Second warning"); - { - error::uefi_handler handler(con); - con.status_begin(L"Trying to do an easy thing..."); + con.status_begin(L"Trying to do the impossible..."); + con.status_warn(L"we're not going to make it"); + + error::raise(uefi::status::unsupported, L"OH NO"); + */ + + con.status_begin(L"Initializing pointer fixup for virtualization"); + memory::init_pointer_fixup(bs, rs); + con.status_ok(); + + // Find ACPI tables. Ignore ACPI 1.0 if a 2.0 table is found. + // + con.status_begin(L"Searching for ACPI table"); + uintptr_t acpi_table = 0; + for (size_t i = 0; i < st->number_of_table_entries; ++i) { + uefi::configuration_table *table = &st->configuration_table[i]; + + if (table->vendor_guid == uefi::vendor_guids::acpi2) { + acpi_table = reinterpret_cast(table->vendor_table); + break; + } + + if (table->vendor_guid == uefi::vendor_guids::acpi1) { + // Mark a v1 table with the LSB high + acpi_table = reinterpret_cast(table->vendor_table); + acpi_table |= 1; + } + } + + if (!acpi_table) { + error::raise(uefi::status::not_found, L"Could not find ACPI table"); + } else if (acpi_table & 1) { + con.status_warn(L"Only found ACPI 1.0 table"); + } else { con.status_ok(); - - con.status_begin(L"Trying to do a harder thing..."); - con.status_warn(L"First warning"); - con.status_warn(L"Second warning"); - - con.status_begin(L"Trying to do the impossible..."); - con.status_warn(L"we're not going to make it"); - - error::raise(uefi::status::unsupported, L"OH NO"); } while(1); @@ -122,28 +142,6 @@ efi_main(uefi::handle image_handle, uefi::system_table *st) } /* - // 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(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, SCRATCH_PAGES); - - // Find ACPI tables. Ignore ACPI 1.0 if a 2.0 table is found. - // - void *acpi_table = NULL; - for (size_t i=0; iNumberOfTableEntries; ++i) { - EFI_CONFIGURATION_TABLE *efi_table = &system_table->ConfigurationTable[i]; - if (is_guid(&efi_table->VendorGuid, &guid_acpi2)) { - acpi_table = efi_table->VendorTable; - break; - } else if (is_guid(&efi_table->VendorGuid, &guid_acpi1)) { - // Mark a v1 table with the LSB high - acpi_table = (void *)((intptr_t)efi_table->VendorTable | 0x1); - } - } - // Compute necessary number of data pages // size_t data_length = 0; @@ -259,3 +257,16 @@ efi_main(uefi::handle image_handle, uefi::system_table *st) return EFI_LOAD_ERROR; } */ +} // namespace boot + +extern "C" uefi::status +efi_main(uefi::handle image_handle, uefi::system_table *st) +{ + using namespace boot; + + error::cpu_assert_handler handler; + console con(st); + + return bootloader_main_uefi(st, con); +} + diff --git a/src/boot/memory.cpp b/src/boot/memory.cpp index 3495b48..a827b83 100644 --- a/src/boot/memory.cpp +++ b/src/boot/memory.cpp @@ -1,20 +1,27 @@ #include +#include -#include "loader.h" +#include "error.h" #include "memory.h" #include "utility.h" -const EFI_MEMORY_TYPE memtype_kernel = static_cast(0x80000000); -const EFI_MEMORY_TYPE memtype_data = static_cast(0x80000001); -const EFI_MEMORY_TYPE memtype_initrd = static_cast(0x80000002); -const EFI_MEMORY_TYPE memtype_scratch = static_cast(0x80000003); +namespace boot { +namespace memory { + +/* +const EFI_MEMORY_TYPE memtype_kernel = static_cast(0x80000000ul); +const EFI_MEMORY_TYPE memtype_data = static_cast(0x80000001ul); +const EFI_MEMORY_TYPE memtype_initrd = static_cast(0x80000002ul); +const EFI_MEMORY_TYPE memtype_scratch = static_cast(0x80000003ul); #define INCREMENT_DESC(p, b) (EFI_MEMORY_DESCRIPTOR*)(((uint8_t*)(p))+(b)) +*/ size_t fixup_pointer_index = 0; void **fixup_pointers[64]; uint64_t *new_pml4 = 0; +/* const wchar_t *memory_type_names[] = { L"EfiReservedMemoryType", L"EfiLoaderCode", @@ -47,44 +54,52 @@ memory_type_name(UINT32 value) } return memory_type_names[value]; } +*/ -void EFIAPI -memory_update_marked_addresses(EFI_EVENT UNUSED *event, void *context) +void +update_marked_addresses(uefi::event, void *context) { - EFI_RUNTIME_SERVICES *runsvc = (EFI_RUNTIME_SERVICES*)context; + uefi::runtime_services *rs = + reinterpret_cast(context); + for (size_t i = 0; i < fixup_pointer_index; ++i) { if (fixup_pointers[i]) - runsvc->ConvertPointer(0, fixup_pointers[i]); + rs->convert_pointer(0, fixup_pointers[i]); } } -EFI_STATUS -memory_init_pointer_fixup(EFI_BOOT_SERVICES *bootsvc, EFI_RUNTIME_SERVICES *runsvc, unsigned scratch_pages) +void +init_pointer_fixup(uefi::boot_services *bs, uefi::runtime_services *rs) { - EFI_STATUS status; - EFI_EVENT event; + uefi::event event; - status = bootsvc->CreateEvent( - EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE, - TPL_CALLBACK, - (EFI_EVENT_NOTIFY)&memory_update_marked_addresses, - runsvc, - &event); + try_or_raise( + bs->create_event( + uefi::evt::signal_virtual_address_change, + uefi::tpl::callback, + (uefi::event_notify)&update_marked_addresses, + rs, + &event), + L"Error creating memory virtualization event"); - CHECK_EFI_STATUS_OR_RETURN(status, "Failed to initialize pointer update event."); + uefi::memory_type memtype = static_cast(0x80000003ul); // Reserve a page for our replacement PML4, plus some pages for the kernel to use // as page tables while it gets started. - EFI_PHYSICAL_ADDRESS addr = 0; - status = bootsvc->AllocatePages(AllocateAnyPages, memtype_scratch, scratch_pages, &addr); - CHECK_EFI_STATUS_OR_RETURN(status, "Failed to allocate page table pages."); + uintptr_t addr = 0; + try_or_raise( + bs->allocate_pages( + uefi::allocate_type::any_pages, + memtype, + 64, + &addr), + L"Error allocating page table pages."); new_pml4 = (uint64_t *)addr; - return EFI_SUCCESS; } void -memory_mark_pointer_fixup(void **p) +mark_pointer_fixup(void **p) { if (fixup_pointer_index == 0) { const size_t count = sizeof(fixup_pointers) / sizeof(void*); @@ -93,6 +108,7 @@ memory_mark_pointer_fixup(void **p) fixup_pointers[fixup_pointer_index++] = p; } +/* void copy_desc(EFI_MEMORY_DESCRIPTOR *src, EFI_MEMORY_DESCRIPTOR *dst, size_t len) { @@ -213,3 +229,7 @@ memory_virtualize(EFI_RUNTIME_SERVICES *runsvc, struct memory_map *map) runsvc->SetVirtualAddressMap(map->length, map->size, map->version, map->entries); } +*/ + +} // namespace boot +} // namespace memory diff --git a/src/boot/memory.h b/src/boot/memory.h index 471254f..ce4b301 100644 --- a/src/boot/memory.h +++ b/src/boot/memory.h @@ -1,6 +1,15 @@ #pragma once -#include +#include +#include +#include +namespace boot { +namespace memory { + +void init_pointer_fixup(uefi::boot_services *bs, uefi::runtime_services *rs); +void mark_pointer_fixup(void **p); + +/* extern const EFI_MEMORY_TYPE memtype_kernel; extern const EFI_MEMORY_TYPE memtype_data; extern const EFI_MEMORY_TYPE memtype_initrd; @@ -14,14 +23,12 @@ struct memory_map { EFI_MEMORY_DESCRIPTOR *entries; }; -EFI_STATUS memory_init_pointer_fixup( - EFI_BOOT_SERVICES *bootsvc, - EFI_RUNTIME_SERVICES *runsvc, - unsigned scratch_pages); -void memory_mark_pointer_fixup(void **p); - EFI_STATUS memory_get_map_length(EFI_BOOT_SERVICES *bootsvc, size_t *size); EFI_STATUS memory_get_map(EFI_BOOT_SERVICES *bootsvc, struct memory_map *map); EFI_STATUS memory_dump_map(struct memory_map *map); void memory_virtualize(EFI_RUNTIME_SERVICES *runsvc, struct memory_map *map); +*/ + +} // namespace boot +} // namespace memory diff --git a/src/boot/utility.cpp b/src/boot/utility.cpp index 417402d..75273e5 100644 --- a/src/boot/utility.cpp +++ b/src/boot/utility.cpp @@ -1,33 +1,5 @@ #include "utility.h" -struct error_code_desc { - uefi::status code; - const wchar_t *name; -}; - -struct error_code_desc error_table[] = { -#define STATUS_ERROR(name, num) { uefi::status::name, L#name }, -#define STATUS_WARNING(name, num) { uefi::status::name, L#name }, -#include "uefi/errors.inc" -#undef STATUS_ERROR -#undef STATUS_WARNING - { uefi::status::success, nullptr } -}; - -const wchar_t * -util_error_message(uefi::status status) -{ - int32_t i = -1; - while (error_table[++i].name != nullptr) { - if (error_table[i].code == status) return error_table[i].name; - } - - if (uefi::is_error(status)) - return L"Unknown Error"; - else - return L"Unknown Warning"; -} - size_t wstrlen(const wchar_t *s) { diff --git a/src/boot/utility.h b/src/boot/utility.h index 4bd6ffe..8485782 100644 --- a/src/boot/utility.h +++ b/src/boot/utility.h @@ -6,32 +6,6 @@ #define UNUSED __attribute__((unused)) size_t wstrlen(const wchar_t *s); -const wchar_t *util_error_message(uefi::status status); - -#define CHECK_EFI_STATUS_OR_RETURN(s, msg, ...) \ - if (uefi::is_error((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 (uefi::is_error((s))) { \ - console::get().status_fail(util_error_message(s)); \ - while (1) __asm__("hlt"); \ - } - -#define CHECK_EFI_STATUS_OR_ASSERT(s, d) \ - if (uefi::is_error((s))) { \ - __asm__ __volatile__( \ - "movq %0, %%r8;" \ - "movq %1, %%r9;" \ - "movq %2, %%r10;" \ - "movq $0, %%rdx;" \ - "divq %%rdx;" \ - : \ - : "r"((uint64_t)s), "r"((uint64_t)d), "r"((uint64_t)__LINE__) \ - : "rax", "rdx", "r8", "r9", "r10"); \ - } #ifdef BOOTLOADER_DEBUG #define con_debug(msg, ...) console::print(L"DEBUG: " msg L"\r\n", __VA_ARGS__)