From b7f18c0d310181a11d69947206c58a1bb4898d72 Mon Sep 17 00:00:00 2001 From: "Justin C. Miller" Date: Mon, 16 Apr 2018 01:15:42 -0700 Subject: [PATCH] Parse the ACPI XSDT and find ACPI tables. --- src/modules/main/acpi_tables.h | 43 ++++++++++++++++++++ src/modules/main/device_manager.cpp | 61 +++++++++++++++++++++++------ src/modules/main/device_manager.h | 5 +++ src/modules/main/interrupts.cpp | 1 + src/modules/main/main.cpp | 19 +++++---- src/modules/main/util.h | 6 +++ 6 files changed, 116 insertions(+), 19 deletions(-) create mode 100644 src/modules/main/acpi_tables.h diff --git a/src/modules/main/acpi_tables.h b/src/modules/main/acpi_tables.h new file mode 100644 index 0000000..64e094b --- /dev/null +++ b/src/modules/main/acpi_tables.h @@ -0,0 +1,43 @@ +#pragma once + +#include +#include + +#include "util.h" + +struct acpi_table_header +{ + uint32_t type; + uint32_t length; + uint8_t revision; + uint8_t checksum; + char oem_id[6]; + char oem_table[8]; + uint32_t oem_revision; + uint32_t creator_id; + uint32_t creator_revision; + + bool validate(uint32_t expected_type = 0) const; +} __attribute__ ((packed)); + +#define TABLE_HEADER(signature) \ + static const uint32_t type_id = byteswap(signature); \ + acpi_table_header header; + + +struct acpi_xsdt +{ + TABLE_HEADER('XSDT'); + acpi_table_header *headers[0]; +} __attribute__ ((packed)); + + +template +bool acpi_validate(const T *t) { return t->header.validate(T::type_id); } + +template +size_t acpi_table_entries(const T *t, size_t size) +{ + return (t->header.length - sizeof(T)) / size; +} + diff --git a/src/modules/main/device_manager.cpp b/src/modules/main/device_manager.cpp index 428306f..cdcdf85 100644 --- a/src/modules/main/device_manager.cpp +++ b/src/modules/main/device_manager.cpp @@ -1,13 +1,14 @@ #include #include +#include "acpi_tables.h" #include "device_manager.h" #include "console.h" #include "util.h" static const char expected_signature[] = "RSD PTR "; -struct Acpi10RSDPDescriptor +struct acpi1_rsdp { char signature[8]; uint8_t checksum; @@ -16,7 +17,7 @@ struct Acpi10RSDPDescriptor uint32_t rsdt_address; } __attribute__ ((packed)); -struct Acpi20RSDPDescriptor +struct acpi2_rsdp { char signature[8]; uint8_t checksum10; @@ -31,38 +32,74 @@ struct Acpi20RSDPDescriptor } __attribute__ ((packed)); -template -uint8_t acpi_checksum(const T *p, size_t off = 0) +uint8_t acpi_checksum(const void *p, size_t len, size_t off = 0) { uint8_t sum = 0; const uint8_t *c = reinterpret_cast(p); - for (int i = off; i < sizeof(T); ++i) sum += c[i]; + for (int i = off; i < len; ++i) sum += c[i]; return sum; } +bool +acpi_table_header::validate(uint32_t expected_type) const +{ + if (acpi_checksum(this, length) != 0) return false; + return !expected_type || (expected_type == type); +} + device_manager::device_manager(const void *root_table) { console *cons = console::get(); kassert(root_table != 0, "ACPI root table pointer is null."); - const Acpi10RSDPDescriptor *acpi1 = - reinterpret_cast(root_table); + const acpi1_rsdp *acpi1 = + reinterpret_cast(root_table); for (int i = 0; i < sizeof(acpi1->signature); ++i) kassert(acpi1->signature[i] == expected_signature[i], "ACPI RSDP table signature mismatch"); - uint8_t sum = acpi_checksum(acpi1, 0); + uint8_t sum = acpi_checksum(acpi1, sizeof(acpi1_rsdp), 0); kassert(sum == 0, "ACPI 1.0 RSDP checksum mismatch."); kassert(acpi1->revision > 1, "ACPI 1.0 not supported."); - const Acpi20RSDPDescriptor *acpi2 = - reinterpret_cast(acpi1); + const acpi2_rsdp *acpi2 = + reinterpret_cast(acpi1); - sum = acpi_checksum(acpi2, sizeof(Acpi10RSDPDescriptor)); + sum = acpi_checksum(acpi2, sizeof(acpi2_rsdp), sizeof(acpi1_rsdp)); kassert(sum == 0, "ACPI 2.0 RSDP checksum mismatch."); - cons->puts("ACPI 2.0 tables loading...\n"); + load_xsdt(reinterpret_cast(acpi2->xsdt_address)); +} + +static void +put_sig(console *cons, uint32_t type) +{ + char sig[5] = {0,0,0,0,0}; + for (int j=0; j<4; ++j) + sig[j] = reinterpret_cast(&type)[j]; + cons->puts(sig); +} + +void +device_manager::load_xsdt(const acpi_xsdt *xsdt) +{ + kassert(xsdt && acpi_validate(xsdt), "Invalid ACPI XSDT."); + + console *cons = console::get(); + cons->puts("ACPI 2.0 tables loading: "); + put_sig(cons, xsdt->header.type); + + size_t num_tables = acpi_table_entries(xsdt, sizeof(void*)); + for (size_t i = 0; i < num_tables; ++i) { + const acpi_table_header *header = xsdt->headers[i]; + + cons->puts(" "); + put_sig(cons, header->type); + kassert(header->validate(), "Table failed validation."); + } + + cons->puts("\n"); } diff --git a/src/modules/main/device_manager.h b/src/modules/main/device_manager.h index 2a42f0f..d8d9b62 100644 --- a/src/modules/main/device_manager.h +++ b/src/modules/main/device_manager.h @@ -1,5 +1,7 @@ #pragma once +struct acpi_xsdt; + class device_manager { public: @@ -7,4 +9,7 @@ public: device_manager() = delete; device_manager(const device_manager &) = delete; + +private: + void load_xsdt(const acpi_xsdt *xsdt); }; diff --git a/src/modules/main/interrupts.cpp b/src/modules/main/interrupts.cpp index a6fecb5..e258e81 100644 --- a/src/modules/main/interrupts.cpp +++ b/src/modules/main/interrupts.cpp @@ -177,6 +177,7 @@ isr_handler(registers regs) print_reg(" ef", regs.eflags); print_reg("esp", regs.user_esp); print_reg(" ss", regs.ss); + while(1) asm("hlt"); } diff --git a/src/modules/main/main.cpp b/src/modules/main/main.cpp index 5709a23..1152289 100644 --- a/src/modules/main/main.cpp +++ b/src/modules/main/main.cpp @@ -2,6 +2,7 @@ #include #include "console.h" +#include "device_manager.h" #include "font.h" #include "interrupts.h" #include "kernel_data.h" @@ -15,7 +16,7 @@ extern "C" { console load_console(const popcorn_data *header) { - return console{ + console cons{ font::load(header->font), screen{ header->frame_buffer, @@ -26,6 +27,13 @@ load_console(const popcorn_data *header) header->bmask}, header->log, header->log_length}; + + cons.set_color(0x21, 0x00); + cons.puts("Popcorn OS "); + cons.set_color(0x08, 0x00); + cons.puts(GIT_VERSION " booting...\n"); + + return cons; } void @@ -33,18 +41,15 @@ kernel_main(popcorn_data *header) { console cons = load_console(header); - cons.set_color(0x21, 0x00); - cons.puts("Popcorn OS "); - cons.set_color(0x08, 0x00); - cons.puts(GIT_VERSION " booting...\n"); - interrupts_init(); interrupts_enable(); cons.puts("Interrupts initialized.\n"); + device_manager devices(header->acpi_table); + // int x = 1 / 0; - __asm__ __volatile__("int $15"); + // __asm__ __volatile__("int $15"); cons.puts("boogity!"); do_the_set_registers(header); diff --git a/src/modules/main/util.h b/src/modules/main/util.h index 162a045..fa3e959 100644 --- a/src/modules/main/util.h +++ b/src/modules/main/util.h @@ -11,3 +11,9 @@ struct coord { [[noreturn]] void __kernel_assert(const char *file, unsigned line, const char *message); #define kassert(stmt, message) if(!(stmt)) { __kernel_assert(__FILE__, __LINE__, (message)); } else {} + +constexpr uint32_t byteswap(uint32_t x) +{ + return ((x >> 24) & 0x000000ff) | ((x >> 8) & 0x0000ff00) + | ((x << 8) & 0x00ff0000) | ((x << 24) & 0xff000000); +}