Parse the ACPI XSDT and find ACPI tables.

This commit is contained in:
Justin C. Miller
2018-04-16 01:15:42 -07:00
parent 696c29086b
commit b7f18c0d31
6 changed files with 116 additions and 19 deletions

View File

@@ -0,0 +1,43 @@
#pragma once
#include <stddef.h>
#include <stdint.h>
#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 <typename T>
bool acpi_validate(const T *t) { return t->header.validate(T::type_id); }
template <typename T>
size_t acpi_table_entries(const T *t, size_t size)
{
return (t->header.length - sizeof(T)) / size;
}

View File

@@ -1,13 +1,14 @@
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include "acpi_tables.h"
#include "device_manager.h" #include "device_manager.h"
#include "console.h" #include "console.h"
#include "util.h" #include "util.h"
static const char expected_signature[] = "RSD PTR "; static const char expected_signature[] = "RSD PTR ";
struct Acpi10RSDPDescriptor struct acpi1_rsdp
{ {
char signature[8]; char signature[8];
uint8_t checksum; uint8_t checksum;
@@ -16,7 +17,7 @@ struct Acpi10RSDPDescriptor
uint32_t rsdt_address; uint32_t rsdt_address;
} __attribute__ ((packed)); } __attribute__ ((packed));
struct Acpi20RSDPDescriptor struct acpi2_rsdp
{ {
char signature[8]; char signature[8];
uint8_t checksum10; uint8_t checksum10;
@@ -31,38 +32,74 @@ struct Acpi20RSDPDescriptor
} __attribute__ ((packed)); } __attribute__ ((packed));
template <typename T> uint8_t acpi_checksum(const void *p, size_t len, size_t off = 0)
uint8_t acpi_checksum(const T *p, size_t off = 0)
{ {
uint8_t sum = 0; uint8_t sum = 0;
const uint8_t *c = reinterpret_cast<const uint8_t *>(p); const uint8_t *c = reinterpret_cast<const uint8_t *>(p);
for (int i = off; i < sizeof(T); ++i) sum += c[i]; for (int i = off; i < len; ++i) sum += c[i];
return sum; 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) device_manager::device_manager(const void *root_table)
{ {
console *cons = console::get(); console *cons = console::get();
kassert(root_table != 0, "ACPI root table pointer is null."); kassert(root_table != 0, "ACPI root table pointer is null.");
const Acpi10RSDPDescriptor *acpi1 = const acpi1_rsdp *acpi1 =
reinterpret_cast<const Acpi10RSDPDescriptor *>(root_table); reinterpret_cast<const acpi1_rsdp *>(root_table);
for (int i = 0; i < sizeof(acpi1->signature); ++i) for (int i = 0; i < sizeof(acpi1->signature); ++i)
kassert(acpi1->signature[i] == expected_signature[i], kassert(acpi1->signature[i] == expected_signature[i],
"ACPI RSDP table signature mismatch"); "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(sum == 0, "ACPI 1.0 RSDP checksum mismatch.");
kassert(acpi1->revision > 1, "ACPI 1.0 not supported."); kassert(acpi1->revision > 1, "ACPI 1.0 not supported.");
const Acpi20RSDPDescriptor *acpi2 = const acpi2_rsdp *acpi2 =
reinterpret_cast<const Acpi20RSDPDescriptor *>(acpi1); reinterpret_cast<const acpi2_rsdp *>(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."); kassert(sum == 0, "ACPI 2.0 RSDP checksum mismatch.");
cons->puts("ACPI 2.0 tables loading...\n"); load_xsdt(reinterpret_cast<const acpi_xsdt *>(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<char *>(&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");
} }

View File

@@ -1,5 +1,7 @@
#pragma once #pragma once
struct acpi_xsdt;
class device_manager class device_manager
{ {
public: public:
@@ -7,4 +9,7 @@ public:
device_manager() = delete; device_manager() = delete;
device_manager(const device_manager &) = delete; device_manager(const device_manager &) = delete;
private:
void load_xsdt(const acpi_xsdt *xsdt);
}; };

View File

@@ -177,6 +177,7 @@ isr_handler(registers regs)
print_reg(" ef", regs.eflags); print_reg(" ef", regs.eflags);
print_reg("esp", regs.user_esp); print_reg("esp", regs.user_esp);
print_reg(" ss", regs.ss); print_reg(" ss", regs.ss);
while(1) asm("hlt");
} }

View File

@@ -2,6 +2,7 @@
#include <stdint.h> #include <stdint.h>
#include "console.h" #include "console.h"
#include "device_manager.h"
#include "font.h" #include "font.h"
#include "interrupts.h" #include "interrupts.h"
#include "kernel_data.h" #include "kernel_data.h"
@@ -15,7 +16,7 @@ extern "C" {
console console
load_console(const popcorn_data *header) load_console(const popcorn_data *header)
{ {
return console{ console cons{
font::load(header->font), font::load(header->font),
screen{ screen{
header->frame_buffer, header->frame_buffer,
@@ -26,6 +27,13 @@ load_console(const popcorn_data *header)
header->bmask}, header->bmask},
header->log, header->log,
header->log_length}; 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 void
@@ -33,18 +41,15 @@ kernel_main(popcorn_data *header)
{ {
console cons = load_console(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_init();
interrupts_enable(); interrupts_enable();
cons.puts("Interrupts initialized.\n"); cons.puts("Interrupts initialized.\n");
device_manager devices(header->acpi_table);
// int x = 1 / 0; // int x = 1 / 0;
__asm__ __volatile__("int $15"); // __asm__ __volatile__("int $15");
cons.puts("boogity!"); cons.puts("boogity!");
do_the_set_registers(header); do_the_set_registers(header);

View File

@@ -11,3 +11,9 @@ struct coord {
[[noreturn]] void __kernel_assert(const char *file, unsigned line, const char *message); [[noreturn]] void __kernel_assert(const char *file, unsigned line, const char *message);
#define kassert(stmt, message) if(!(stmt)) { __kernel_assert(__FILE__, __LINE__, (message)); } else {} #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);
}