From 3e1e37bf0308dca013bf9254ac8bfa4c4bc43151 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Wed, 7 Jun 2023 16:24:13 -0700 Subject: [PATCH] Probe RSDP for PCIe Config --- CMakeLists.txt | 3 +- zion/CMakeLists.txt | 1 + zion/boot/acpi.cpp | 171 ++++++++++++++++++++++++++++++++++++++++ zion/boot/acpi.h | 9 +++ zion/boot/boot_info.cpp | 11 +++ zion/boot/boot_info.h | 2 + zion/zion.cpp | 4 + 7 files changed, 200 insertions(+), 1 deletion(-) create mode 100644 zion/boot/acpi.cpp create mode 100644 zion/boot/acpi.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 2c67361..aa209f0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,7 +16,8 @@ add_subdirectory(zion) add_subdirectory(lib) add_subdirectory(sys) -set(QEMU_CMD qemu-system-x86_64 -d guest_errors -m 1G -serial stdio -hda disk.img) +# Use machine q35 to access PCI devices. +set(QEMU_CMD qemu-system-x86_64 -machine q35 -d guest_errors -m 1G -serial stdio -hda disk.img) add_custom_command( OUTPUT disk.img diff --git a/zion/CMakeLists.txt b/zion/CMakeLists.txt index 06f76a5..bb3f52e 100644 --- a/zion/CMakeLists.txt +++ b/zion/CMakeLists.txt @@ -1,4 +1,5 @@ add_executable(zion + boot/acpi.cpp boot/boot_info.cpp capability/capability.cpp common/gdt.cpp diff --git a/zion/boot/acpi.cpp b/zion/boot/acpi.cpp new file mode 100644 index 0000000..6cd5be6 --- /dev/null +++ b/zion/boot/acpi.cpp @@ -0,0 +1,171 @@ +#include "boot/acpi.h" + +#include "boot/boot_info.h" +#include "debug/debug.h" + +#define K_ACPI_DEBUG 0 + +namespace { + +static uint64_t gPcieEcBase = 0x0; +static uint64_t gPcieEcSize = 0x0; + +struct RsdpDescriptor { + char signature[8]; + uint8_t checksum; + char oem_id[6]; + uint8_t revision; + uint32_t rsdt_addr; + uint32_t length; + uint64_t xsdt_addr; + uint8_t ext_checksum; + uint8_t reserved[3]; +} __attribute__((packed)); + +struct SdtHeader { + char signature[4]; + 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)); + +bool streq(const char* a, const char* b, uint8_t len) { + for (uint8_t i = 0; i < len; i++) { + if (a[i] != b[i]) return false; + } + return true; +} + +bool checksum(uint8_t* addr, uint8_t num_bytes) { + uint8_t check_cnt = 0; + for (uint8_t i = 0; i < num_bytes; i++) { + check_cnt += addr[i]; + } + return check_cnt == 0; +} + +void dbgsz(const char* c, uint8_t cnt) { + char cl[cnt + 1]; + + for (uint8_t i = 0; i < cnt; i++) { + cl[i] = c[i]; + } + cl[cnt] = '\0'; + dbgln(cl); +} + +uint8_t* SdtDataStart(SdtHeader* sdt) { + return reinterpret_cast(sdt) + sizeof(SdtHeader); +} + +void ParseMcfg(SdtHeader* rsdt) { +#if K_ACPI_DEBUG + dbgsz(rsdt->signature, 4); +#endif + uint32_t size = (rsdt->length - sizeof(SdtHeader)) / 16; + uint64_t* entries = reinterpret_cast(SdtDataStart(rsdt)); + // There are 8 reserved bytes at the end of the table. + entries++; + for (uint32_t i = 0; i < size; i++) { + uint64_t base_ecm_addr = entries[2 * i]; + uint64_t bus_info = entries[2 * i + 1]; + if (bus_info != 0xff000000) { +#if K_ACPI_DEBUG + dbgln("WARN: Unexpected bus-info for PCI EC. Mem region will be wrong.") +#endif + } + gPcieEcBase = base_ecm_addr; + uint64_t num_busses = 0x100; + uint64_t dev_per_bus = 0x20; + uint64_t fns_per_dev = 0x8; + uint64_t bytes_per_fn = 0x1000; + gPcieEcSize = num_busses * dev_per_bus * fns_per_dev * bytes_per_fn; +#if K_ACPI_DEBUG + dbgln("PCI Map: %m:%x", gPcieEcBase, gPcieEcSize); +#endif + } +} + +void ParseSdt(SdtHeader* rsdt) { + if (!checksum((uint8_t*)rsdt, rsdt->length)) { + dbgln("Bad RSDT checksum."); + return; + } + if (streq(rsdt->signature, "MCFG", 4)) { + ParseMcfg(rsdt); + } else { +#if K_ACPI_DEBUG + dbgln("Unhandled:"); + dbgsz(rsdt->signature, 4); +#endif + } +} + +void ProbeRsdt(SdtHeader* rsdt) { + if (!checksum((uint8_t*)rsdt, rsdt->length)) { + dbgln("Bad RSDT checksum."); + return; + } +#if K_ACPI_DEBUG + dbgsz(rsdt->signature, 4); +#endif + uint32_t size = (rsdt->length - sizeof(SdtHeader)) / 4; + uint32_t* entries = reinterpret_cast(SdtDataStart(rsdt)); + for (uint32_t i = 0; i < size; i++) { + SdtHeader* table = reinterpret_cast(entries[i]); + ParseSdt(table); + } +} + +} // namespace + +void ProbeRsdp() { + void* rsdp_addr = boot::GetRsdpAddr(); + RsdpDescriptor* rsdp = static_cast(rsdp_addr); + if (!streq(rsdp->signature, "RSD PTR ", 8)) { + dbgln("Invalid Rsdp!"); + return; + } + + // Checks V1 up to rsdt_addr. + if (!checksum((uint8_t*)rsdp_addr, 20)) { + dbgln("Rsdp Check failed"); + return; + } + +#if K_ACPI_DEBUG + dbgln("ACPI Ver %u", rsdp->revision); + dbgln("RSDT Addr: %m", rsdp->rsdt_addr); +#endif + + ProbeRsdt(reinterpret_cast(rsdp->rsdt_addr)); + + if (rsdp->revision == 0) { + return; + } + + // Checks V2 (entire structure). + if (!checksum((uint8_t*)rsdp_addr, rsdp->length)) { + dbgln("Rsdp ext checksum failed"); + return; + } + +#if K_ACPI_DEBUG + dbgln("XSDT Addr: %m", rsdp->xsdt_addr); +#endif +} + +z_err_t GetPciExtendedConfiguration(uint64_t* base, uint64_t* offset) { + if (gPcieEcSize == 0) { + return Z_ERR_NOT_FOUND; + } + + *base = gPcieEcBase; + *offset = gPcieEcSize; + return Z_OK; +} diff --git a/zion/boot/acpi.h b/zion/boot/acpi.h new file mode 100644 index 0000000..60cac00 --- /dev/null +++ b/zion/boot/acpi.h @@ -0,0 +1,9 @@ +#pragma once + +#include + +#include "include/zerrors.h" + +void ProbeRsdp(); + +z_err_t GetPciExtendedConfiguration(uint64_t* base, uint64_t* offset); diff --git a/zion/boot/boot_info.cpp b/zion/boot/boot_info.cpp index 2ed0e58..04bfbac 100644 --- a/zion/boot/boot_info.cpp +++ b/zion/boot/boot_info.cpp @@ -36,4 +36,15 @@ const limine_module_response& GetModules() { return *gModuleRequest.response; } +static volatile struct limine_rsdp_request gRsdpRequest { + .id = LIMINE_RSDP_REQUEST, .revision = 0, .response = 0, +}; + +void* GetRsdpAddr() { + if (!gRsdpRequest.response) { + panic("No rsdp response from limine"); + } + return gRsdpRequest.response->address; +} + } // namespace boot diff --git a/zion/boot/boot_info.h b/zion/boot/boot_info.h index 15e6e40..814b79a 100644 --- a/zion/boot/boot_info.h +++ b/zion/boot/boot_info.h @@ -9,4 +9,6 @@ uint64_t GetHigherHalfDirectMap(); const limine_module_response& GetModules(); +void* GetRsdpAddr(); + } // namespace boot diff --git a/zion/zion.cpp b/zion/zion.cpp index abdc4a8..62808c2 100644 --- a/zion/zion.cpp +++ b/zion/zion.cpp @@ -1,5 +1,6 @@ #include +#include "boot/acpi.h" #include "common/gdt.h" #include "debug/debug.h" #include "interrupt/interrupt.h" @@ -25,6 +26,9 @@ extern "C" void zion() { dbgln("[boot] Memory allocations available now."); + dbgln("[boot] Probing Hardware"); + ProbeRsdp(); + dbgln("[boot] Init Kernel Stack Manager."); KernelStackManager::Init();