aboutsummaryrefslogtreecommitdiff
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
parent2a3575a267dede6a364386c0bd6edcff92421f0d (diff)
parentd5c2e101d62f6b4b69c45c127e7a729d246da566 (diff)
downloadkernel-fe26083101537df306153e7bea7c291a041897f7.tar.xz
kernel-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.
-rw-r--r--.vscode/settings.json10
-rw-r--r--.vscode/tasks.json4
-rw-r--r--arch/x86_64/CMakeLists.txt4
-rw-r--r--arch/x86_64/include/arch/devices/init.hpp12
-rw-r--r--arch/x86_64/include/arch/devices/local_apic.hpp26
-rw-r--r--arch/x86_64/kapi/acpi.cpp30
-rw-r--r--arch/x86_64/kapi/devices.cpp27
-rw-r--r--arch/x86_64/kapi/platform.cpp71
-rw-r--r--arch/x86_64/src/devices/init.cpp39
-rw-r--r--arch/x86_64/src/devices/local_apic.cpp28
-rw-r--r--kapi/include/kapi/acpi.hpp134
-rw-r--r--kapi/include/kapi/devices/bus.hpp56
-rw-r--r--kapi/include/kapi/devices/device.hpp30
-rw-r--r--kapi/include/kapi/memory/layout.hpp12
-rw-r--r--kapi/include/kapi/platform.hpp34
-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
-rw-r--r--libs/kstd/include/kstd/flat_map18
-rw-r--r--libs/kstd/include/kstd/units7
-rw-r--r--libs/multiboot2/include/multiboot2/constants/information_id.hpp8
-rw-r--r--libs/multiboot2/include/multiboot2/information.hpp43
-rw-r--r--libs/multiboot2/include/multiboot2/information/data.hpp12
32 files changed, 1043 insertions, 107 deletions
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 4271526..bebda51 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -26,12 +26,14 @@
},
"cSpell.words": [
"acpi",
+ "APIC",
"bugprone",
"cppcoreguidelines",
"crtc",
"crtp",
"efer",
"functors",
+ "hhdm",
"idtr",
"initializable",
"interprocedural",
@@ -40,9 +42,12 @@
"iwyu",
"kapi",
"kstd",
+ "lapic",
+ "madt",
"malloc",
"memcmp",
"memset",
+ "mmio",
"multiboot",
"nodiscard",
"nolintnextline",
@@ -51,12 +56,15 @@
"raii",
"rdmsr",
"RSDP",
+ "rsdt",
"rvalues",
"stringview",
"sysret",
"teachos",
"undelegated",
- "wrmsr"
+ "wrmsr",
+ "xsdp",
+ "xsdt"
],
"testMate.cpp.debug.configTemplate": {
"type": "cppdbg",
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
index e07afd2..d673a7a 100644
--- a/.vscode/tasks.json
+++ b/.vscode/tasks.json
@@ -11,6 +11,8 @@
"32M",
"-machine",
"q35",
+ "-smp",
+ "4,sockets=1,cores=4,threads=1",
"-display",
"curses",
"-debugcon",
@@ -52,6 +54,8 @@
"32M",
"-machine",
"q35",
+ "-smp",
+ "4,sockets=1,cores=4,threads=1",
"-display",
"curses",
"-debugcon",
diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt
index 83cae0b..87cb98c 100644
--- a/arch/x86_64/CMakeLists.txt
+++ b/arch/x86_64/CMakeLists.txt
@@ -12,12 +12,14 @@ target_link_libraries("x86_64" PUBLIC
target_sources("x86_64" PRIVATE
# Platform-dependent KAPI implementation
+ "kapi/acpi.cpp"
"kapi/boot_modules.cpp"
"kapi/cio.cpp"
"kapi/cpu.cpp"
"kapi/devices.cpp"
"kapi/interrupts.cpp"
"kapi/memory.cpp"
+ "kapi/platform.cpp"
"kapi/system.cpp"
# CPU Initialization
@@ -38,7 +40,9 @@ target_sources("x86_64" PRIVATE
"src/debug/qemu_output.cpp"
# Devices
+ "src/devices/init.cpp"
"src/devices/legacy_pit.cpp"
+ "src/devices/local_apic.cpp"
# Memory management
"src/memory/kernel_mapper.cpp"
diff --git a/arch/x86_64/include/arch/devices/init.hpp b/arch/x86_64/include/arch/devices/init.hpp
new file mode 100644
index 0000000..c5fbf37
--- /dev/null
+++ b/arch/x86_64/include/arch/devices/init.hpp
@@ -0,0 +1,12 @@
+#ifndef TEACHOS_ARCH_X86_64_DEVICES_INIT_HPP
+#define TEACHOS_ARCH_X86_64_DEVICES_INIT_HPP
+
+namespace arch::devices
+{
+
+ auto init_acpi_devices() -> void;
+ auto init_legacy_devices() -> void;
+
+} // namespace arch::devices
+
+#endif \ No newline at end of file
diff --git a/arch/x86_64/include/arch/devices/local_apic.hpp b/arch/x86_64/include/arch/devices/local_apic.hpp
new file mode 100644
index 0000000..71e9758
--- /dev/null
+++ b/arch/x86_64/include/arch/devices/local_apic.hpp
@@ -0,0 +1,26 @@
+#ifndef TEACHOS_ARCH_X86_64_DEVICES_LOCAL_APIC_HPP
+#define TEACHOS_ARCH_X86_64_DEVICES_LOCAL_APIC_HPP
+
+#include "kapi/devices/device.hpp"
+#include "kapi/memory.hpp"
+
+#include <cstddef>
+#include <cstdint>
+
+namespace arch::devices
+{
+
+ struct local_apic : kapi::devices::device
+ {
+ local_apic(std::size_t major, std::size_t minor, std::uint64_t hardware_id, kapi::memory::physical_address base);
+
+ auto init() -> bool override;
+
+ private:
+ std::uint64_t m_hardware_id{};
+ kapi::memory::physical_address m_base{};
+ };
+
+} // namespace arch::devices
+
+#endif \ No newline at end of file
diff --git a/arch/x86_64/kapi/acpi.cpp b/arch/x86_64/kapi/acpi.cpp
new file mode 100644
index 0000000..ec38aee
--- /dev/null
+++ b/arch/x86_64/kapi/acpi.cpp
@@ -0,0 +1,30 @@
+#include "kapi/acpi.hpp"
+
+#include "arch/boot/boot.hpp"
+
+#include <kstd/memory>
+
+namespace kapi::acpi
+{
+
+ auto get_root_pointer() -> kstd::observer_ptr<root_system_description_pointer const>
+ {
+ auto const & mbi = kapi::boot::bootstrap_information.mbi;
+ auto system_description_pointer = static_cast<kapi::acpi::root_system_description_pointer const *>(nullptr);
+
+ if (auto const & xsdp = mbi->maybe_acpi_xsdp())
+ {
+ auto data = xsdp->pointer().data();
+
+ system_description_pointer = reinterpret_cast<kapi::acpi::root_system_description_pointer const *>(data);
+ }
+ else if (auto const & rsdp = mbi->maybe_acpi_rsdp())
+ {
+ auto data = rsdp->pointer().data();
+ system_description_pointer = reinterpret_cast<kapi::acpi::root_system_description_pointer const *>(data);
+ }
+
+ return kstd::make_observer(system_description_pointer);
+ }
+
+} // namespace kapi::acpi \ No newline at end of file
diff --git a/arch/x86_64/kapi/devices.cpp b/arch/x86_64/kapi/devices.cpp
index b15503d..47c7f8c 100644
--- a/arch/x86_64/kapi/devices.cpp
+++ b/arch/x86_64/kapi/devices.cpp
@@ -1,35 +1,14 @@
#include "kapi/devices.hpp"
-#include "arch/bus/isa.hpp"
-#include "arch/devices/legacy_pit.hpp"
-
-#include <kstd/memory>
-#include <kstd/print>
-
-#include <cstdint>
-#include <utility>
+#include "arch/devices/init.hpp"
namespace kapi::devices
{
- namespace
- {
- constexpr auto pit_frequency_in_hz = std::uint32_t{100u};
- }
-
auto init_platform_devices() -> void
{
- kstd::println("[x86_64:devices] Initializing ISA bus...");
-
- auto isa_major_number = kapi::devices::allocate_major_number();
- auto isa_bus = kstd::make_unique<arch::bus::isa>(isa_major_number);
-
- auto pit_major_number = kapi::devices::allocate_major_number();
- auto pit = kstd::make_unique<arch::devices::legacy_pit>(pit_major_number, pit_frequency_in_hz);
- isa_bus->add_child(std::move(pit));
-
- auto & root_bus = get_root_bus();
- root_bus.add_child(std::move(isa_bus));
+ arch::devices::init_acpi_devices();
+ arch::devices::init_legacy_devices();
}
} // namespace kapi::devices \ No newline at end of file
diff --git a/arch/x86_64/kapi/platform.cpp b/arch/x86_64/kapi/platform.cpp
new file mode 100644
index 0000000..380fc66
--- /dev/null
+++ b/arch/x86_64/kapi/platform.cpp
@@ -0,0 +1,71 @@
+#include "kapi/platform.hpp"
+
+#include "kapi/acpi.hpp"
+#include "kapi/devices.hpp"
+#include "kapi/memory.hpp"
+
+#include "arch/devices/local_apic.hpp"
+
+#include <kstd/memory>
+#include <kstd/print>
+
+#include <cstddef>
+#include <utility>
+
+namespace kapi::platform
+{
+
+ namespace
+ {
+ constexpr auto default_lapic_address = kapi::memory::physical_address{0xFEE0'0000};
+ }
+
+ auto discover_cpu_topology(kapi::devices::bus & bus) -> bool
+ {
+ auto static const core_major = kapi::devices::allocate_major_number();
+ auto static const interrupt_controller_major = kapi::devices::allocate_major_number();
+ auto static core_index = 0uz;
+
+ auto madt = kapi::acpi::get_table("APIC");
+ if (!madt)
+ {
+ kstd::println("[x86_64:PLT] Failed to find ACPI APIC table");
+ return false;
+ }
+
+ auto const * current = reinterpret_cast<std::byte const *>(madt.get()) + sizeof(kapi::acpi::madt_header);
+ auto const * end = reinterpret_cast<std::byte const *>(madt.get()) + madt->length();
+
+ auto bsp_found = false;
+ auto core_count = 0uz;
+
+ while (current < end)
+ {
+ auto const * sub_table = reinterpret_cast<kapi::acpi::madt_subtable_header const *>(current);
+ if (sub_table->type() == 0)
+ {
+ auto const * local_apic = reinterpret_cast<kapi::acpi::madt_local_apic const *>(sub_table);
+ if (local_apic->flags() & 0b11)
+ {
+ auto is_bsp = !bsp_found;
+ bsp_found = true;
+
+ auto lapic = kstd::make_unique<arch::devices::local_apic>(interrupt_controller_major, core_index,
+ local_apic->apic_id(), default_lapic_address);
+ if (kapi::platform::cpu_detected(bus, core_major, core_index, local_apic->processor_id(), is_bsp,
+ std::move(lapic)))
+ {
+ ++core_count;
+ }
+ }
+ }
+
+ current += sub_table->length();
+ }
+
+ kstd::println("[x86_64:PLT] Found {} CPU cores", core_count);
+
+ return core_count > 0;
+ }
+
+} // namespace kapi::platform \ No newline at end of file
diff --git a/arch/x86_64/src/devices/init.cpp b/arch/x86_64/src/devices/init.cpp
new file mode 100644
index 0000000..6cba986
--- /dev/null
+++ b/arch/x86_64/src/devices/init.cpp
@@ -0,0 +1,39 @@
+#include "arch/devices/init.hpp"
+
+#include "kapi/devices.hpp"
+
+#include "arch/bus/isa.hpp"
+#include "arch/devices/legacy_pit.hpp"
+
+#include <kstd/memory>
+#include <kstd/print>
+
+#include <cstdint>
+#include <utility>
+
+namespace arch::devices
+{
+
+ namespace
+ {
+ constexpr auto pit_frequency_in_hz = std::uint32_t{100u};
+ }
+
+ auto init_acpi_devices() -> void {}
+
+ auto init_legacy_devices() -> void
+ {
+ kstd::println("[x86_64:DEV] Initializing ISA bus...");
+
+ auto isa_major_number = kapi::devices::allocate_major_number();
+ auto isa_bus = kstd::make_unique<arch::bus::isa>(isa_major_number);
+
+ auto pit_major_number = kapi::devices::allocate_major_number();
+ auto pit = kstd::make_unique<arch::devices::legacy_pit>(pit_major_number, pit_frequency_in_hz);
+ isa_bus->add_child(std::move(pit));
+
+ auto & root_bus = kapi::devices::get_root_bus();
+ root_bus.add_child(std::move(isa_bus));
+ }
+
+} // namespace arch::devices
diff --git a/arch/x86_64/src/devices/local_apic.cpp b/arch/x86_64/src/devices/local_apic.cpp
new file mode 100644
index 0000000..beb75ef
--- /dev/null
+++ b/arch/x86_64/src/devices/local_apic.cpp
@@ -0,0 +1,28 @@
+#include "arch/devices/local_apic.hpp"
+
+#include "kapi/devices.hpp"
+#include "kapi/memory.hpp"
+
+#include <kstd/print>
+
+#include <cstddef>
+#include <cstdint>
+
+namespace arch::devices
+{
+
+ local_apic::local_apic(std::size_t major, std::size_t minor, std::uint64_t hardware_id,
+ kapi::memory::physical_address base)
+ : kapi::devices::device{major, minor, "lapic"}
+ , m_hardware_id{hardware_id}
+ , m_base{base}
+ {}
+
+ auto local_apic::init() -> bool
+ {
+ kstd::println("[x86_64:DEV] Initializing local APIC on core {}", m_hardware_id);
+
+ return true;
+ }
+
+} // namespace arch::devices \ No newline at end of file
diff --git a/kapi/include/kapi/acpi.hpp b/kapi/include/kapi/acpi.hpp
new file mode 100644
index 0000000..75b6c48
--- /dev/null
+++ b/kapi/include/kapi/acpi.hpp
@@ -0,0 +1,134 @@
+#ifndef TEACHOS_KAPI_ACPI_HPP
+#define TEACHOS_KAPI_ACPI_HPP
+
+#include "kapi/memory.hpp"
+
+#include <kstd/memory>
+#include <kstd/units>
+
+#include <array>
+#include <cstddef>
+#include <cstdint>
+#include <span>
+#include <string_view>
+
+namespace kapi::acpi
+{
+
+ //! @addtogroup kapi-acpi-kernel-defined
+ //! @{
+
+ struct [[gnu::packed]] root_system_description_pointer
+ {
+ [[nodiscard]] auto oem_id() const noexcept -> std::string_view;
+ [[nodiscard]] auto revision() const noexcept -> std::uint8_t;
+ [[nodiscard]] auto signature() const noexcept -> std::string_view;
+ [[nodiscard]] auto table_address() const noexcept -> memory::physical_address;
+ [[nodiscard]] auto validate() const noexcept -> bool;
+
+ private:
+ std::array<char, 8> m_signature;
+ [[maybe_unused]] std::uint8_t m_checksum;
+ std::array<char, 6> m_oem_id;
+ std::uint8_t m_revision;
+ std::array<std::byte, 4> m_rsdt_address;
+ };
+
+ struct [[gnu::packed]] extended_system_description_pointer : root_system_description_pointer
+ {
+ [[nodiscard]] auto length() const noexcept -> kstd::units::bytes;
+ [[nodiscard]] auto table_address() const noexcept -> memory::physical_address;
+ [[nodiscard]] auto validate() const noexcept -> bool;
+
+ private:
+ std::uint32_t m_length;
+ std::array<std::byte, 8> m_xsdt_address;
+ [[maybe_unused]] std::uint8_t m_extended_checksum;
+ [[maybe_unused]] std::array<std::byte, 3> m_reserved;
+ };
+
+ struct [[gnu::packed]] system_description_table_header
+ {
+ [[nodiscard]] auto checksum() const noexcept -> std::uint8_t;
+ [[nodiscard]] auto creator_revision() const noexcept -> std::uint32_t;
+ [[nodiscard]] auto creator_id() const noexcept -> std::uint32_t;
+ [[nodiscard]] auto length() const noexcept -> kstd::units::bytes;
+ [[nodiscard]] auto oem_id() const noexcept -> std::string_view;
+ [[nodiscard]] auto oem_revision() const noexcept -> std::uint32_t;
+ [[nodiscard]] auto oem_table_id() const noexcept -> std::string_view;
+ [[nodiscard]] auto revision() const noexcept -> std::uint8_t;
+ [[nodiscard]] auto signature() const noexcept -> std::string_view;
+
+ private:
+ std::array<char, 4> m_signature;
+ std::uint32_t m_length;
+ std::uint8_t m_revision;
+ std::uint8_t m_checksum;
+ std::array<char, 6> m_oem_id;
+ std::array<char, 8> m_oem_table_id;
+ std::uint32_t m_oem_revision;
+ std::uint32_t m_creator_id;
+ std::uint32_t m_creator_revision;
+ };
+
+ struct [[gnu::packed]] madt_header : system_description_table_header
+ {
+ [[nodiscard]] auto local_interrupt_controller_address() const noexcept -> memory::physical_address;
+ [[nodiscard]] auto flags() const noexcept -> std::uint32_t;
+
+ private:
+ std::uint32_t m_local_interrupt_controller_address;
+ std::uint32_t m_flags;
+ };
+
+ struct [[gnu::packed]] madt_subtable_header
+ {
+ [[nodiscard]] auto type() const noexcept -> std::uint8_t;
+ [[nodiscard]] auto length() const noexcept -> std::size_t;
+
+ private:
+ std::uint8_t m_type;
+ std::uint8_t m_length;
+ };
+
+ struct [[gnu::packed]] madt_local_apic : madt_subtable_header
+ {
+ [[nodiscard]] auto apic_id() const noexcept -> std::uint8_t;
+ [[nodiscard]] auto flags() const noexcept -> std::uint32_t;
+ [[nodiscard]] auto processor_id() const noexcept -> std::uint32_t;
+
+ private:
+ std::uint8_t m_processor_id;
+ std::uint8_t m_apic_id;
+ std::uint32_t m_flags;
+ };
+
+ //! Initialize the ACPI subsystem and discover the available tables.
+ //!
+ //! @return true iff. a valid system description tabled was found, false otherwise.
+ auto init(root_system_description_pointer const & sdp) -> bool;
+
+ //! Validate and ACPI entity checksum.
+ //!
+ //! @param data The data to validate the checksum of.
+ //! @return true iff. the checksum is valid, false otherwise.
+ auto validate_checksum(std::span<std::byte const> data) -> bool;
+
+ //! Get an ACPI table by its signature.
+ //!
+ //! @param signature The signature of the table to get.
+ //! @return A pointer to the table if found, nullptr otherwise.
+ auto get_table(std::string_view signature) -> kstd::observer_ptr<system_description_table_header const>;
+
+ //! @}
+
+ //! @addtogroup kapi-acpi-platform-defined
+ //! @{
+
+ auto get_root_pointer() -> kstd::observer_ptr<root_system_description_pointer const>;
+
+ //! @}
+
+} // namespace kapi::acpi
+
+#endif
diff --git a/kapi/include/kapi/devices/bus.hpp b/kapi/include/kapi/devices/bus.hpp
index 052c062..7b2d41f 100644
--- a/kapi/include/kapi/devices/bus.hpp
+++ b/kapi/include/kapi/devices/bus.hpp
@@ -1,24 +1,22 @@
#ifndef TEACHOS_KAPI_DEVICES_BUS_HPP
#define TEACHOS_KAPI_DEVICES_BUS_HPP
+// IWYU pragma: private, include "kapi/devices.hpp"
+
#include "kapi/devices/device.hpp"
-#include "kapi/devices/manager.hpp"
-#include "kapi/system.hpp"
#include <kstd/memory>
#include <kstd/print>
#include <kstd/string>
#include <kstd/vector>
-#include <algorithm>
#include <atomic>
#include <cstddef>
-#include <utility>
namespace kapi::devices
{
- //! @addtogroup kapi-devices
+ //! @addtogroup kapi-devices-kernel-defined
//! @{
//! A bus device that represents a logical/physical tree of devices and busses.
@@ -29,65 +27,27 @@ namespace kapi::devices
//! @param major The major number of the bus.
//! @param minor The minor number of the bus.
//! @param name The name of the bus.
- bus(std::size_t major, std::size_t minor, kstd::string const & name)
- : device(major, minor, name)
- {}
+ bus(std::size_t major, std::size_t minor, kstd::string const & name);
//! Initialize the bus and all of its children.
//!
//! @return true iff. the bus and all of its children are healthy, false otherwise.
- auto init() -> bool final
- {
- 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("[kAPI:BUS] Initializing child device {}@{}", child->name(), name());
- return child->init() && acc;
- });
- }
+ auto init() -> bool final;
//! Attach a child device to this bus.
//!
//! Whenever a device is attached to a bus, the bus takes sole ownership of the device.
//!
//! @param child The child device to attach.
- auto 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("[kAPI:BUS] Initializing child device {}@{}", observer->name(), name());
- if (!observer->init())
- {
- kapi::system::panic("[kAPI:BUS] Failed to initialize child device");
- }
- }
- }
+ auto add_child(kstd::unique_ptr<device> child) -> void;
- [[nodiscard]] auto children() const -> kstd::vector<kstd::observer_ptr<device>> const &
- {
- return m_observers;
- }
+ [[nodiscard]] auto children() const -> kstd::vector<kstd::observer_ptr<device>> const &;
protected:
//! Probe the bus hardware state.
//!
//! @return true iff. the bus hardware is healthy, false otherwise.
- auto virtual probe() -> bool
- {
- return true;
- }
+ auto virtual probe() -> bool;
private:
kstd::vector<kstd::unique_ptr<device>> m_devices;
diff --git a/kapi/include/kapi/devices/device.hpp b/kapi/include/kapi/devices/device.hpp
index b7b6bba..b3647da 100644
--- a/kapi/include/kapi/devices/device.hpp
+++ b/kapi/include/kapi/devices/device.hpp
@@ -1,6 +1,8 @@
#ifndef TEACH_OS_KAPI_DEVICES_DEVICE_HPP
#define TEACH_OS_KAPI_DEVICES_DEVICE_HPP
+// IWYU pragma: private, include "kapi/devices.hpp"
+
#include <kstd/string>
#include <cstddef>
@@ -8,7 +10,7 @@
namespace kapi::devices
{
- //! @addtogroup kapi-devices
+ //! @addtogroup kapi-devices-kernel-defined
//! @{
/**
@@ -22,11 +24,7 @@ namespace kapi::devices
* @param minor Device minor number.
* @param name Device name.
*/
- device(size_t major, size_t minor, kstd::string const & name)
- : m_major(major)
- , m_minor(minor)
- , m_name(name)
- {}
+ device(size_t major, size_t minor, kstd::string const & name);
/**
* @brief Virtual destructor for device.
@@ -43,37 +41,25 @@ namespace kapi::devices
* @brief Returns the major number of the device.
* @return Device major number.
*/
- [[nodiscard]] auto major() const -> size_t
- {
- return m_major;
- }
+ [[nodiscard]] auto major() const -> size_t;
/**
* @brief Returns the minor number of the device.
* @return Device minor number.
*/
- [[nodiscard]] auto minor() const -> size_t
- {
- return m_minor;
- }
+ [[nodiscard]] auto minor() const -> size_t;
/**
* @brief Returns the name of the device.
* @return Device name.
*/
- [[nodiscard]] auto name() const -> kstd::string const &
- {
- return m_name;
- }
+ [[nodiscard]] auto name() const -> kstd::string const &;
/**
* @brief Check if the device is a block device.
* @return true if this device is a block device, false otherwise.
*/
- [[nodiscard]] virtual auto is_block_device() const -> bool
- {
- return false;
- }
+ [[nodiscard]] virtual auto is_block_device() const -> bool;
private:
size_t m_major;
diff --git a/kapi/include/kapi/memory/layout.hpp b/kapi/include/kapi/memory/layout.hpp
index 157f41e..26b48d8 100644
--- a/kapi/include/kapi/memory/layout.hpp
+++ b/kapi/include/kapi/memory/layout.hpp
@@ -37,6 +37,18 @@ namespace kapi::memory
//! The linear base address of the loaded kernel image.
constexpr auto kernel_base = linear_address{0xffff'ffff'8000'0000uz};
+ //! Convert a physical address to a linear address using the higher-half direct map.
+ constexpr auto hhdm_to_linear(physical_address address) -> linear_address
+ {
+ return linear_address{address.raw() + higher_half_direct_map_base.raw()};
+ }
+
+ //! Convert a linear address in the higher-half direct map to a physical address.
+ constexpr auto hhdm_to_physical(linear_address address) -> physical_address
+ {
+ return physical_address{address.raw() - higher_half_direct_map_base.raw()};
+ }
+
} // namespace kapi::memory
#endif \ No newline at end of file
diff --git a/kapi/include/kapi/platform.hpp b/kapi/include/kapi/platform.hpp
new file mode 100644
index 0000000..e1e267e
--- /dev/null
+++ b/kapi/include/kapi/platform.hpp
@@ -0,0 +1,34 @@
+#ifndef TEACHOS_KAPI_PLATFORM_HPP
+#define TEACHOS_KAPI_PLATFORM_HPP
+
+#include "kapi/devices.hpp"
+
+#include <kstd/memory>
+
+#include <cstddef>
+#include <cstdint>
+
+namespace kapi::platform
+{
+
+ //! @addtogroup kapi-platform-kernel-defined
+ //! @{
+
+ 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;
+ //! @}
+
+ //! @addtogroup kapi-platform-platform-defined
+ //! @{
+
+ //! Discover the CPU topology of the platform and attach it to the given CPU bus.
+ //!
+ //! @param bus The bus to attach the CPU topology to.
+ //! @return true iff. the CPU topology was discovered successfully, false otherwise.
+ auto discover_cpu_topology(kapi::devices::bus & bus) -> bool;
+
+ //! @}
+
+} // namespace kapi::platform
+
+#endif \ No newline at end of file
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.");
diff --git a/libs/kstd/include/kstd/flat_map b/libs/kstd/include/kstd/flat_map
index 6ffbbcf..3b13754 100644
--- a/libs/kstd/include/kstd/flat_map
+++ b/libs/kstd/include/kstd/flat_map
@@ -205,6 +205,24 @@ namespace kstd
return const_reverse_iterator{cbegin()};
}
+ //! Check whether this flat map is empty or not
+ [[nodiscard]] auto empty() const noexcept -> bool
+ {
+ return m_containers.keys.empty();
+ }
+
+ //! Get the number of elements in this flat map.
+ [[nodiscard]] auto size() const noexcept -> size_type
+ {
+ return m_containers.keys.size();
+ }
+
+ //! Get the maximum number of elements possible in this flat map
+ [[nodiscard]] auto max_size() const noexcept -> size_type
+ {
+ return std::min(m_containers.keys.max_size(), m_containers.values.max_size());
+ }
+
//! Try to insert a new key-value pair into the map.
//!
//! @param args Arguments to use for constructing the key-value pair.
diff --git a/libs/kstd/include/kstd/units b/libs/kstd/include/kstd/units
index f6dcdb1..bc7e1b9 100644
--- a/libs/kstd/include/kstd/units
+++ b/libs/kstd/include/kstd/units
@@ -14,6 +14,11 @@ namespace kstd
{
using value_type = ValueType;
+ constexpr basic_unit() noexcept
+ : value{}
+ {
+ }
+
explicit constexpr basic_unit(value_type value) noexcept
: value{value}
{}
@@ -142,4 +147,4 @@ namespace kstd
} // namespace kstd
-#endif \ No newline at end of file
+#endif
diff --git a/libs/multiboot2/include/multiboot2/constants/information_id.hpp b/libs/multiboot2/include/multiboot2/constants/information_id.hpp
index be492eb..27c5300 100644
--- a/libs/multiboot2/include/multiboot2/constants/information_id.hpp
+++ b/libs/multiboot2/include/multiboot2/constants/information_id.hpp
@@ -57,10 +57,10 @@ namespace multiboot2
smbios_tables,
//! A copy of RSDP as defined per ACPI 1.0 specification.
- acpi_old_rsdp,
+ acpi_rsdp,
- //! A copy of RSDP as defined per ACPI 2.0 or later specification.
- acpi_new_rsdp,
+ //! A copy of XSDP as defined per ACPI 2.0 or later specification.
+ acpi_xsdp,
//! The network information specified specified as per DHCP.
networking_information,
@@ -83,4 +83,4 @@ namespace multiboot2
} // namespace multiboot2
-#endif \ No newline at end of file
+#endif
diff --git a/libs/multiboot2/include/multiboot2/information.hpp b/libs/multiboot2/include/multiboot2/information.hpp
index d2fac2e..a2ded56 100644
--- a/libs/multiboot2/include/multiboot2/information.hpp
+++ b/libs/multiboot2/include/multiboot2/information.hpp
@@ -11,6 +11,7 @@
#include <elf/section_header.hpp>
#include <algorithm>
+#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <optional>
@@ -128,6 +129,26 @@ namespace multiboot2
return kstd::units::bytes{end_address - start_address};
}
};
+
+ struct acpi_rsdp : vla_tag<data::acpi_rsdp, std::byte, std::span>
+ {
+ using vla_tag::vla_tag;
+
+ [[nodiscard]] auto pointer() const noexcept -> range_type
+ {
+ return {data(), size()};
+ }
+ };
+
+ struct acpi_xsdp : vla_tag<data::acpi_xsdp, std::byte, std::span>
+ {
+ using vla_tag::vla_tag;
+
+ [[nodiscard]] auto pointer() const noexcept -> range_type
+ {
+ return {data(), size()};
+ }
+ };
struct information_view
{
@@ -245,6 +266,26 @@ namespace multiboot2
std::views::transform(transform_module);
}
+ [[nodiscard]] auto maybe_acpi_rsdp() const noexcept -> std::optional<acpi_rsdp>
+ {
+ return get<multiboot2::acpi_rsdp>();
+ }
+
+ [[nodiscard]] auto acpi_rsdp() const noexcept -> acpi_rsdp
+ {
+ return maybe_acpi_rsdp().value();
+ }
+
+ [[nodiscard]] auto maybe_acpi_xsdp() const noexcept -> std::optional<acpi_xsdp>
+ {
+ return get<multiboot2::acpi_xsdp>();
+ }
+
+ [[nodiscard]] auto acpi_xsdp() const noexcept -> acpi_xsdp
+ {
+ return maybe_acpi_xsdp().value();
+ }
+
private:
template<typename Tag>
[[nodiscard]] constexpr auto get() const noexcept -> std::optional<Tag>
@@ -264,4 +305,4 @@ namespace multiboot2
} // namespace multiboot2
-#endif \ No newline at end of file
+#endif
diff --git a/libs/multiboot2/include/multiboot2/information/data.hpp b/libs/multiboot2/include/multiboot2/information/data.hpp
index 3b07d20..315eb39 100644
--- a/libs/multiboot2/include/multiboot2/information/data.hpp
+++ b/libs/multiboot2/include/multiboot2/information/data.hpp
@@ -167,8 +167,18 @@ namespace multiboot2
std::uint32_t end_address;
};
+ //! A copy of the ACPI RSDP
+ struct acpi_rsdp : tag_data<information_id::acpi_rsdp>
+ {
+ };
+
+ //! A copy of the ACPI XSDP
+ struct acpi_xsdp : tag_data<information_id::acpi_xsdp>
+ {
+ };
+
} // namespace data
} // namespace multiboot2
-#endif \ No newline at end of file
+#endif