feat: madt parsing
This commit is contained in:
parent
6c5c1f5c60
commit
7d0155d8ce
4 changed files with 227 additions and 16 deletions
|
|
@ -12,9 +12,6 @@ constexpr uint32_t fold_signature(const char (&text)[5]) {
|
||||||
| static_cast<uint32_t>(static_cast<uint8_t>(text[3])) << 24;
|
| static_cast<uint32_t>(static_cast<uint8_t>(text[3])) << 24;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Values match the folded signature stored in sdt_header_t::signature. DSDT and
|
|
||||||
// FACS are absent on purpose: they are reached through the FADT, not listed in
|
|
||||||
// the RSDT/XSDT.
|
|
||||||
enum class signature : uint32_t {
|
enum class signature : uint32_t {
|
||||||
fadt = fold_signature("FACP"),
|
fadt = fold_signature("FACP"),
|
||||||
madt = fold_signature("APIC"),
|
madt = fold_signature("APIC"),
|
||||||
|
|
@ -24,7 +21,6 @@ enum class signature : uint32_t {
|
||||||
ssdt = fold_signature("SSDT"),
|
ssdt = fold_signature("SSDT"),
|
||||||
};
|
};
|
||||||
|
|
||||||
// A folded signature, unfolded back into a null-terminated 4-character string.
|
|
||||||
struct signature_text_t {
|
struct signature_text_t {
|
||||||
char text[5];
|
char text[5];
|
||||||
};
|
};
|
||||||
|
|
@ -63,6 +59,8 @@ struct rsdp_t {
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
static_assert(sizeof(rsdp_t) == 36);
|
static_assert(sizeof(rsdp_t) == 36);
|
||||||
|
|
||||||
|
struct madt_t;
|
||||||
|
|
||||||
struct Rsdp {
|
struct Rsdp {
|
||||||
explicit Rsdp(paddr_t rsdp_physical) : physical(rsdp_physical) {}
|
explicit Rsdp(paddr_t rsdp_physical) : physical(rsdp_physical) {}
|
||||||
|
|
||||||
|
|
@ -75,20 +73,33 @@ struct Rsdp {
|
||||||
for (auto index = 0u; index < count; index++) {
|
for (auto index = 0u; index < count; index++) {
|
||||||
uint64_t table_physical = 0;
|
uint64_t table_physical = 0;
|
||||||
memcpy(&table_physical, entries + index * entry_size, entry_size);
|
memcpy(&table_physical, entries + index * entry_size, entry_size);
|
||||||
callback(paddr_t{table_physical});
|
dispatch(paddr_t{table_physical}.access<sdt_header_t>(), callback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
template<typename Fn>
|
template<typename Fn>
|
||||||
void find_table(signature sig, Fn&& callback) {
|
static void dispatch(const sdt_header_t* header, Fn&& fn) {
|
||||||
for_each_table([&](paddr_t table) {
|
#define ACPI_DISPATCH(signature_enum, TableType) \
|
||||||
if (table.access<sdt_header_t>()->signature == static_cast<uint32_t>(sig)) {
|
case signature::signature_enum: \
|
||||||
callback(table);
|
if constexpr (requires { fn(static_cast<const TableType*>(nullptr)); }) { \
|
||||||
}
|
fn(reinterpret_cast<const TableType*>(header)); \
|
||||||
});
|
return; \
|
||||||
|
} \
|
||||||
|
break;
|
||||||
|
|
||||||
|
switch (static_cast<signature>(header->signature)) {
|
||||||
|
ACPI_DISPATCH(madt, madt_t)
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef ACPI_DISPATCH
|
||||||
|
|
||||||
|
if constexpr (requires { fn(static_cast<const sdt_header_t*>(nullptr)); }) {
|
||||||
|
fn(header);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
|
||||||
bool uses_xsdt() {
|
bool uses_xsdt() {
|
||||||
return physical.access<rsdp_t>()->revision >= 2;
|
return physical.access<rsdp_t>()->revision >= 2;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
193
kernel/include/init/apic.h
Normal file
193
kernel/include/init/apic.h
Normal file
|
|
@ -0,0 +1,193 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "init/acpi.h"
|
||||||
|
#include "memory/pointer.h"
|
||||||
|
#include "util/number.h"
|
||||||
|
|
||||||
|
namespace acpi {
|
||||||
|
|
||||||
|
enum class madt_entry_type : uint8_t {
|
||||||
|
local_apic = 0,
|
||||||
|
io_apic = 1,
|
||||||
|
interrupt_source_override = 2,
|
||||||
|
nmi_source = 3,
|
||||||
|
local_apic_nmi = 4,
|
||||||
|
local_apic_address_override = 5,
|
||||||
|
};
|
||||||
|
|
||||||
|
inline constexpr const char *get_madt_entry_type_name(madt_entry_type type) {
|
||||||
|
switch (type) {
|
||||||
|
case madt_entry_type::local_apic:
|
||||||
|
return "local_apic";
|
||||||
|
case madt_entry_type::io_apic:
|
||||||
|
return "io_apic";
|
||||||
|
case madt_entry_type::interrupt_source_override:
|
||||||
|
return "interrupt_source_override";
|
||||||
|
case madt_entry_type::nmi_source:
|
||||||
|
return "nmi_source";
|
||||||
|
case madt_entry_type::local_apic_nmi:
|
||||||
|
return "local_apic_nmi";
|
||||||
|
case madt_entry_type::local_apic_address_override:
|
||||||
|
return "local_apic_address_override";
|
||||||
|
}
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
|
|
||||||
|
struct madt_flags_t {
|
||||||
|
uint32_t dual_8259_present : 1;
|
||||||
|
uint32_t reserved : 31;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(madt_flags_t) == 4);
|
||||||
|
|
||||||
|
struct local_apic_flags_t {
|
||||||
|
uint32_t enabled : 1;
|
||||||
|
uint32_t online_capable : 1;
|
||||||
|
uint32_t reserved : 30;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(local_apic_flags_t) == 4);
|
||||||
|
|
||||||
|
enum class inti_polarity : uint16_t {
|
||||||
|
bus_default = 0,
|
||||||
|
active_high = 1,
|
||||||
|
active_low = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class inti_trigger_mode : uint16_t {
|
||||||
|
bus_default = 0,
|
||||||
|
edge = 1,
|
||||||
|
level = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct inti_flags_t {
|
||||||
|
inti_polarity polarity : 2;
|
||||||
|
inti_trigger_mode trigger_mode : 2;
|
||||||
|
uint16_t reserved : 12;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(inti_flags_t) == 2);
|
||||||
|
|
||||||
|
struct madt_t {
|
||||||
|
sdt_header_t header;
|
||||||
|
uint32_t local_apic_address;
|
||||||
|
madt_flags_t flags;
|
||||||
|
uint8_t entries[0];
|
||||||
|
} __attribute__((packed));
|
||||||
|
static_assert(sizeof(madt_t) == 44);
|
||||||
|
|
||||||
|
struct madt_entry_t {
|
||||||
|
madt_entry_type type;
|
||||||
|
uint8_t length;
|
||||||
|
} __attribute__((packed));
|
||||||
|
static_assert(sizeof(madt_entry_t) == 2);
|
||||||
|
|
||||||
|
struct madt_local_apic_t {
|
||||||
|
madt_entry_type type;
|
||||||
|
uint8_t length;
|
||||||
|
uint8_t acpi_processor_uid;
|
||||||
|
uint8_t apic_id;
|
||||||
|
local_apic_flags_t flags;
|
||||||
|
} __attribute__((packed));
|
||||||
|
static_assert(sizeof(madt_local_apic_t) == 8);
|
||||||
|
|
||||||
|
struct madt_io_apic_t {
|
||||||
|
madt_entry_type type;
|
||||||
|
uint8_t length;
|
||||||
|
uint8_t io_apic_id;
|
||||||
|
uint8_t reserved;
|
||||||
|
uint32_t io_apic_address;
|
||||||
|
uint32_t global_system_interrupt_base;
|
||||||
|
} __attribute__((packed));
|
||||||
|
static_assert(sizeof(madt_io_apic_t) == 12);
|
||||||
|
|
||||||
|
struct madt_interrupt_source_override_t {
|
||||||
|
madt_entry_type type;
|
||||||
|
uint8_t length;
|
||||||
|
uint8_t bus; // always 0 (ISA)
|
||||||
|
uint8_t source; // ISA IRQ number
|
||||||
|
uint32_t global_system_interrupt;
|
||||||
|
inti_flags_t flags;
|
||||||
|
} __attribute__((packed));
|
||||||
|
static_assert(sizeof(madt_interrupt_source_override_t) == 10);
|
||||||
|
|
||||||
|
struct madt_nmi_source_t {
|
||||||
|
madt_entry_type type;
|
||||||
|
uint8_t length;
|
||||||
|
inti_flags_t flags;
|
||||||
|
uint32_t global_system_interrupt;
|
||||||
|
} __attribute__((packed));
|
||||||
|
static_assert(sizeof(madt_nmi_source_t) == 8);
|
||||||
|
|
||||||
|
struct madt_local_apic_nmi_t {
|
||||||
|
madt_entry_type type;
|
||||||
|
uint8_t length;
|
||||||
|
uint8_t acpi_processor_uid; // 0xFF: applies to all processors
|
||||||
|
inti_flags_t flags;
|
||||||
|
uint8_t lint; // local APIC LINT# the NMI is wired to
|
||||||
|
} __attribute__((packed));
|
||||||
|
static_assert(sizeof(madt_local_apic_nmi_t) == 6);
|
||||||
|
|
||||||
|
struct madt_local_apic_address_override_t {
|
||||||
|
madt_entry_type type;
|
||||||
|
uint8_t length;
|
||||||
|
uint16_t reserved;
|
||||||
|
uint64_t local_apic_address;
|
||||||
|
} __attribute__((packed));
|
||||||
|
static_assert(sizeof(madt_local_apic_address_override_t) == 12);
|
||||||
|
|
||||||
|
struct Madt {
|
||||||
|
explicit Madt(paddr_t madt_physical)
|
||||||
|
: table(madt_physical.access<madt_t>()) {}
|
||||||
|
explicit Madt(const madt_t *madt_table) : table(madt_table) {}
|
||||||
|
|
||||||
|
paddr_t local_apic_address() {
|
||||||
|
uint64_t address = table->local_apic_address;
|
||||||
|
for_each_entry(
|
||||||
|
[&](const madt_local_apic_address_override_t *override_entry) {
|
||||||
|
address = override_entry->local_apic_address;
|
||||||
|
});
|
||||||
|
return paddr_t{address};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool has_legacy_pic() { return table->flags.dual_8259_present != 0; }
|
||||||
|
|
||||||
|
template <typename Fn> void for_each_entry(Fn &&callback) {
|
||||||
|
auto ptr = table->entries;
|
||||||
|
const auto end =
|
||||||
|
reinterpret_cast<const uint8_t *>(table) + table->header.length;
|
||||||
|
while (ptr < end) {
|
||||||
|
auto entry = reinterpret_cast<const madt_entry_t *>(ptr);
|
||||||
|
if (entry->length < sizeof(madt_entry_t)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
dispatch(entry, callback);
|
||||||
|
ptr += entry->length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
template <typename Fn>
|
||||||
|
static void dispatch(const madt_entry_t *entry, Fn &&fn) {
|
||||||
|
#define MADT_DISPATCH(entry_enum, EntryType) \
|
||||||
|
case madt_entry_type::entry_enum: \
|
||||||
|
if constexpr (requires { fn(static_cast<const EntryType *>(nullptr)); }) \
|
||||||
|
fn(reinterpret_cast<const EntryType *>(entry)); \
|
||||||
|
break;
|
||||||
|
|
||||||
|
switch (entry->type) {
|
||||||
|
MADT_DISPATCH(local_apic, madt_local_apic_t)
|
||||||
|
MADT_DISPATCH(io_apic, madt_io_apic_t)
|
||||||
|
MADT_DISPATCH(interrupt_source_override, madt_interrupt_source_override_t)
|
||||||
|
MADT_DISPATCH(nmi_source, madt_nmi_source_t)
|
||||||
|
MADT_DISPATCH(local_apic_nmi, madt_local_apic_nmi_t)
|
||||||
|
MADT_DISPATCH(local_apic_address_override,
|
||||||
|
madt_local_apic_address_override_t)
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef MADT_DISPATCH
|
||||||
|
}
|
||||||
|
|
||||||
|
const madt_t *table;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace acpi
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
#include "init/multiboot2.h"
|
#include "init/multiboot2.h"
|
||||||
#include "init/print.h"
|
#include "init/print.h"
|
||||||
#include "init/acpi.h"
|
#include "init/acpi.h"
|
||||||
|
#include "init/apic.h"
|
||||||
#include "memory/allocator.h"
|
#include "memory/allocator.h"
|
||||||
|
|
||||||
[[maybe_unused]] [[noreturn]] __attribute__((used)) static void halt() {
|
[[maybe_unused]] [[noreturn]] __attribute__((used)) static void halt() {
|
||||||
|
|
@ -179,12 +180,18 @@ static acpi::Rsdp findRsdp() {
|
||||||
return acpi::Rsdp(*rsdp);
|
return acpi::Rsdp(*rsdp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct AcpiDiscoveryResult {
|
||||||
|
optional<acpi::Rsdp> rsdp;
|
||||||
|
optional<acpi::Madt> madt;
|
||||||
|
};
|
||||||
|
|
||||||
static void setupAcpi() {
|
static void setupAcpi() {
|
||||||
auto rsdp = findRsdp();
|
auto rsdp = findRsdp();
|
||||||
rsdp.for_each_table([](paddr_t table) {
|
rsdp.for_each_table(overloaded{
|
||||||
auto header = table.access<acpi::sdt_header_t>();
|
[&](const acpi::sdt_header_t* header) {
|
||||||
print(acpi::unfold_signature(header->signature).text);
|
print(acpi::unfold_signature(header->signature).text);
|
||||||
print("\n");
|
print("\n");
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue