diff --git a/kernel/include/init/acpi.h b/kernel/include/init/acpi.h new file mode 100644 index 0000000..39675b1 --- /dev/null +++ b/kernel/include/init/acpi.h @@ -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(static_cast(text[0])) + | static_cast(static_cast(text[1])) << 8 + | static_cast(static_cast(text[2])) << 16 + | static_cast(static_cast(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 + void for_each_table(Fn&& callback) { + auto root = root_table().access(); + auto entry_size = uses_xsdt() ? 8 : 4; + auto count = (root->length - sizeof(sdt_header_t)) / entry_size; + auto entries = reinterpret_cast(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 + void find_table(signature sig, Fn&& callback) { + for_each_table([&](paddr_t table) { + if (table.access()->signature == static_cast(sig)) { + callback(table); + } + }); + } + +private: + bool uses_xsdt() { + return physical.access()->revision >= 2; + } + + paddr_t root_table() { + auto rsdp = physical.access(); + return uses_xsdt() ? paddr_t{rsdp->xsdt_address} : paddr_t{rsdp->rsdt_address}; + } + + paddr_t physical; +}; + +} // namespace acpi diff --git a/kernel/include/init/multiboot2.h b/kernel/include/init/multiboot2.h index 0313fc7..7f8e4ea 100644 --- a/kernel/include/init/multiboot2.h +++ b/kernel/include/init/multiboot2.h @@ -21,17 +21,17 @@ enum class tag_type : uint32_t { framebuffer = 8, elf_sections = 9, apm = 10, - efi32 = 14, - efi64 = 15, - smbios = 16, - acpi_old = 17, - acpi_new = 18, - network = 19, - efi_mmap = 20, - efi_bs = 21, - efi32_ih = 22, - efi64_ih = 23, - load_base_addr = 24, + efi32 = 11, + efi64 = 12, + smbios = 13, + acpi_old = 14, + acpi_new = 15, + network = 16, + efi_mmap = 17, + efi_bs = 18, + efi32_ih = 19, + efi64_ih = 20, + load_base_addr = 21, }; inline constexpr const char* get_tag_name(tag_type type) { diff --git a/kernel/src/init/init.cpp b/kernel/src/init/init.cpp index c92347b..07d2ed6 100644 --- a/kernel/src/init/init.cpp +++ b/kernel/src/init/init.cpp @@ -3,6 +3,7 @@ #include "init/init.h" #include "init/multiboot2.h" #include "init/print.h" +#include "init/acpi.h" #include "memory/allocator.h" [[maybe_unused]] [[noreturn]] __attribute__((used)) static void halt() { @@ -142,30 +143,55 @@ void PhysicalAllocator::init(const multiboot::tag_mmap* multiboot_info) { PhysicalAllocator::getInstance() = alloc; } -static void loadMultiboot() { +static void setupMemory() { multiboot::visit_all(overloaded{ [](const multiboot::tag_mmap* mem) { - print("Tag Memory Map\n"); - step("memory setup", [mem](){PhysicalAllocator::init(mem);}); + PhysicalAllocator::init(mem); }, - [](const multiboot::tag_string* str) { - print("Tag String ("); - print(multiboot::get_tag_name(str->type)); - print("): "); - print(str->string); - print("\n"); + [](const auto* tag) {} + }); +} + +static paddr_t rsdp_physical_of(const uint8_t* rsdp_payload) { + const multiboot::info* mb = multiboot::get_multiboot_info(); + uint64_t info_phys = reinterpret_cast(mb) - high_base; + uint64_t offset_in_info = reinterpret_cast(rsdp_payload) - reinterpret_cast(mb); + return paddr_t{info_phys + offset_in_info}; +} + +static acpi::Rsdp findRsdp() { + optional rsdp{}; + multiboot::visit_all(overloaded{ + [&](const multiboot::tag_new_acpi* tag) { + rsdp = rsdp_physical_of(tag->rsdp); }, - [](const auto* tag) { - print("Tag "); - print(multiboot::get_tag_name(tag->type)); - print("\n"); - } + [&](const multiboot::tag_old_acpi* tag) { + if(!rsdp.has_value()) { + rsdp = rsdp_physical_of(tag->rsdp); + } + }, + [&](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(); + print(acpi::unfold_signature(header->signature).text); + print("\n"); }); } [[maybe_unused]] [[noreturn]] __attribute__((used)) void init() { initFromLow(); print("Reached init\n"); - step("multiboot", loadMultiboot); + step("memory", setupMemory); + step("acpi", setupAcpi); halt(); } diff --git a/kernel/src/init/init.o b/kernel/src/init/init.o new file mode 100644 index 0000000..5387e41 Binary files /dev/null and b/kernel/src/init/init.o differ diff --git a/kernel/src/startup/entry.cpp b/kernel/src/startup/entry.cpp index 02796c8..fe808b7 100644 --- a/kernel/src/startup/entry.cpp +++ b/kernel/src/startup/entry.cpp @@ -225,13 +225,19 @@ __page_level_4: .align 0x1000 __page_level_3_low_1gb_identity_map: - .quad (1 << 0) | (1 << 1) | (1 << 7) | 0x0 - .zero 0xFF8 # rest of table is 0 + .set gib_index, 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 __page_level_3_kernel_1gb_identity_map: - .quad (1 << 0) | (1 << 1) | (1 << 7) | 0x0 - .zero 0xFF8 # rest of table is 0 + .set gib_index, 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