mirror of
https://github.com/justinian/jsix.git
synced 2025-12-10 08:24:32 -08:00
Parse the ACPI XSDT and find ACPI tables.
This commit is contained in:
43
src/modules/main/acpi_tables.h
Normal file
43
src/modules/main/acpi_tables.h
Normal 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;
|
||||
}
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#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 <typename T>
|
||||
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<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;
|
||||
}
|
||||
|
||||
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<const Acpi10RSDPDescriptor *>(root_table);
|
||||
const acpi1_rsdp *acpi1 =
|
||||
reinterpret_cast<const acpi1_rsdp *>(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<const Acpi20RSDPDescriptor *>(acpi1);
|
||||
const acpi2_rsdp *acpi2 =
|
||||
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.");
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user