diff options
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 |
