feat: add acpi rsdp parsing and extend startup memory mapping

This commit is contained in:
Katharina 2026-07-01 23:05:01 +02:00
parent e028f9ba63
commit 6c5c1f5c60
5 changed files with 166 additions and 30 deletions

104
kernel/include/init/acpi.h Normal file
View file

@ -0,0 +1,104 @@
#pragma once
#include "util/number.h"
#include "memory/pointer.h"
namespace acpi {
constexpr uint32_t fold_signature(const char (&text)[5]) {
return static_cast<uint32_t>(static_cast<uint8_t>(text[0]))
| static_cast<uint32_t>(static_cast<uint8_t>(text[1])) << 8
| static_cast<uint32_t>(static_cast<uint8_t>(text[2])) << 16
| 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 {
fadt = fold_signature("FACP"),
madt = fold_signature("APIC"),
hpet = fold_signature("HPET"),
mcfg = fold_signature("MCFG"),
srat = fold_signature("SRAT"),
ssdt = fold_signature("SSDT"),
};
// A folded signature, unfolded back into a null-terminated 4-character string.
struct signature_text_t {
char text[5];
};
inline signature_text_t unfold_signature(uint32_t folded) {
signature_text_t result{};
memcpy(result.text, &folded, 4);
result.text[4] = '\0';
return result;
}
struct sdt_header_t {
uint32_t signature;
uint32_t length;
uint8_t revision;
uint8_t checksum;
char oem_id[6];
char oem_table_id[8];
uint32_t oem_revision;
uint32_t creator_id;
uint32_t creator_revision;
} __attribute__((packed));
static_assert(sizeof(sdt_header_t) == 36);
struct rsdp_t {
char signature[8];
uint8_t checksum;
char oem_id[6];
uint8_t revision;
uint32_t rsdt_address;
uint32_t length;
uint64_t xsdt_address;
uint8_t extended_checksum;
uint8_t reserved[3];
} __attribute__((packed));
static_assert(sizeof(rsdp_t) == 36);
struct Rsdp {
explicit Rsdp(paddr_t rsdp_physical) : physical(rsdp_physical) {}
template<typename Fn>
void for_each_table(Fn&& callback) {
auto root = root_table().access<sdt_header_t>();
auto entry_size = uses_xsdt() ? 8 : 4;
auto count = (root->length - sizeof(sdt_header_t)) / entry_size;
auto entries = reinterpret_cast<const uint8_t*>(root) + sizeof(sdt_header_t);
for (auto index = 0u; index < count; index++) {
uint64_t table_physical = 0;
memcpy(&table_physical, entries + index * entry_size, entry_size);
callback(paddr_t{table_physical});
}
}
template<typename Fn>
void find_table(signature sig, Fn&& callback) {
for_each_table([&](paddr_t table) {
if (table.access<sdt_header_t>()->signature == static_cast<uint32_t>(sig)) {
callback(table);
}
});
}
private:
bool uses_xsdt() {
return physical.access<rsdp_t>()->revision >= 2;
}
paddr_t root_table() {
auto rsdp = physical.access<rsdp_t>();
return uses_xsdt() ? paddr_t{rsdp->xsdt_address} : paddr_t{rsdp->rsdt_address};
}
paddr_t physical;
};
} // namespace acpi

View file

@ -21,17 +21,17 @@ enum class tag_type : uint32_t {
framebuffer = 8, framebuffer = 8,
elf_sections = 9, elf_sections = 9,
apm = 10, apm = 10,
efi32 = 14, efi32 = 11,
efi64 = 15, efi64 = 12,
smbios = 16, smbios = 13,
acpi_old = 17, acpi_old = 14,
acpi_new = 18, acpi_new = 15,
network = 19, network = 16,
efi_mmap = 20, efi_mmap = 17,
efi_bs = 21, efi_bs = 18,
efi32_ih = 22, efi32_ih = 19,
efi64_ih = 23, efi64_ih = 20,
load_base_addr = 24, load_base_addr = 21,
}; };
inline constexpr const char* get_tag_name(tag_type type) { inline constexpr const char* get_tag_name(tag_type type) {

View file

@ -3,6 +3,7 @@
#include "init/init.h" #include "init/init.h"
#include "init/multiboot2.h" #include "init/multiboot2.h"
#include "init/print.h" #include "init/print.h"
#include "init/acpi.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() {
@ -142,30 +143,55 @@ void PhysicalAllocator::init(const multiboot::tag_mmap* multiboot_info) {
PhysicalAllocator::getInstance() = alloc; PhysicalAllocator::getInstance() = alloc;
} }
static void loadMultiboot() { static void setupMemory() {
multiboot::visit_all(overloaded{ multiboot::visit_all(overloaded{
[](const multiboot::tag_mmap* mem) { [](const multiboot::tag_mmap* mem) {
print("Tag Memory Map\n"); PhysicalAllocator::init(mem);
step("memory setup", [mem](){PhysicalAllocator::init(mem);});
}, },
[](const multiboot::tag_string* str) { [](const auto* tag) {}
print("Tag String ("); });
print(multiboot::get_tag_name(str->type)); }
print("): ");
print(str->string); static paddr_t rsdp_physical_of(const uint8_t* rsdp_payload) {
print("\n"); const multiboot::info* mb = multiboot::get_multiboot_info();
uint64_t info_phys = reinterpret_cast<uint64_t>(mb) - high_base;
uint64_t offset_in_info = reinterpret_cast<uint64_t>(rsdp_payload) - reinterpret_cast<uint64_t>(mb);
return paddr_t{info_phys + offset_in_info};
}
static acpi::Rsdp findRsdp() {
optional<paddr_t> rsdp{};
multiboot::visit_all(overloaded{
[&](const multiboot::tag_new_acpi* tag) {
rsdp = rsdp_physical_of(tag->rsdp);
}, },
[](const auto* tag) { [&](const multiboot::tag_old_acpi* tag) {
print("Tag "); if(!rsdp.has_value()) {
print(multiboot::get_tag_name(tag->type)); rsdp = rsdp_physical_of(tag->rsdp);
print("\n");
} }
},
[&](const auto* tag) {}
});
if(!rsdp.has_value()) {
panic("System could not find ACPI RSDP!");
}
return acpi::Rsdp(*rsdp);
}
static void setupAcpi() {
auto rsdp = findRsdp();
rsdp.for_each_table([](paddr_t table) {
auto header = table.access<acpi::sdt_header_t>();
print(acpi::unfold_signature(header->signature).text);
print("\n");
}); });
} }
[[maybe_unused]] [[noreturn]] __attribute__((used)) void init() { [[maybe_unused]] [[noreturn]] __attribute__((used)) void init() {
initFromLow(); initFromLow();
print("Reached init\n"); print("Reached init\n");
step("multiboot", loadMultiboot); step("memory", setupMemory);
step("acpi", setupAcpi);
halt(); halt();
} }

BIN
kernel/src/init/init.o Normal file

Binary file not shown.

View file

@ -225,13 +225,19 @@ __page_level_4:
.align 0x1000 .align 0x1000
__page_level_3_low_1gb_identity_map: __page_level_3_low_1gb_identity_map:
.quad (1 << 0) | (1 << 1) | (1 << 7) | 0x0 .set gib_index, 0
.zero 0xFF8 # rest of table is 0 .rept 512 # identity-map all 512 GiB the PDPT spans, one 1 GiB huge page each
.quad (1 << 0) | (1 << 1) | (1 << 7) | (gib_index << 30)
.set gib_index, gib_index + 1
.endr
.align 0x1000 .align 0x1000
__page_level_3_kernel_1gb_identity_map: __page_level_3_kernel_1gb_identity_map:
.quad (1 << 0) | (1 << 1) | (1 << 7) | 0x0 .set gib_index, 0
.zero 0xFF8 # rest of table is 0 .rept 512 # identity-map all 512 GiB the PDPT spans, one 1 GiB huge page each
.quad (1 << 0) | (1 << 1) | (1 << 7) | (gib_index << 30)
.set gib_index, gib_index + 1
.endr
)"); )");
// startup gdt // startup gdt