aboutsummaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorFelix Morgner <felix.morgner@ost.ch>2026-04-06 19:04:40 +0200
committerFelix Morgner <felix.morgner@ost.ch>2026-04-06 19:04:40 +0200
commitfe26083101537df306153e7bea7c291a041897f7 (patch)
tree0f26687fb172fc1852e9c4d58c351a76e9ceb50c /kernel
parent2a3575a267dede6a364386c0bd6edcff92421f0d (diff)
parentd5c2e101d62f6b4b69c45c127e7a729d246da566 (diff)
downloadteachos-fe26083101537df306153e7bea7c291a041897f7.tar.xz
teachos-fe26083101537df306153e7bea7c291a041897f7.zip
Merge branch 'fmorgner/develop-BA-FS26/apci' into develop-BA-FS26
This patchset introduces basic support for ACPI. Currently, the only user of that support is the CPU discovery subsystem. It uses the processed ACPI information to initialize CPU core devices and their associated local APICs.
Diffstat (limited to 'kernel')
-rw-r--r--kernel/CMakeLists.txt6
-rw-r--r--kernel/include/kernel/acpi/manager.hpp32
-rw-r--r--kernel/include/kernel/devices/cpu.hpp33
-rw-r--r--kernel/include/kernel/memory/block_list_allocator.hpp10
-rw-r--r--kernel/kapi/acpi.cpp174
-rw-r--r--kernel/kapi/devices.cpp5
-rw-r--r--kernel/kapi/devices/bus.cpp65
-rw-r--r--kernel/kapi/devices/device.cpp35
-rw-r--r--kernel/kapi/platform.cpp27
-rw-r--r--kernel/src/acpi/manager.cpp103
-rw-r--r--kernel/src/devices/cpu.cpp45
-rw-r--r--kernel/src/main.cpp10
12 files changed, 540 insertions, 5 deletions
diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt
index 9868eb9..22513ea 100644
--- a/kernel/CMakeLists.txt
+++ b/kernel/CMakeLists.txt
@@ -1,11 +1,15 @@
add_library("kernel_objs" OBJECT
# Platform-independent KAPI implementation
+ "kapi/acpi.cpp"
"kapi/boot_modules.cpp"
"kapi/cio.cpp"
"kapi/cpu.cpp"
"kapi/devices.cpp"
+ "kapi/devices/bus.cpp"
+ "kapi/devices/device.cpp"
"kapi/interrupts.cpp"
"kapi/memory.cpp"
+ "kapi/platform.cpp"
"kapi/system.cpp"
# KSTD OS Implementation
@@ -13,11 +17,13 @@ add_library("kernel_objs" OBJECT
"kstd/print.cpp"
# Kernel Implementation
+ "src/acpi/manager.cpp"
"src/memory/bitmap_allocator.cpp"
"src/memory/block_list_allocator.cpp"
"src/memory.cpp"
"src/devices/block_device.cpp"
"src/devices/block_device_utils.cpp"
+ "src/devices/cpu.cpp"
"src/devices/root_bus.cpp"
"src/devices/storage/controller.cpp"
"src/devices/storage/management.cpp"
diff --git a/kernel/include/kernel/acpi/manager.hpp b/kernel/include/kernel/acpi/manager.hpp
new file mode 100644
index 0000000..fae59a6
--- /dev/null
+++ b/kernel/include/kernel/acpi/manager.hpp
@@ -0,0 +1,32 @@
+#ifndef TEACHOS_KERNEL_ACPI_MANAGER_HPP
+#define TEACHOS_KERNEL_ACPI_MANAGER_HPP
+
+#include "kapi/acpi.hpp"
+
+#include <kstd/flat_map>
+#include <kstd/memory>
+#include <kstd/vector>
+
+#include <string_view>
+
+namespace kernel::acpi
+{
+
+ struct manager
+ {
+ explicit manager(kapi::acpi::root_system_description_pointer const & sdp);
+
+ auto load_tables() -> bool;
+
+ auto get_table(std::string_view signature) -> kstd::observer_ptr<kapi::acpi::system_description_table_header const>;
+
+ private:
+ kapi::acpi::root_system_description_pointer const * m_sdp{};
+ kapi::acpi::system_description_table_header const * m_rsdt{};
+ kstd::flat_map<std::string_view, kapi::acpi::system_description_table_header const *> m_tables{};
+ bool m_extended{};
+ };
+
+} // namespace kernel::acpi
+
+#endif
diff --git a/kernel/include/kernel/devices/cpu.hpp b/kernel/include/kernel/devices/cpu.hpp
new file mode 100644
index 0000000..b056665
--- /dev/null
+++ b/kernel/include/kernel/devices/cpu.hpp
@@ -0,0 +1,33 @@
+#ifndef TEACHOS_KERNEL_DEVICES_CPU_HPP
+#define TEACHOS_KERNEL_DEVICES_CPU_HPP
+
+#include "kapi/devices.hpp"
+
+#include <cstddef>
+#include <cstdint>
+
+namespace kernel::devices
+{
+
+ struct cpu final : kapi::devices::bus
+ {
+ struct core final : kapi::devices::bus
+ {
+ explicit core(std::size_t major_number, std::size_t minor_number, std::uint64_t hardware_id, bool is_bsp);
+
+ [[nodiscard]] auto hardware_id() const -> std::uint64_t;
+ [[nodiscard]] auto is_bsp() const -> bool;
+
+ private:
+ std::uint64_t m_hardware_id;
+ bool m_is_bsp;
+ };
+
+ explicit cpu(std::size_t major_number);
+
+ auto probe() -> bool final;
+ };
+
+} // namespace kernel::devices
+
+#endif \ No newline at end of file
diff --git a/kernel/include/kernel/memory/block_list_allocator.hpp b/kernel/include/kernel/memory/block_list_allocator.hpp
index f319097..de89f3b 100644
--- a/kernel/include/kernel/memory/block_list_allocator.hpp
+++ b/kernel/include/kernel/memory/block_list_allocator.hpp
@@ -43,10 +43,10 @@ namespace kernel::memory
private:
struct block_header final
{
- kstd::units::bytes usable_size;
- bool free;
- block_header * next;
- block_header * prev;
+ kstd::units::bytes usable_size{};
+ bool free{};
+ block_header * next{};
+ block_header * prev{};
};
//! The size of the metadata required for each allocated block.
@@ -87,4 +87,4 @@ namespace kernel::memory
} // namespace kernel::memory
-#endif \ No newline at end of file
+#endif
diff --git a/kernel/kapi/acpi.cpp b/kernel/kapi/acpi.cpp
new file mode 100644
index 0000000..1283d7e
--- /dev/null
+++ b/kernel/kapi/acpi.cpp
@@ -0,0 +1,174 @@
+#include "kapi/acpi.hpp"
+
+#include "kapi/memory.hpp"
+#include "kapi/system.hpp"
+
+#include "kernel/acpi/manager.hpp"
+
+#include <kstd/memory>
+#include <kstd/units>
+
+#include <algorithm>
+#include <atomic>
+#include <bit>
+#include <cstddef>
+#include <cstdint>
+#include <optional>
+#include <span>
+#include <string_view>
+
+namespace kapi::acpi
+{
+
+ namespace
+ {
+ auto constinit manager = std::optional<kernel::acpi::manager>{};
+ } // namespace
+
+ auto root_system_description_pointer::oem_id() const noexcept -> std::string_view
+ {
+ return {m_oem_id.data(), m_oem_id.size()};
+ }
+
+ auto root_system_description_pointer::revision() const noexcept -> std::uint8_t
+ {
+ return m_revision;
+ }
+
+ auto root_system_description_pointer::signature() const noexcept -> std::string_view
+ {
+ return {m_signature.data(), m_signature.size()};
+ }
+
+ auto root_system_description_pointer::table_address() const noexcept -> memory::physical_address
+ {
+ auto raw = std::bit_cast<std::uint32_t>(m_rsdt_address);
+ return memory::physical_address{static_cast<std::uintptr_t>(raw)};
+ }
+
+ auto root_system_description_pointer::validate() const noexcept -> bool
+ {
+ return validate_checksum({reinterpret_cast<std::byte const *>(this), sizeof(root_system_description_pointer)});
+ }
+
+ auto extended_system_description_pointer::length() const noexcept -> kstd::units::bytes
+ {
+ return kstd::units::bytes{m_length};
+ }
+
+ auto extended_system_description_pointer::table_address() const noexcept -> memory::physical_address
+ {
+ return memory::physical_address{std::bit_cast<std::uintptr_t>(m_xsdt_address)};
+ }
+
+ auto extended_system_description_pointer::validate() const noexcept -> bool
+ {
+ return validate_checksum({reinterpret_cast<std::byte const *>(this), m_length});
+ }
+
+ [[nodiscard]] auto system_description_table_header::checksum() const noexcept -> std::uint8_t
+ {
+ return m_checksum;
+ }
+
+ [[nodiscard]] auto system_description_table_header::creator_revision() const noexcept -> std::uint32_t
+ {
+ return m_creator_revision;
+ }
+
+ [[nodiscard]] auto system_description_table_header::creator_id() const noexcept -> std::uint32_t
+ {
+ return m_creator_id;
+ }
+
+ [[nodiscard]] auto system_description_table_header::length() const noexcept -> kstd::units::bytes
+ {
+ return kstd::units::bytes{m_length};
+ }
+
+ [[nodiscard]] auto system_description_table_header::oem_id() const noexcept -> std::string_view
+ {
+ return {m_oem_id.data(), m_oem_id.size()};
+ }
+
+ [[nodiscard]] auto system_description_table_header::oem_revision() const noexcept -> std::uint32_t
+ {
+ return m_oem_revision;
+ }
+
+ [[nodiscard]] auto system_description_table_header::oem_table_id() const noexcept -> std::string_view
+ {
+ return {m_oem_table_id.data(), m_oem_table_id.size()};
+ }
+
+ [[nodiscard]] auto system_description_table_header::revision() const noexcept -> std::uint8_t
+ {
+ return m_revision;
+ }
+
+ [[nodiscard]] auto system_description_table_header::signature() const noexcept -> std::string_view
+ {
+ return {m_signature.data(), m_signature.size()};
+ }
+
+ [[nodiscard]] auto madt_header::local_interrupt_controller_address() const noexcept -> memory::physical_address
+ {
+ return memory::physical_address{static_cast<std::uintptr_t>(m_local_interrupt_controller_address)};
+ }
+
+ [[nodiscard]] auto madt_header::flags() const noexcept -> std::uint32_t
+ {
+ return m_flags;
+ }
+
+ [[nodiscard]] auto madt_subtable_header::type() const noexcept -> std::uint8_t
+ {
+ return m_type;
+ }
+
+ [[nodiscard]] auto madt_subtable_header::length() const noexcept -> std::size_t
+ {
+ return m_length;
+ }
+
+ [[nodiscard]] auto madt_local_apic::apic_id() const noexcept -> std::uint8_t
+ {
+ return m_apic_id;
+ }
+
+ [[nodiscard]] auto madt_local_apic::flags() const noexcept -> std::uint32_t
+ {
+ return m_flags;
+ }
+
+ [[nodiscard]] auto madt_local_apic::processor_id() const noexcept -> std::uint32_t
+ {
+ return m_processor_id;
+ }
+
+ auto init(root_system_description_pointer const & sdp) -> bool
+ {
+ auto static constinit initialized = std::atomic_flag{};
+ if (initialized.test_and_set())
+ {
+ system::panic("[OS:ACPI] The ACPI manager has already been initialized!");
+ }
+
+ manager.emplace(sdp);
+ return manager->load_tables();
+ }
+
+ auto validate_checksum(std::span<std::byte const> data) -> bool
+ {
+ auto sum = std::ranges::fold_left(data, std::uint8_t{}, [](auto acc, auto byte) {
+ return static_cast<std::uint8_t>(acc + static_cast<std::uint8_t>(byte));
+ });
+ return sum == 0;
+ }
+
+ auto get_table(std::string_view signature) -> kstd::observer_ptr<system_description_table_header const>
+ {
+ return manager->get_table(signature);
+ }
+
+}; // namespace kapi::acpi
diff --git a/kernel/kapi/devices.cpp b/kernel/kapi/devices.cpp
index 031f2c9..dad1fe4 100644
--- a/kernel/kapi/devices.cpp
+++ b/kernel/kapi/devices.cpp
@@ -2,6 +2,7 @@
#include "kapi/system.hpp"
+#include "kernel/devices/cpu.hpp"
#include "kernel/devices/root_bus.hpp"
#include <kstd/flat_map>
@@ -35,6 +36,10 @@ namespace kapi::devices
auto & bus = root_bus.emplace();
register_device(bus);
bus.init();
+
+ auto cpu_major = allocate_major_number();
+ auto cpu = kstd::make_unique<kernel::devices::cpu>(cpu_major);
+ bus.add_child(std::move(cpu));
}
auto get_root_bus() -> bus &
diff --git a/kernel/kapi/devices/bus.cpp b/kernel/kapi/devices/bus.cpp
new file mode 100644
index 0000000..68874c4
--- /dev/null
+++ b/kernel/kapi/devices/bus.cpp
@@ -0,0 +1,65 @@
+#include "kapi/devices/bus.hpp"
+
+#include "kapi/devices.hpp"
+#include "kapi/system.hpp"
+
+#include <kstd/memory>
+#include <kstd/print>
+#include <kstd/string>
+#include <kstd/vector>
+
+#include <algorithm>
+#include <cstddef>
+#include <utility>
+
+namespace kapi::devices
+{
+ bus::bus(std::size_t major, std::size_t minor, kstd::string const & name)
+ : device(major, minor, name)
+ {}
+
+ auto bus::init() -> bool
+ {
+ if (m_initialized.test_and_set())
+ {
+ return true;
+ }
+
+ if (!probe())
+ {
+ return false;
+ }
+
+ return std::ranges::fold_left(m_devices, true, [&](bool acc, auto & child) -> bool {
+ kstd::println("[OS:DEV] Initializing child device {}@{}", child->name(), name());
+ return child->init() && acc;
+ });
+ }
+
+ auto bus::add_child(kstd::unique_ptr<device> child) -> void
+ {
+ auto observer = m_observers.emplace_back(child.get());
+ m_devices.push_back(std::move(child));
+ kapi::devices::register_device(*observer);
+
+ if (m_initialized.test())
+ {
+ kstd::println("[OS:DEV] Initializing child device {}@{}", observer->name(), name());
+ if (!observer->init())
+ {
+ kapi::system::panic("[OS:DEV] Failed to initialize child device");
+ }
+ }
+ }
+
+ [[nodiscard]] auto bus::children() const -> kstd::vector<kstd::observer_ptr<device>> const &
+ {
+ return m_observers;
+ }
+
+ auto bus::probe() -> bool
+ {
+ return true;
+ }
+
+} // namespace kapi::devices \ No newline at end of file
diff --git a/kernel/kapi/devices/device.cpp b/kernel/kapi/devices/device.cpp
new file mode 100644
index 0000000..9f7a404
--- /dev/null
+++ b/kernel/kapi/devices/device.cpp
@@ -0,0 +1,35 @@
+#include "kapi/devices/device.hpp"
+
+#include <kstd/string>
+
+#include <cstddef>
+
+namespace kapi::devices
+{
+ device::device(size_t major, size_t minor, kstd::string const & name)
+ : m_major(major)
+ , m_minor(minor)
+ , m_name(name)
+ {}
+
+ [[nodiscard]] auto device::major() const -> size_t
+ {
+ return m_major;
+ }
+
+ [[nodiscard]] auto device::minor() const -> size_t
+ {
+ return m_minor;
+ }
+
+ [[nodiscard]] auto device::name() const -> kstd::string const &
+ {
+ return m_name;
+ }
+
+ [[nodiscard]] auto device::is_block_device() const -> bool
+ {
+ return false;
+ }
+
+} // namespace kapi::devices \ No newline at end of file
diff --git a/kernel/kapi/platform.cpp b/kernel/kapi/platform.cpp
new file mode 100644
index 0000000..7638cf9
--- /dev/null
+++ b/kernel/kapi/platform.cpp
@@ -0,0 +1,27 @@
+#include "kapi/platform.hpp"
+
+#include "kapi/devices.hpp"
+
+#include "kernel/devices/cpu.hpp"
+
+#include <kstd/memory>
+
+#include <cstddef>
+#include <cstdint>
+#include <utility>
+
+namespace kapi::platform
+{
+
+ auto cpu_detected(kapi::devices::bus & bus, std::size_t major, std::size_t minor, std::uint64_t hardware_id,
+ bool is_bsp, kstd::unique_ptr<devices::device> core_interrupt_controller) -> bool
+ {
+ auto core = kstd::make_unique<kernel::devices::cpu::core>(major, minor, hardware_id, is_bsp);
+
+ core->add_child(std::move(core_interrupt_controller));
+ bus.add_child(std::move(core));
+
+ return true;
+ }
+
+} // namespace kapi::platform \ No newline at end of file
diff --git a/kernel/src/acpi/manager.cpp b/kernel/src/acpi/manager.cpp
new file mode 100644
index 0000000..300b85e
--- /dev/null
+++ b/kernel/src/acpi/manager.cpp
@@ -0,0 +1,103 @@
+#include "kernel/acpi/manager.hpp"
+
+#include "kapi/acpi.hpp"
+#include "kapi/memory.hpp"
+#include "kapi/system.hpp"
+
+#include <kstd/memory>
+#include <kstd/print>
+
+#include <cstddef>
+#include <cstdint>
+#include <string_view>
+
+namespace kernel::acpi
+{
+
+ manager::manager(kapi::acpi::root_system_description_pointer const & sdp)
+ : m_sdp{&sdp}
+ {
+ if (m_sdp->signature() != "RSD PTR ")
+ {
+ kapi::system::panic("[OS:ACPI] Invalid RSDP signature!");
+ }
+
+ if (m_sdp->revision() >= 2)
+ {
+ auto const xsdp = static_cast<kapi::acpi::extended_system_description_pointer const *>(m_sdp);
+ if (!xsdp->validate())
+ {
+ kapi::system::panic("[OS:ACPI] Invalid XSDP signature!");
+ }
+ auto physical_extended_table_address = xsdp->table_address();
+ auto linear_extended_table_address = kapi::memory::hhdm_to_linear(physical_extended_table_address);
+ m_rsdt = static_cast<kapi::acpi::system_description_table_header const *>(linear_extended_table_address);
+ m_extended = true;
+ }
+ else
+ {
+ if (!m_sdp->validate())
+ {
+ kapi::system::panic("[OS:ACPI] Invalid RSDP checksum!");
+ }
+ auto physical_root_table_address = m_sdp->table_address();
+ auto linear_root_table_address = kapi::memory::hhdm_to_linear(physical_root_table_address);
+ m_rsdt = static_cast<kapi::acpi::system_description_table_header const *>(linear_root_table_address);
+ }
+ }
+
+ auto manager::load_tables() -> bool
+ {
+ if (!kapi::acpi::validate_checksum({reinterpret_cast<std::byte const *>(m_rsdt), m_rsdt->length().value}))
+ {
+ kapi::system::panic("[OS:ACPI] Invalid RSDT checksum!");
+ }
+
+ auto entry_size = m_extended ? sizeof(std::uint64_t) : sizeof(std::uint32_t);
+ auto entry_count = (m_rsdt->length().value - sizeof(kapi::acpi::system_description_table_header)) / entry_size;
+ auto entries_base =
+ reinterpret_cast<std::byte const *>(m_rsdt) + sizeof(kapi::acpi::system_description_table_header);
+
+ for (std::size_t i = 0; i < entry_count; ++i)
+ {
+ auto physical_table_address = kapi::memory::physical_address{};
+
+ if (m_extended)
+ {
+ auto entry = reinterpret_cast<std::uint64_t const *>(entries_base + (i * entry_size));
+ physical_table_address = kapi::memory::physical_address{*entry};
+ }
+ else
+ {
+ auto entry = reinterpret_cast<std::uint32_t const *>(entries_base + (i * entry_size));
+ physical_table_address = kapi::memory::physical_address{*entry};
+ }
+
+ auto linear_table_address = kapi::memory::hhdm_to_linear(physical_table_address);
+ auto table = static_cast<kapi::acpi::system_description_table_header const *>(linear_table_address);
+
+ if (!kapi::acpi::validate_checksum({reinterpret_cast<std::byte const *>(table), table->length().value}))
+ {
+ kstd::println(kstd::print_sink::stderr, "[OS:ACPI] Invalid table checksum!");
+ }
+ else
+ {
+ kstd::println("[OS:ACPI] Found '{}' ACPI table", table->signature());
+ m_tables.emplace(table->signature(), table);
+ }
+ }
+
+ return !m_tables.empty();
+ }
+
+ auto manager::get_table(std::string_view signature)
+ -> kstd::observer_ptr<kapi::acpi::system_description_table_header const>
+ {
+ if (m_tables.contains(signature))
+ {
+ return kstd::make_observer(m_tables.at(signature));
+ }
+ return nullptr;
+ }
+
+} // namespace kernel::acpi
diff --git a/kernel/src/devices/cpu.cpp b/kernel/src/devices/cpu.cpp
new file mode 100644
index 0000000..eb10d74
--- /dev/null
+++ b/kernel/src/devices/cpu.cpp
@@ -0,0 +1,45 @@
+#include "kernel/devices/cpu.hpp"
+
+#include "kapi/devices.hpp"
+#include "kapi/platform.hpp"
+
+#include <kstd/print>
+
+#include <cstddef>
+#include <cstdint>
+
+namespace kernel::devices
+{
+
+ cpu::core::core(std::size_t major_number, std::size_t minor_number, std::uint64_t hardware_id, bool is_bsp)
+ : kapi::devices::bus{major_number, minor_number, "cpu_core"}
+ , m_hardware_id{hardware_id}
+ , m_is_bsp{is_bsp}
+ {}
+
+ auto cpu::core::hardware_id() const -> std::uint64_t
+ {
+ return m_hardware_id;
+ }
+
+ auto cpu::core::is_bsp() const -> bool
+ {
+ return m_is_bsp;
+ }
+
+ cpu::cpu(std::size_t major_number)
+ : kapi::devices::bus{major_number, 0, "cpu"}
+ {}
+
+ auto cpu::probe() -> bool
+ {
+ if (!kapi::platform::discover_cpu_topology(*this))
+ {
+ kstd::println("[OS:DEV] Failed to discover CPU topology");
+ return false;
+ }
+
+ return true;
+ }
+
+} // namespace kernel::devices \ No newline at end of file
diff --git a/kernel/src/main.cpp b/kernel/src/main.cpp
index 2eaa2d8..e704955 100644
--- a/kernel/src/main.cpp
+++ b/kernel/src/main.cpp
@@ -1,3 +1,4 @@
+#include "kapi/acpi.hpp"
#include "kapi/boot_modules.hpp"
#include "kapi/cio.hpp"
#include "kapi/cpu.hpp"
@@ -179,6 +180,15 @@ auto main() -> int
kstd::println("[OS] Memory subsystem initialized.");
kapi::system::memory_initialized();
+ auto acpi_root_pointer = kapi::acpi::get_root_pointer();
+ if (acpi_root_pointer && acpi_root_pointer->validate())
+ {
+ if (kapi::acpi::init(*acpi_root_pointer))
+ {
+ kstd::println("[OS] ACPI subsystem initialized.");
+ }
+ }
+
kapi::devices::init();
kstd::println("[OS] System root bus initialized.");