From 4b71a936183070e43a6ca73c2975eae70742e124 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 29 Apr 2026 09:25:53 +0200 Subject: chore: migrate 'kapi' to p1204 layout --- kapi/CMakeLists.txt | 2 +- kapi/include/kapi/acpi.hpp | 40 ---- kapi/include/kapi/boot.hpp | 17 -- kapi/include/kapi/boot_module/boot_module.hpp | 23 -- .../kapi/boot_module/boot_module_registry.hpp | 107 --------- kapi/include/kapi/boot_modules.hpp | 31 --- kapi/include/kapi/cio.hpp | 48 ---- kapi/include/kapi/cio/output_device.hpp | 39 ---- kapi/include/kapi/cpu.hpp | 135 ----------- kapi/include/kapi/devices.hpp | 37 --- kapi/include/kapi/devices/bus.hpp | 63 ------ kapi/include/kapi/devices/cpu.hpp | 37 --- kapi/include/kapi/devices/device.hpp | 80 ------- kapi/include/kapi/devices/manager.hpp | 53 ----- kapi/include/kapi/filesystem.hpp | 73 ------ kapi/include/kapi/interrupts.hpp | 74 ------ kapi/include/kapi/memory.hpp | 131 ----------- kapi/include/kapi/memory/address.hpp | 252 --------------------- kapi/include/kapi/memory/chunk.hpp | 109 --------- kapi/include/kapi/memory/frame.hpp | 48 ---- kapi/include/kapi/memory/frame_allocator.hpp | 66 ------ kapi/include/kapi/memory/layout.hpp | 54 ----- kapi/include/kapi/memory/page.hpp | 38 ---- kapi/include/kapi/memory/page_mapper.hpp | 90 -------- kapi/include/kapi/system.hpp | 32 --- kapi/kapi/acpi.hpp | 40 ++++ kapi/kapi/boot.hpp | 17 ++ kapi/kapi/boot_module/boot_module.hpp | 23 ++ kapi/kapi/boot_module/boot_module_registry.hpp | 107 +++++++++ kapi/kapi/boot_modules.hpp | 31 +++ kapi/kapi/cio.hpp | 48 ++++ kapi/kapi/cio/output_device.hpp | 39 ++++ kapi/kapi/cpu.hpp | 135 +++++++++++ kapi/kapi/devices.hpp | 37 +++ kapi/kapi/devices/bus.hpp | 63 ++++++ kapi/kapi/devices/cpu.hpp | 37 +++ kapi/kapi/devices/device.hpp | 80 +++++++ kapi/kapi/devices/manager.hpp | 53 +++++ kapi/kapi/filesystem.hpp | 73 ++++++ kapi/kapi/interrupts.hpp | 74 ++++++ kapi/kapi/memory.hpp | 131 +++++++++++ kapi/kapi/memory/address.hpp | 252 +++++++++++++++++++++ kapi/kapi/memory/chunk.hpp | 109 +++++++++ kapi/kapi/memory/frame.hpp | 48 ++++ kapi/kapi/memory/frame_allocator.hpp | 66 ++++++ kapi/kapi/memory/layout.hpp | 54 +++++ kapi/kapi/memory/page.hpp | 38 ++++ kapi/kapi/memory/page_mapper.hpp | 90 ++++++++ kapi/kapi/system.hpp | 32 +++ 49 files changed, 1678 insertions(+), 1678 deletions(-) delete mode 100644 kapi/include/kapi/acpi.hpp delete mode 100644 kapi/include/kapi/boot.hpp delete mode 100644 kapi/include/kapi/boot_module/boot_module.hpp delete mode 100644 kapi/include/kapi/boot_module/boot_module_registry.hpp delete mode 100644 kapi/include/kapi/boot_modules.hpp delete mode 100644 kapi/include/kapi/cio.hpp delete mode 100644 kapi/include/kapi/cio/output_device.hpp delete mode 100644 kapi/include/kapi/cpu.hpp delete mode 100644 kapi/include/kapi/devices.hpp delete mode 100644 kapi/include/kapi/devices/bus.hpp delete mode 100644 kapi/include/kapi/devices/cpu.hpp delete mode 100644 kapi/include/kapi/devices/device.hpp delete mode 100644 kapi/include/kapi/devices/manager.hpp delete mode 100644 kapi/include/kapi/filesystem.hpp delete mode 100644 kapi/include/kapi/interrupts.hpp delete mode 100644 kapi/include/kapi/memory.hpp delete mode 100644 kapi/include/kapi/memory/address.hpp delete mode 100644 kapi/include/kapi/memory/chunk.hpp delete mode 100644 kapi/include/kapi/memory/frame.hpp delete mode 100644 kapi/include/kapi/memory/frame_allocator.hpp delete mode 100644 kapi/include/kapi/memory/layout.hpp delete mode 100644 kapi/include/kapi/memory/page.hpp delete mode 100644 kapi/include/kapi/memory/page_mapper.hpp delete mode 100644 kapi/include/kapi/system.hpp create mode 100644 kapi/kapi/acpi.hpp create mode 100644 kapi/kapi/boot.hpp create mode 100644 kapi/kapi/boot_module/boot_module.hpp create mode 100644 kapi/kapi/boot_module/boot_module_registry.hpp create mode 100644 kapi/kapi/boot_modules.hpp create mode 100644 kapi/kapi/cio.hpp create mode 100644 kapi/kapi/cio/output_device.hpp create mode 100644 kapi/kapi/cpu.hpp create mode 100644 kapi/kapi/devices.hpp create mode 100644 kapi/kapi/devices/bus.hpp create mode 100644 kapi/kapi/devices/cpu.hpp create mode 100644 kapi/kapi/devices/device.hpp create mode 100644 kapi/kapi/devices/manager.hpp create mode 100644 kapi/kapi/filesystem.hpp create mode 100644 kapi/kapi/interrupts.hpp create mode 100644 kapi/kapi/memory.hpp create mode 100644 kapi/kapi/memory/address.hpp create mode 100644 kapi/kapi/memory/chunk.hpp create mode 100644 kapi/kapi/memory/frame.hpp create mode 100644 kapi/kapi/memory/frame_allocator.hpp create mode 100644 kapi/kapi/memory/layout.hpp create mode 100644 kapi/kapi/memory/page.hpp create mode 100644 kapi/kapi/memory/page_mapper.hpp create mode 100644 kapi/kapi/system.hpp diff --git a/kapi/CMakeLists.txt b/kapi/CMakeLists.txt index d15b923..f74cfb3 100644 --- a/kapi/CMakeLists.txt +++ b/kapi/CMakeLists.txt @@ -15,7 +15,7 @@ target_sources("kapi" PUBLIC ) target_include_directories("kapi" INTERFACE - "include" + "${CMAKE_CURRENT_SOURCE_DIR}" ) target_link_libraries("kapi" INTERFACE diff --git a/kapi/include/kapi/acpi.hpp b/kapi/include/kapi/acpi.hpp deleted file mode 100644 index 885fcde..0000000 --- a/kapi/include/kapi/acpi.hpp +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef TEACHOS_KAPI_ACPI_HPP -#define TEACHOS_KAPI_ACPI_HPP - -#include - -#include -#include - -#include - -namespace kapi::acpi -{ - - //! @addtogroup kapi-acpi-kernel-defined - //! @{ - - //! Initialize the ACPI subsystem and discover the available tables. - //! - //! @return true iff. a valid system description tabled was found, false otherwise. - auto init(::acpi::rsdp const & sdp) -> bool; - - //! Get a pointer to 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<::acpi::table_header const>; - - //! Get a type-cast pointer to an ACPI table by its signature. - //! - //! @tparam Signature The signature of the table to get - //! @return A pointer to the table if found, nullptr otherwise. - template - auto get_table() -> kstd::observer_ptr<::acpi::table_type_t const> - { - return kstd::make_observer(static_cast<::acpi::table_type_t const *>(get_table(Signature).get())); - } - -} // namespace kapi::acpi - -#endif diff --git a/kapi/include/kapi/boot.hpp b/kapi/include/kapi/boot.hpp deleted file mode 100644 index 55ca941..0000000 --- a/kapi/include/kapi/boot.hpp +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef TEACHOS_KAPI_BOOT_HPP -#define TEACHOS_KAPI_BOOT_HPP - -namespace kapi::boot -{ - //! @qualifier platform-defined - //! Information passed from the early pre-main stage to the kernel executable. - //! - //! The specific structure of this type is defined on a platform level. - struct information; - - //! @qualifier platform-defined - //! An object passed from the early pre-main stage to the kernel executable. - extern "C" information const bootstrap_information; -} // namespace kapi::boot - -#endif diff --git a/kapi/include/kapi/boot_module/boot_module.hpp b/kapi/include/kapi/boot_module/boot_module.hpp deleted file mode 100644 index 9b4b165..0000000 --- a/kapi/include/kapi/boot_module/boot_module.hpp +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef TEACHOS_KAPI_BOOT_MODULE_BOOT_MODULE_HPP -#define TEACHOS_KAPI_BOOT_MODULE_BOOT_MODULE_HPP - -#include - -#include -#include - -namespace kapi::boot_modules -{ - // ! The boot module struct - // ! - // ! The boot module struct represents a module loaded by the bootloader, and contains information about it, such as - // ! its name, virtual start address, and size. - struct boot_module - { - std::string_view name{}; - memory::linear_address start_address{}; - std::size_t size{}; - }; -} // namespace kapi::boot_modules - -#endif \ No newline at end of file diff --git a/kapi/include/kapi/boot_module/boot_module_registry.hpp b/kapi/include/kapi/boot_module/boot_module_registry.hpp deleted file mode 100644 index fc3590f..0000000 --- a/kapi/include/kapi/boot_module/boot_module_registry.hpp +++ /dev/null @@ -1,107 +0,0 @@ -#ifndef TEACHOS_KAPI_BOOT_MODULE_BOOT_MODULE_REGISTRY_HPP -#define TEACHOS_KAPI_BOOT_MODULE_BOOT_MODULE_REGISTRY_HPP - -#include - -#include - -#include - -namespace kapi::boot_modules -{ - - // ! The interface of the boot module registry - // ! - // ! The boot module registry is responsible for keeping track of the modules loaded by the bootloader, and - // ! providing access to them for the rest of the kernel. - struct boot_module_registry - { - using range_type = kstd::vector; - using value_type = range_type::value_type; - using const_reference = range_type::const_reference; - - using const_iterator = range_type::const_iterator; - using const_reverse_iterator = range_type::const_reverse_iterator; - using size_type = range_type::size_type; - - [[nodiscard]] auto begin() const noexcept -> const_iterator - { - return m_modules.begin(); - } - - [[nodiscard]] auto end() const noexcept -> const_iterator - { - return m_modules.end(); - } - - [[nodiscard]] auto cbegin() const noexcept -> const_iterator - { - return begin(); - } - - [[nodiscard]] auto cend() const noexcept -> const_iterator - { - return end(); - } - - [[nodiscard]] auto rbegin() const noexcept -> const_reverse_iterator - { - return m_modules.rbegin(); - } - - [[nodiscard]] auto rend() const noexcept -> const_reverse_iterator - { - return m_modules.rend(); - } - - [[nodiscard]] auto crbegin() const noexcept -> const_reverse_iterator - { - return rbegin(); - } - - [[nodiscard]] auto crend() const noexcept -> const_reverse_iterator - { - return rend(); - } - - [[nodiscard]] auto front() const noexcept -> const_reference - { - return m_modules.front(); - } - - [[nodiscard]] auto back() const noexcept -> const_reference - { - return m_modules.back(); - } - - [[nodiscard]] auto size() const noexcept -> std::size_t - { - return m_modules.size(); - } - - [[nodiscard]] auto empty() const noexcept -> bool - { - return m_modules.empty(); - } - - [[nodiscard]] auto at(std::size_t index) const -> const_reference - { - return m_modules.at(index); - } - - [[nodiscard]] auto operator[](std::size_t index) const noexcept -> const_reference - { - return m_modules[index]; - } - - auto add_boot_module(boot_module module) -> void - { - m_modules.push_back(module); - } - - private: - range_type m_modules{}; - }; -} // namespace kapi::boot_modules - -#endif \ No newline at end of file diff --git a/kapi/include/kapi/boot_modules.hpp b/kapi/include/kapi/boot_modules.hpp deleted file mode 100644 index 026479d..0000000 --- a/kapi/include/kapi/boot_modules.hpp +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef TEACHOS_KAPI_BOOT_MODULES_HPP -#define TEACHOS_KAPI_BOOT_MODULES_HPP - -#include // IWYU pragma: export - -namespace kapi::boot_modules -{ - - //! @qualifier platform-defined - //! Initialize the boot module registry. - //! - //! @note This function must be implemented by the target platform. - //! - //! This function initializes the boot module registry, which is responsible for keeping track of the modules loaded - //! by the bootloader, and providing access to them for the rest of the kernel. - auto init() -> void; - - //! @qualifier kernel-defined - //! Set the boot module registry - //! - //! @param registry A new boot module registry. - auto set_boot_module_registry(boot_module_registry & registry) -> void; - - //! @qualifier kernel-defined - //! Get the boot module registry. - //! - //! @returns The boot module registry. - auto get_boot_module_registry() -> boot_module_registry &; - -} // namespace kapi::boot_modules -#endif \ No newline at end of file diff --git a/kapi/include/kapi/cio.hpp b/kapi/include/kapi/cio.hpp deleted file mode 100644 index 9bbf7fa..0000000 --- a/kapi/include/kapi/cio.hpp +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef TEACHOS_KAPI_CIO_HPP -#define TEACHOS_KAPI_CIO_HPP - -#include // IWYU pragma: export - -#include - -#include -#include - -namespace kapi::cio -{ - - //! @addtogroup kapi-cio - //! @{ - //! @} - - //! @addtogroup kapi-cio-kernel-defined - //! @{ - - //! Set the currently active output device. - //! - //! @param device A new output device. - //! @return The previously active output device. - auto set_output_device(output_device & device) -> std::optional; - - //! Write a string to the given output stream. - //! - //! @param stream The output stream to write to. - //! @param text The text to write to the stream. - auto write(output_stream stream, std::string_view text) -> void; - - //! @} - - //! @addtogroup kapi-cio-platform-defined - //! @{ - - //! Initialize the character I/O subsystem. - //! - //! If a platform support character output, it shall ensure that when this function returns, basic character - //! output can be performed on the system. - auto init() -> void; - - //! @} - -} // namespace kapi::cio - -#endif diff --git a/kapi/include/kapi/cio/output_device.hpp b/kapi/include/kapi/cio/output_device.hpp deleted file mode 100644 index 9fe2557..0000000 --- a/kapi/include/kapi/cio/output_device.hpp +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef TEACHOS_KAPI_CIO_OUTPUT_DEVICE_HPP -#define TEACHOS_KAPI_CIO_OUTPUT_DEVICE_HPP - -// IWYU pragma: private, include - -#include - -namespace kapi::cio -{ - - enum struct output_stream - { - stdout, - stderr, - }; - - //! The interface of a device able to perform character output on a platform. - struct output_device - { - output_device(output_device const &) = delete; - output_device(output_device &&) = delete; - auto operator=(output_device const &) -> output_device & = delete; - auto operator=(output_device &&) -> output_device & = delete; - - virtual ~output_device() = default; - - //! Write the given text to the output device. - //! - //! @param stream The stream to write to. - //! @param text The text to write. - auto virtual write(output_stream stream, std::string_view text) -> void = 0; - - protected: - output_device() = default; - }; - -} // namespace kapi::cio - -#endif diff --git a/kapi/include/kapi/cpu.hpp b/kapi/include/kapi/cpu.hpp deleted file mode 100644 index deaf5cd..0000000 --- a/kapi/include/kapi/cpu.hpp +++ /dev/null @@ -1,135 +0,0 @@ -#ifndef TEACHOS_KAPI_CPU_HPP -#define TEACHOS_KAPI_CPU_HPP - -#include - -#include -#include - -#include - -namespace kapi::cpu -{ - - //! @addtogroup kapi-cpu - //! @{ - - //! An exception originating from the CPU directly. - //! - //! Exception generally model interrupts that are synchronous to the instruction stream. This means that they do not - //! originate from external hardware, but rather are a product of program execution. - struct exception - { - //! The type of the exception, which identifies the reason for it being raised. - enum class type : std::uint8_t - { - //! The reason for the exception is unknown or platform-specific - unknown, - //! A page fault occurred - page_fault, - //! A memory access (either in the data or instruction stream) violated it's alignment constraints. - alignment_fault, - //! A memory access (either in the data or instruction stream) violated it's permissions. - memory_access_fault, - //! An invalid instruction was present in the instruction stream. - illegal_instruction, - //! The preconditions for the execution of an instruction were not met. - privilege_violation, - //! An arithmetic error occurred. - arithmetic_error, - //! A breakpoint was hit in the instruction stream. - breakpoint, - //! The CPU is single-stepping through the instruction stream. - single_step, - }; - - //! The type of this exception. - type type{}; - - //! The value of the instruction pointer at the time this exception was raised. - kapi::memory::linear_address instruction_pointer{}; - - //! The memory address that caused this exception. - kapi::memory::linear_address access_address{}; - - //! Whether the page was present at the time of the exception. - bool is_present{}; - - //! Whether the exception was caused by a write access. - bool is_write_access{}; - - //! Whether the exception was caused by a user mode access. - bool is_user_mode{}; - }; - - //! @} - - //! @addtogroup kapi-cpu-kernel-defined - //! @{ - - //! Dispatch an exception to the appropriate handler. - //! - //! @param context The exception context. - //! @return Whether the exception was handled. - [[nodiscard]] auto dispatch(exception const & context) -> bool; - - //! @} - - //! @addtogroup kapi-cpu-platform-defined - //! @{ - - //! Halt the CPU. - //! - //! This function terminates execution of the kernel. - [[noreturn]] auto halt() -> void; - - //! Perform early CPU initialization. - //! - //! When this function returns, the CPU is in a state where interrupt could be enabled. This function must not enable - //! interrupts itself. - auto init() -> void; - - //! Discover the CPU topology of the platform and attach it to the given CPU bus. - //! - //! @return true iff. the CPU topology was discovered successfully, false otherwise. - auto discover_topology() -> bool; - - //! @} - -} // namespace kapi::cpu - -template<> -struct kstd::formatter -{ - constexpr auto parse(kstd::format_parse_context & ctx) -> decltype(ctx.begin()) - { - return ctx.begin(); - } - - constexpr auto format(enum kapi::cpu::exception::type type, kstd::format_context & ctx) const -> void - { - switch (type) - { - case kapi::cpu::exception::type::unknown: - return ctx.push("unknown"); - case kapi::cpu::exception::type::page_fault: - return ctx.push("page fault"); - case kapi::cpu::exception::type::alignment_fault: - return ctx.push("alignment fault"); - case kapi::cpu::exception::type::memory_access_fault: - return ctx.push("memory access fault"); - case kapi::cpu::exception::type::illegal_instruction: - return ctx.push("illegal instruction"); - case kapi::cpu::exception::type::privilege_violation: - return ctx.push("privilege violation"); - case kapi::cpu::exception::type::arithmetic_error: - return ctx.push("arithmetic error"); - case kapi::cpu::exception::type::breakpoint: - return ctx.push("breakpoint"); - case kapi::cpu::exception::type::single_step: - return ctx.push("single step"); - } - } -}; - -#endif diff --git a/kapi/include/kapi/devices.hpp b/kapi/include/kapi/devices.hpp deleted file mode 100644 index b597aa8..0000000 --- a/kapi/include/kapi/devices.hpp +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef TEACHOS_KAPI_DEVICES_HPP -#define TEACHOS_KAPI_DEVICES_HPP - -#include // IWYU pragma: export -#include // IWYU pragma: export -#include // IWYU pragma: export -#include // IWYU pragma: export - -namespace kapi::devices -{ - - //! @addtogroup kapi-devices-kernel-defined - //! @{ - - //! Initialize the kernel's device management subsystem. - auto init() -> void; - - //! Get the virtual system root bus. - //! - //! @warning This function will panic if the root bus has not been initialized. - //! - //! @return a reference to the root bus. - auto get_root_bus() -> bus &; - - //! @} - - //! @addtogroup kapi-devices-platform-defined - //! @{ - - //! Initialize the platform's device tree. - auto init_platform_devices() -> void; - - //! @} - -} // namespace kapi::devices - -#endif \ No newline at end of file diff --git a/kapi/include/kapi/devices/bus.hpp b/kapi/include/kapi/devices/bus.hpp deleted file mode 100644 index 59f49f7..0000000 --- a/kapi/include/kapi/devices/bus.hpp +++ /dev/null @@ -1,63 +0,0 @@ -#ifndef TEACHOS_KAPI_DEVICES_BUS_HPP -#define TEACHOS_KAPI_DEVICES_BUS_HPP - -// IWYU pragma: private, include - -#include - -#include -#include -#include -#include - -#include -#include - -namespace kapi::devices -{ - - //! @addtogroup kapi-devices-kernel-defined - //! @{ - - //! A bus device that represents a logical/physical tree of devices and busses. - struct bus : device - { - //! Construct a bus with the given major number, minor number, and name. - //! - //! @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); - - //! 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; - - //! 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 child) -> void; - - [[nodiscard]] auto children() const -> kstd::vector> const &; - - protected: - //! Probe the bus hardware state. - //! - //! @return true iff. the bus hardware is healthy, false otherwise. - auto virtual probe() -> bool; - - private: - kstd::vector> m_devices; - kstd::vector> m_observers; - std::atomic_flag m_init_was_called{}; - std::atomic_flag m_initialized{}; - }; - - //! @} - -} // namespace kapi::devices - -#endif \ No newline at end of file diff --git a/kapi/include/kapi/devices/cpu.hpp b/kapi/include/kapi/devices/cpu.hpp deleted file mode 100644 index f8ff60c..0000000 --- a/kapi/include/kapi/devices/cpu.hpp +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef TEACHOS_KAPI_DEVICES_CPU_HPP -#define TEACHOS_KAPI_DEVICES_CPU_HPP - -#include - -#include -#include - -namespace kapi::devices -{ - - //! A virtual CPU bus to host all CPUs in the system. - struct cpu final : kapi::devices::bus - { - //! A virtual CPU Core to host all core local devices. - 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; - }; - - //! Create a new CPU with the given major and minor numbers. - //! - //! @param major The major number of this CPU - //! @param minor The minor number of this CPU, identifying the physical CPU - cpu(std::size_t major, std::size_t minor); - }; - -} // namespace kapi::devices - -#endif \ No newline at end of file diff --git a/kapi/include/kapi/devices/device.hpp b/kapi/include/kapi/devices/device.hpp deleted file mode 100644 index 70cf01f..0000000 --- a/kapi/include/kapi/devices/device.hpp +++ /dev/null @@ -1,80 +0,0 @@ -#ifndef TEACH_OS_KAPI_DEVICES_DEVICE_HPP -#define TEACH_OS_KAPI_DEVICES_DEVICE_HPP - -// IWYU pragma: private, include - -#include -#include - -#include - -namespace kapi::devices -{ - - //! @addtogroup kapi-devices-kernel-defined - //! @{ - - /** - * @brief Base device identified by a major, minor number and name. - */ - struct device - { - /** - * @brief Create a device identifier from @p major, @p minor and @p name. - * @param major Device major number. - * @param minor Device minor number. - * @param name Device name. - */ - device(size_t major, size_t minor, kstd::string const & name); - - /** - * @brief Virtual destructor for device. - */ - virtual ~device() = default; - - /** - * @brief Initialize the device. - * @return true on success, false otherwise. - */ - virtual auto init() -> bool = 0; - - /** - * @brief Returns the major number of the device. - * @return Device major number. - */ - [[nodiscard]] auto major() const -> size_t; - - /** - * @brief Returns the minor number of the device. - * @return Device minor number. - */ - [[nodiscard]] auto minor() const -> size_t; - - /** - * @brief Returns the name of the device. - * @return Device 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; - - private: - friend struct bus; - - auto set_parent(kstd::observer_ptr parent) -> void; - - size_t m_major; - size_t m_minor; - kstd::string m_name; - kstd::observer_ptr m_parent; - }; - - //! @} - -} // namespace kapi::devices - -#endif \ No newline at end of file diff --git a/kapi/include/kapi/devices/manager.hpp b/kapi/include/kapi/devices/manager.hpp deleted file mode 100644 index c9b90b4..0000000 --- a/kapi/include/kapi/devices/manager.hpp +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef TEACHOS_KAPI_DEVICES_MANAGER_HPP -#define TEACHOS_KAPI_DEVICES_MANAGER_HPP - -// IWYU pragma: private, include - -#include - -#include - -#include -#include - -namespace kapi::devices -{ - - //! @addtogroup kapi-devices-kernel-defined - //! @{ - - //! Ask the kernel to allocate a new major number. - //! - //! @return a new, unused major number. - auto allocate_major_number() -> std::size_t; - - //! Register a new device with the kernel's device manager. - //! - //! @param device The device to register. - //! @return true if the device was registered successfully, false otherwise. - auto register_device(device & device) -> bool; - - //! Unregister a device from the kernel's device manager. - //! - //! @param device The device to unregister. - //! @return true if the device was unregistered successfully, false otherwise. - auto unregister_device(device & device) -> bool; - - //! Find a device by its major and minor numbers. - //! - //! @param major the major number of the device. - //! @param minor the minor number of the device. - //! @return a pointer to the device iff. the device was found, nullptr otherwise. - auto find_device(std::size_t major, std::size_t minor) -> kstd::observer_ptr; - - //! Find a device by its name. - //! - //! @param name the name of the device. - //! @return a pointer to the device iff. the device was found, nullptr otherwise. - auto find_device(std::string_view name) -> kstd::observer_ptr; - - //! @} - -} // namespace kapi::devices - -#endif \ No newline at end of file diff --git a/kapi/include/kapi/filesystem.hpp b/kapi/include/kapi/filesystem.hpp deleted file mode 100644 index 94d42ce..0000000 --- a/kapi/include/kapi/filesystem.hpp +++ /dev/null @@ -1,73 +0,0 @@ -#ifndef TEACHOS_KAPI_FILESYSTEM_HPP -#define TEACHOS_KAPI_FILESYSTEM_HPP - -#include -#include - -#include - -namespace kapi::filesystem -{ - /** - @brief The kapi::filesystem namespace provides the interface for filesystem operations in the kernel. It includes - functions for mounting and unmounting filesystems, as well as basic file operations such as opening, closing, reading - from, and writing to files. The actual implementation of these functions is in the kernel's filesystem subsystem, - which will handle the specifics of different filesystem types and their interactions with the underlying storage - devices. - */ - - /** - @brief Mounts a filesystem from the specified @p source at the specified @p target path. - @param source The source device or filesystem to mount. - @param target The target mount point. - @return 0 on success, -1 on failure. - @qualifier kernel-defined - */ - auto mount(std::string_view source, std::string_view target) -> int; - - /** - @brief Unmounts a filesystem from the specified @p target path. - @param target The target mount point to unmount. - @return 0 on success, -1 on failure. - @qualifier kernel-defined - */ - auto umount(std::string_view target) -> int; - - /** - @brief Opens a file at the specified @p path. - @param path The path to the file to open. - @return A file descriptor on success, -1 on failure. - @qualifier kernel-defined - */ - auto open(std::string_view path) -> int; - - /** - @brief Closes a @p file_descriptor. - @param file_descriptor The file descriptor to close. - @return 0 on success, -1 on failure. - @qualifier kernel-defined - */ - auto close(int file_descriptor) -> int; - - /** - @brief Reads @p size bytes into @p buffer from a @p file_descriptor. - @param file_descriptor The file descriptor to read from. - @param buffer The buffer to store the read data. - @param size The number of bytes to read. - @return The number of bytes read on success, -1 on failure. - @qualifier kernel-defined - */ - auto read(int file_descriptor, void * buffer, size_t size) -> ssize_t; - - /** - @brief Writes @p size bytes from @p buffer to a @p file_descriptor. - @param file_descriptor The file descriptor to write to. - @param buffer The buffer containing the data to write. - @param size The number of bytes to write. - @return The number of bytes written on success, -1 on failure. - @qualifier kernel-defined - */ - auto write(int file_descriptor, void const * buffer, size_t size) -> ssize_t; -} // namespace kapi::filesystem - -#endif // TEACHOS_KAPI_FILESYSTEM_HPP \ No newline at end of file diff --git a/kapi/include/kapi/interrupts.hpp b/kapi/include/kapi/interrupts.hpp deleted file mode 100644 index 4ba0684..0000000 --- a/kapi/include/kapi/interrupts.hpp +++ /dev/null @@ -1,74 +0,0 @@ -#ifndef TEACHOS_KAPI_INTERRUPTS_HPP -#define TEACHOS_KAPI_INTERRUPTS_HPP - -#include - -namespace kapi::interrupts -{ - - //! @addtogroup kapi-interrupts - //! @{ - - //! A status that indicates whether an interrupt was handled by a handler. - enum class status : bool - { - //! The interrupt was not handled by any handler. - unhandled, - //! The interrupt was handled by at least one handler. - handled, - }; - - //! The interface for all interrupt handlers. - struct handler - { - virtual ~handler() = default; - - //! Handle an interrupt with the given IRQ number. - // - //! This function will be called by the kernel in an interrupt context. As such, the function should complete its - //! task quickly and must take care when acquiring globally shared locks. - //! - //! @param irq_number The identifier of the interrupt request that triggered the handler. - //! @return status::handled if the handler successfully handled the interrupt, status::unhandled otherwise. - virtual auto handle_interrupt(std::uint32_t irq_number) -> status = 0; - }; - - //! @} - - //! @addtogroup kapi-interrupts-kernel-defined - //! @{ - - //! Register an interrupt handler for the given IRQ number. - //! - //! @param irq_number The IRQ number to register the handler for. - //! @param handler The interrupt handler to register. - auto register_handler(std::uint32_t irq_number, handler & handler) -> void; - - //! Unregister a previously registered interrupt handler. - //! - //! @param irq_number The IRQ number to unregister the handler for. - //! @param handler The interrupt handler to unregister. - auto unregister_handler(std::uint32_t irq_number, handler & handler) -> void; - - //! Dispatch an interrupt to all registered handlers. - //! - //! @param irq_number The IRQ number to dispatch. - //! @return status::handled if the interrupt was handled by at least one handler, status::unhandled otherwise. - auto dispatch(std::uint32_t irq_number) -> status; - - //! @} - - //! @addtogroup kapi-interrupts-platform-defined - //! @{ - - //! Enable external interrupts. - auto enable() -> void; - - //! Disable external interrupts. - auto disable() -> void; - - //! @} - -} // namespace kapi::interrupts - -#endif \ No newline at end of file diff --git a/kapi/include/kapi/memory.hpp b/kapi/include/kapi/memory.hpp deleted file mode 100644 index 8ad8d6e..0000000 --- a/kapi/include/kapi/memory.hpp +++ /dev/null @@ -1,131 +0,0 @@ -#ifndef TEACHOS_KAPI_MEMORY_HPP -#define TEACHOS_KAPI_MEMORY_HPP - -#include // IWYU pragma: export -#include // IWYU pragma: export -#include // IWYU pragma: export -#include // IWYU pragma: export -#include // IWYU pragma: export -#include // IWYU pragma: export -#include // IWYU pragma: export - -#include -#include -#include - -namespace kapi::memory -{ - - using mmio_region = std::pair; - - //! @addtogroup kapi-memory-kernel-defined - //! @{ - - //! Initialize the physical memory manager. - //! - //! This function initializes the kernel-wide physical memory manager. The function will invoke the handoff handler to - //! transfer the platform-specific frame allocation state to the physical memory manager. - //! - //! @note Once this function returns, the global allocator has been replaced by the platform-agnostic, kernel-defined - //! allocator. Any state of the platform specific allocator may be released. - //! - //! @param frame_count The number of frames present in the system. - //! @param handoff_handler A function to be invoked to transfer the platform-specific frame allocation state. The - //! allocator to hand off to is passed to the handler. - auto init_pmm(std::size_t frame_count, void (&handoff_handler)(frame_allocator &)) -> void; - - //! Get the currently active frame allocator. - auto get_frame_allocator() -> frame_allocator &; - - //! Set the currently active frame allocator. - //! - //! @param allocator A new frame allocator. - //! @return The previously active frame allocator. - auto set_frame_allocator(frame_allocator & allocator) -> std::optional; - - //! Set the currently active page mapper. - //! - //! @param mapper A new page mapper. - //! @return The previously active page mapper. - auto set_page_mapper(page_mapper & mapper) -> std::optional; - - //! Allocate a new frame of physical memory - //! - //! @warning This function will panic if no frame allocator has been registered. - //! - //! @return An engaged std::optional iff. a frame could be allocated, std::nullopt otherwise. - auto allocate_frame() -> std::optional; - - //! Allocate multiple new frames of physical memory - //! - //! @warning This function will panic if no frame allocator has been registered. - //! - //! @return An engaged std::optional iff. @p count frames could be allocated, std::nullopt otherwise. - auto allocate_many_frames(std::size_t count) -> std::optional>; - - //! Map a page onto a frame. - //! - //! @warning This function will panic if no page mapper has been registered, or the page has already been mapped. - //! This function will not ensure that the frame is not already in use. - //! - //! @param page The page to map. - //! @param frame The frame to map the page into. - //! @param flags The flags to apply to this mapping. - //! @return A pointer to the first byte of the mapped page. - auto map(page page, frame frame, page_mapper::flags flags = page_mapper::flags::empty) -> std::byte *; - - //! Unmap a page. - //! - //! @warning This function will panic if no page mapper has been registered, or the page is not mapped. - //! - //! @param page The page to unmap - auto unmap(page page) -> void; - - //! Initialize the Memory-mapped I/O region system. - //! - //! @param base The base address for the MMIO region. - //! @param page_count The number of pages the MMIO region is spans. - auto init_mmio(linear_address base, std::size_t page_count) -> void; - - //! Allocate a Memory-mapped I/O region of the given size. - //! - //! @warning This function will panic if the MMIO system has not been initialized! - //! @param page_count The number of pages to allocate. - auto allocate_mmio_region(std::size_t page_count) -> mmio_region; - - //! Map a region of Memory-mapped I/O address space to a given hardware address using the given flags. - //! - //! @warning This function will panic if no page mapper has been registered, or the page has already been mapped. - //! This function will not ensure that the frame is not already in use. - //! - //! This function will always set the @p uncached flag. - //! - //! @param region The region to map. - //! @param hw_base The base of the hardware region. - //! @param flags The flags to apply. - auto map_mmio_region(mmio_region region, physical_address hw_base, page_mapper::flags flags = {}) -> std::byte *; - - //! Release a Memory-mapped I/O region. - //! - //! @warning This function will panic if the MMIO system has not been initialized! - //! @param region The region to release. - auto release_mmio_region(mmio_region region) -> void; - - //! @} - - //! @addtogroup kapi-memory-platform-defined - //! @{ - - //! Initialize the memory subsystem. - //! - //! @note This function must be implemented by the target platform. - //! - //! This function initializes the memory subsystem and activates the platform-specific frame allocator and page - //! mapper. When this function returns, a valid frame allocator and page mapper are expected to have been registered. - auto init() -> void; - - //! @} - -} // namespace kapi::memory - -#endif diff --git a/kapi/include/kapi/memory/address.hpp b/kapi/include/kapi/memory/address.hpp deleted file mode 100644 index 9231cfc..0000000 --- a/kapi/include/kapi/memory/address.hpp +++ /dev/null @@ -1,252 +0,0 @@ -#ifndef TEACHOS_KAPI_MEMORY_ADDRESS_HPP -#define TEACHOS_KAPI_MEMORY_ADDRESS_HPP - -// IWYU pragma: private, include - -#include -#include - -#include -#include -#include -#include -#include - -namespace kapi::memory -{ - - //! @qualifier kernel-defined - //! A tag for different address types. - enum struct address_type : bool - { - linear, - physical, - }; - - //! @qualifier kernel-defined - //! A physical or virtual address. - //! - //! This convenience wrapper type is used to ensure that no linear address is passed where a physical one is expected - //! and vice versa. - //! - //! @tparam Type The type of address. - template - struct address - { - //! Construct a null-address. - constexpr address() noexcept = default; - - //! Construct an address representing the given value. - //! - //! @param value The raw value to initialize this address with. - constexpr explicit address(std::uintptr_t value) noexcept - : m_value{value} - {} - - //! Construct an address representing the given pointer value. - //! - //! @param pointer The pointer value to initialize this address with. - explicit address(std::byte * pointer) noexcept - : m_value{std::bit_cast(pointer)} - {} - - //! Convert this address into a C++ pointer. - //! - //! @tparam T The type of the object this address should refer to. - //! @return This address as a typed pointer to the given type. - template - explicit operator ObjectType *() const noexcept - { - return std::bit_cast(m_value); - } - - //! Create a new address n beyond this one. - //! - //! @param n The amount to add to this address. - //! @return A new address, n further than this one. - [[nodiscard]] constexpr auto operator+(std::ptrdiff_t n) const noexcept -> address - { - return address{m_value + n}; - } - - //! Increment this address by a given amount. - //! - //! @param n The amount to Increment the address by. - //! @return A reference to this address. - constexpr auto operator+=(std::ptrdiff_t n) noexcept -> address & - { - m_value += n; - return *this; - } - - //! Increment this address by one. - //! - //! @return A reference to this address. - constexpr auto operator++() noexcept -> address & - { - return (*this += 1); - } - - //! Increment this address by one. - //! - //! @return A copy of this address before the increment. - constexpr auto operator++(int) noexcept -> address - { - auto copy = *this; - ++*this; - return copy; - } - - //! Create a new address n bytes before this one - //! - //! @param n The amount to subtract from this address - //! @return A nre address, @p n ahead of this one - [[nodiscard]] constexpr auto operator-(std::ptrdiff_t n) noexcept -> address - { - return address{m_value - n}; - } - - //! Decrement this address by a given amount. - //! - //! @param n The amount to Decrement the address by. - //! @return A reference to this address. - constexpr auto operator-=(std::ptrdiff_t n) noexcept -> address & - { - m_value -= n; - return *this; - } - - //! Decrement this address by one. - //! - //! @return A reference to this address. - constexpr auto operator--() noexcept -> address & - { - return (*this -= 1); - } - - //! Decrement this address by one. - //! - //! @return A copy of this address before the decrement. - constexpr auto operator--(int) noexcept -> address - { - auto copy = *this; - --*this; - return copy; - } - - //! Calculate the distance between this address and another one - //! - //! @param other The address to calculate the distance to. - //! @return The distance between this address and the given one. - [[nodiscard]] constexpr auto operator-(address const & other) noexcept -> std::ptrdiff_t - { - return m_value - other.m_value; - } - - //! Extract the lower bits of the address - //! - //! @note The only meaningful values for @p n are powers of two. - //! - //! @param n The divisor to use for extraction. - //! @return The lower bits of the address as defined by the divisor. - constexpr auto operator%(std::size_t n) const noexcept -> std::uintptr_t - { - return m_value % n; - } - - //! Extract the upper bits of the address - //! - //! @note The only meaningful values for @p n are powers of two. - //! - //! @param n The divisor to use for extraction. - //! @return The upper bits of the address as defined by the divisor. - constexpr auto operator/(std::size_t n) const noexcept -> std::uintptr_t - { - return m_value / n; - } - - //! Shift this address n bits to the right. - //! - //! @param n The width of the shift. - //! @return A new address representing the result of the shift operation. - constexpr auto operator>>(std::size_t n) const noexcept -> address - { - return address{m_value >> n}; - } - - //! Apply the given mask to this address. - //! - //! @param mask The mask to apply - //! @return A new address representing the result of the masking operation. - template - constexpr auto operator&(MaskType mask) const noexcept -> MaskType - { - return static_cast(m_value & mask); - } - - constexpr auto operator+(kstd::units::bytes n) const noexcept -> address - { - return address{m_value + n.value}; - } - - constexpr auto operator+=(kstd::units::bytes n) noexcept -> address & - { - return *this = *this + n; - } - - //! Check if this address is equal to another one. - constexpr auto operator==(address const &) const noexcept -> bool = default; - - //! Lexicographically compare this address with another one. - constexpr auto operator<=>(address const &) const noexcept -> std::strong_ordering = default; - - //! Extract the raw value from this address. - //! - //! @return The raw value of this address. - [[nodiscard]] constexpr auto raw() const noexcept -> std::uintptr_t - { - return m_value; - } - - private: - //! The raw address value. - std::uintptr_t m_value{}; - }; - - //! A linear/virtual address. - using linear_address = address; - - //! A physical address. - using physical_address = address; - -} // namespace kapi::memory - -namespace kstd -{ - - template - struct formatter> : kstd::formatter - { - constexpr auto static suffix = Type == kapi::memory::address_type::linear ? "%lin" : "%phy"; - - constexpr auto parse(format_parse_context & context) -> format_parse_context::iterator - { - auto result = formatter::parse(context); - if (!this->specifiers.type) - { - this->specifiers.type = 'p'; - this->specifiers.alternative_form = true; - } - return result; - } - - auto format(kapi::memory::address const & address, format_context & context) const -> void - { - formatter::format(address.raw(), context); - context.push(suffix); - } - }; - -} // namespace kstd - -#endif \ No newline at end of file diff --git a/kapi/include/kapi/memory/chunk.hpp b/kapi/include/kapi/memory/chunk.hpp deleted file mode 100644 index 485a890..0000000 --- a/kapi/include/kapi/memory/chunk.hpp +++ /dev/null @@ -1,109 +0,0 @@ -#ifndef TEACHOS_KAPI_MEMORY_CHUNK_HPP -#define TEACHOS_KAPI_MEMORY_CHUNK_HPP - -// IWYU pragma: private, include - -#include - -#include -#include - -namespace kapi::memory -{ - - //! @qualifier kernel-defined - //! A fixed-size unit of memory, indexed by a number. - //! - //! @tparam ChunkType The CRTP type of the deriving class - //! @tparam AddressType The type of addresses used to index this chunk - //! @tparam Size The size of this chunk. - template - struct chunk - { - //! The type of addresses used to index this chunk - using address_type = AddressType; - - //! The size of this chunk - constexpr auto static size = Size; - - //! Construct a new chunk handle for the chunk containing the given address. - //! - //! @param address An address contained by the desired chunk. - //! @return A handle to a chunk containing the given address. - constexpr auto static containing(address_type address) noexcept -> ChunkType - { - return ChunkType{address / size.value}; - } - - //! Get the start address of the chunk referenced by this handle. - //! - //! @return The address of the first byte contained by the chunk referenced by this handle. - [[nodiscard]] constexpr auto start_address() const noexcept -> address_type - { - return address_type{(m_number * size).value}; - } - - //! Get the number of the chunk referenced by this handle. - //! - //! @return The zero-based number of the chunk referenced by this handle. - [[nodiscard]] constexpr auto number() const noexcept -> std::size_t - { - return m_number; - } - - //! Get a handle n chunks after the one referenced by this handle. - //! - //! @param n The positive offset to this chunk. - //! @return A handle referencing the chunk n chunks after the one referenced by this handle. - constexpr auto operator+(std::size_t n) const noexcept -> ChunkType - { - return ChunkType{m_number + n}; - } - - //! Let this handle reference the next chunk after the currently reference one. - //! - //! @return A handle referencing the same chunk as this handle did before the operation. - constexpr auto operator++(int) noexcept -> ChunkType - { - auto copy = static_cast(*this); - ++*this; - return copy; - } - - //! Let this handle reference the next chunk after the currently reference one. - //! - //! @return A reference to this handle. - constexpr auto operator++() noexcept -> ChunkType & - { - ++m_number; - return static_cast(*this); - } - - //! Check if this chunk handle reference the same chunk as another one. - //! - //! @param other Another chunk handle. - constexpr auto operator==(chunk const & other) const noexcept -> bool = default; - - //! Compare the number of the chunk referenced by this handle to the one reference by another one. - //! - //! @param other Another chunk handle. - constexpr auto operator<=>(chunk const & other) const noexcept -> std::strong_ordering = default; - - private: - friend ChunkType; - - //! Construct a handle referencing the first chunk of the respective address space. - constexpr chunk() noexcept = default; - - //! Construct a handle referencing the chunk of memory with the given number. - explicit constexpr chunk(std::size_t number) noexcept - : m_number{number} - {} - - //! The number of the currently referenced chunk. - std::size_t m_number{}; - }; - -} // namespace kapi::memory - -#endif \ No newline at end of file diff --git a/kapi/include/kapi/memory/frame.hpp b/kapi/include/kapi/memory/frame.hpp deleted file mode 100644 index e423fa4..0000000 --- a/kapi/include/kapi/memory/frame.hpp +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef TEACHOS_KAPI_MEMORY_FRAME_HPP -#define TEACHOS_KAPI_MEMORY_FRAME_HPP - -// IWYU pragma: private, include - -#include -#include -#include - -#include - -namespace kapi::memory -{ - - //! @qualifier kernel-defined - //! A handle to a frame of physical memory. - //! - //! @note Contrary to the address types, this type is modeled using inheritance to support future extensions. - struct frame : chunk - { - frame() = default; - - frame(std::size_t number) - : chunk{number} - {} - - using difference_type = std::ptrdiff_t; - - //! @copydoc chunk::containing - //! - //! @note This factory shadows the base factory to aid in type deduction. - constexpr auto static containing(physical_address address) noexcept -> frame - { - return frame{chunk::containing(address)}; - } - - //! Convert a base chunk into a page. - //! - //! This constructor allows for conversion from chunk to a frame for - //! convenience. It is deliberately not explicit. - constexpr frame(chunk other) - : chunk{other} - {} - }; - -} // namespace kapi::memory - -#endif \ No newline at end of file diff --git a/kapi/include/kapi/memory/frame_allocator.hpp b/kapi/include/kapi/memory/frame_allocator.hpp deleted file mode 100644 index 784ea93..0000000 --- a/kapi/include/kapi/memory/frame_allocator.hpp +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef TEACHOS_KAPI_MEMORY_FRAME_ALLOCATOR_HPP -#define TEACHOS_KAPI_MEMORY_FRAME_ALLOCATOR_HPP - -// IWYU pragma: private, include - -#include - -#include -#include -#include - -namespace kapi::memory -{ - - //! The interface of all frame allocators. - //! - //! A frame allocator is responsible for the allocation, and deallocation, of frames of physical memory. Frames - //! obtained from an allocator shall only be deallocated, or released, via the same allocator. When a frame allocated - //! from one allocator is release via a different one (instance or type), the behavior is undefined. - struct frame_allocator - { - frame_allocator(frame_allocator const &) = delete; - frame_allocator(frame_allocator &&) = delete; - auto operator=(frame_allocator const &) -> frame_allocator & = delete; - auto operator=(frame_allocator &&) -> frame_allocator & = delete; - - virtual ~frame_allocator() = default; - - //! Allocate a frame of physical memory. - //! - //! @return An engaged std::optional iff. a new frame could be allocated, std::nullopt otherwise. - virtual auto allocate() noexcept -> std::optional - { - return allocate_many(1).transform([](auto result) { return result.first; }); - } - - //! Mark the given frame as used - virtual auto mark_used(frame frame) -> void = 0; - - //! Allocate multiple consecutive frames of physical memory. - //! - //! @param count The number of frames to allocate - //! @return an engaged optional iff. a block of consecutive frames could be allocated, std::nullopt otherwise. - virtual auto allocate_many(std::size_t count) noexcept -> std::optional> = 0; - - //! Release a frame of physical memory. - //! - //! @param frame A frame of physical memory, previously acquired by a call to the #allocate function. - virtual auto release(frame frame) -> void - { - return release_many({frame, 1}); - } - - //! Release a frame of physical memory. - //! - //! @param frame_set A set of frames of physical memory, previously acquired by a call to the #allocate_many - //! function. - virtual auto release_many(std::pair frame_set) -> void = 0; - - protected: - frame_allocator() = default; - }; - -} // namespace kapi::memory - -#endif // TEACHOS_KAPI_MEMORY_FRAME_ALLOCATOR_HPP \ No newline at end of file diff --git a/kapi/include/kapi/memory/layout.hpp b/kapi/include/kapi/memory/layout.hpp deleted file mode 100644 index 733fa96..0000000 --- a/kapi/include/kapi/memory/layout.hpp +++ /dev/null @@ -1,54 +0,0 @@ -#ifndef TEACHOS_KAPI_MEMORY_LAYOUT_HPP -#define TEACHOS_KAPI_MEMORY_LAYOUT_HPP - -// IWYU pragma: private, include - -#include - -#include - -namespace kapi::memory -{ - - //! The size of a single page of virtual memory. - //! - //! Platforms that use different sizes of pages are expected to emulate 4 KiB pages towards the kernel. - constexpr auto page_size = kstd::units::KiB(4); - - //! The size of a single frame of physical memory. - //! - //! Platforms that use different sizes of frames are expected to emulate 4 KiB pages towards the kernel. - constexpr auto frame_size = kstd::units::KiB(4); - - //! The linear base address of the higher-half direct map. - //! - //! Platforms are expected to provide a mapping of at least the first 512 GiB of available memory at this address. - constexpr auto higher_half_direct_map_base = linear_address{0xffff'8000'0000'0000uz}; - - //! The linear base address of the kernel heap. - constexpr auto heap_base = linear_address{0xffff'c000'0000'0000uz}; - - //! The linear base address of the memory region reserved for the metadata required by the PMM. - constexpr auto pmm_metadata_base = linear_address{0xffff'd000'0000'0000uz}; - - //! The linear base address of all Memory Mapped I/O mappings. - constexpr auto mmio_base = linear_address{0xffff'e000'0000'0000uz}; - - //! 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/memory/page.hpp b/kapi/include/kapi/memory/page.hpp deleted file mode 100644 index d987534..0000000 --- a/kapi/include/kapi/memory/page.hpp +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef TEACHOS_KAPI_MEMORY_PAGE_HPP -#define TEACHOS_KAPI_MEMORY_PAGE_HPP - -// IWYU pragma: private, include - -#include -#include -#include - -#include - -namespace kapi::memory -{ - - //! @qualifier kernel-defined - //! A handle to a page of virtual memory. - //! - //! @note Contrary to the address types, this type is modeled using inheritance to support future extensions. - struct page : chunk - { - page() = default; - - page(std::size_t number) - : chunk{number} - {} - - //! Convert a base chunk into a page. - //! - //! This constructor allows for conversion from chunk to a page for convenience. - //! It is deliberately not explicit. - constexpr page(chunk other) - : chunk{other} - {} - }; - -} // namespace kapi::memory - -#endif \ No newline at end of file diff --git a/kapi/include/kapi/memory/page_mapper.hpp b/kapi/include/kapi/memory/page_mapper.hpp deleted file mode 100644 index fb600b2..0000000 --- a/kapi/include/kapi/memory/page_mapper.hpp +++ /dev/null @@ -1,90 +0,0 @@ -#ifndef TEACHOS_KAPI_MEMORY_PAGE_MAPPER_HPP -#define TEACHOS_KAPI_MEMORY_PAGE_MAPPER_HPP - -// IWYU pragma: private, include - -#include -#include - -#include - -#include -#include -#include - -namespace kapi::memory -{ - - //! @qualifier platform-implemented - //! The interface of a type allowing the mapping, and unmapping, of pages onto frames. - struct page_mapper - { - page_mapper(page_mapper const &) = delete; - page_mapper(page_mapper &&) = delete; - auto operator=(page_mapper const &) -> page_mapper & = delete; - auto operator=(page_mapper &&) -> page_mapper & = delete; - - //! Platform independent page mapping flags - enum struct flags : std::uint64_t - { - empty, - writable = 1 << 0, //! The page is writable. - executable = 1 << 1, //! The page contains executable instructions. - uncached = 1 << 2, //! The page contents must not be cached. - supervisor_only = 1 << 3, //! The page is only accessible in supervisor mode. - global = 1 << 4, //! The page translation persists across context switches. - }; - - virtual ~page_mapper() = default; - - //! Map a page into a given frame, applying the given flags. - //! - //! @param page The page to map. - //! @param frame The frame to map the page into. - //! @param flags The flags to map the page with. - //! @return A pointer to the first byte of mapped page. - virtual auto map(page page, frame frame, flags flags) -> std::byte * = 0; - - //! Unmap the given page. - //! - //! @warning If the provided page is not mapped, the behavior is undefined. Implementation are encourage to - //! terminate execution via a kernel panic. - //! - //! @param page The page to unmap. - virtual auto unmap(page page) -> void = 0; - - //! Try to unmap the given page. - //! - //! @param page The page to unmap - //! @return true iff. the page was successfully unmapped, false otherwise. - virtual auto try_unmap(page page) noexcept -> bool = 0; - - //! @qualifier kernel-defined - //! Map a page into a given frame, applyint the given flags. - //! - //! @tparam T The type of data contained in the page. - //! @param page The page to map. - //! @param frame The frame to map the page into. - //! @param flags The flags to map the page with. - //! @return A pointer to the first T in the page. - template - [[nodiscard]] auto map_as(page page, frame frame, flags flags) -> T * - { - return std::bit_cast(map(page, frame, flags)); - } - - protected: - page_mapper() = default; - }; - -} // namespace kapi::memory - -namespace kstd::ext -{ - template<> - struct is_bitfield_enum : std::true_type - { - }; -} // namespace kstd::ext - -#endif \ No newline at end of file diff --git a/kapi/include/kapi/system.hpp b/kapi/include/kapi/system.hpp deleted file mode 100644 index 8a20af9..0000000 --- a/kapi/include/kapi/system.hpp +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef TEACHOS_KAPI_SYSTEM_HPP -#define TEACHOS_KAPI_SYSTEM_HPP - -#include -#include - -namespace kapi::system -{ - - //! @addtogroup kapi-system-kernel-defined - //! @{ - - //! Terminate kernel execution with the given error message. - //! - //! This function terminates the execution of the kernel and attempts to issue the given error message to the user. - //! - //! @param message The message associated with the panic - [[noreturn]] auto panic(std::string_view message, std::source_location = std::source_location::current()) -> void; - - //! @} // end group kernel-defined - - //! @addtogroup kapi-system-platform-defined - //! @{ - - //! A hook that runs once the memory subsystem has been initialized. - auto memory_initialized() -> void; - - //! @} // end group platform-defined - -} // namespace kapi::system - -#endif diff --git a/kapi/kapi/acpi.hpp b/kapi/kapi/acpi.hpp new file mode 100644 index 0000000..885fcde --- /dev/null +++ b/kapi/kapi/acpi.hpp @@ -0,0 +1,40 @@ +#ifndef TEACHOS_KAPI_ACPI_HPP +#define TEACHOS_KAPI_ACPI_HPP + +#include + +#include +#include + +#include + +namespace kapi::acpi +{ + + //! @addtogroup kapi-acpi-kernel-defined + //! @{ + + //! Initialize the ACPI subsystem and discover the available tables. + //! + //! @return true iff. a valid system description tabled was found, false otherwise. + auto init(::acpi::rsdp const & sdp) -> bool; + + //! Get a pointer to 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<::acpi::table_header const>; + + //! Get a type-cast pointer to an ACPI table by its signature. + //! + //! @tparam Signature The signature of the table to get + //! @return A pointer to the table if found, nullptr otherwise. + template + auto get_table() -> kstd::observer_ptr<::acpi::table_type_t const> + { + return kstd::make_observer(static_cast<::acpi::table_type_t const *>(get_table(Signature).get())); + } + +} // namespace kapi::acpi + +#endif diff --git a/kapi/kapi/boot.hpp b/kapi/kapi/boot.hpp new file mode 100644 index 0000000..55ca941 --- /dev/null +++ b/kapi/kapi/boot.hpp @@ -0,0 +1,17 @@ +#ifndef TEACHOS_KAPI_BOOT_HPP +#define TEACHOS_KAPI_BOOT_HPP + +namespace kapi::boot +{ + //! @qualifier platform-defined + //! Information passed from the early pre-main stage to the kernel executable. + //! + //! The specific structure of this type is defined on a platform level. + struct information; + + //! @qualifier platform-defined + //! An object passed from the early pre-main stage to the kernel executable. + extern "C" information const bootstrap_information; +} // namespace kapi::boot + +#endif diff --git a/kapi/kapi/boot_module/boot_module.hpp b/kapi/kapi/boot_module/boot_module.hpp new file mode 100644 index 0000000..9b4b165 --- /dev/null +++ b/kapi/kapi/boot_module/boot_module.hpp @@ -0,0 +1,23 @@ +#ifndef TEACHOS_KAPI_BOOT_MODULE_BOOT_MODULE_HPP +#define TEACHOS_KAPI_BOOT_MODULE_BOOT_MODULE_HPP + +#include + +#include +#include + +namespace kapi::boot_modules +{ + // ! The boot module struct + // ! + // ! The boot module struct represents a module loaded by the bootloader, and contains information about it, such as + // ! its name, virtual start address, and size. + struct boot_module + { + std::string_view name{}; + memory::linear_address start_address{}; + std::size_t size{}; + }; +} // namespace kapi::boot_modules + +#endif \ No newline at end of file diff --git a/kapi/kapi/boot_module/boot_module_registry.hpp b/kapi/kapi/boot_module/boot_module_registry.hpp new file mode 100644 index 0000000..fc3590f --- /dev/null +++ b/kapi/kapi/boot_module/boot_module_registry.hpp @@ -0,0 +1,107 @@ +#ifndef TEACHOS_KAPI_BOOT_MODULE_BOOT_MODULE_REGISTRY_HPP +#define TEACHOS_KAPI_BOOT_MODULE_BOOT_MODULE_REGISTRY_HPP + +#include + +#include + +#include + +namespace kapi::boot_modules +{ + + // ! The interface of the boot module registry + // ! + // ! The boot module registry is responsible for keeping track of the modules loaded by the bootloader, and + // ! providing access to them for the rest of the kernel. + struct boot_module_registry + { + using range_type = kstd::vector; + using value_type = range_type::value_type; + using const_reference = range_type::const_reference; + + using const_iterator = range_type::const_iterator; + using const_reverse_iterator = range_type::const_reverse_iterator; + using size_type = range_type::size_type; + + [[nodiscard]] auto begin() const noexcept -> const_iterator + { + return m_modules.begin(); + } + + [[nodiscard]] auto end() const noexcept -> const_iterator + { + return m_modules.end(); + } + + [[nodiscard]] auto cbegin() const noexcept -> const_iterator + { + return begin(); + } + + [[nodiscard]] auto cend() const noexcept -> const_iterator + { + return end(); + } + + [[nodiscard]] auto rbegin() const noexcept -> const_reverse_iterator + { + return m_modules.rbegin(); + } + + [[nodiscard]] auto rend() const noexcept -> const_reverse_iterator + { + return m_modules.rend(); + } + + [[nodiscard]] auto crbegin() const noexcept -> const_reverse_iterator + { + return rbegin(); + } + + [[nodiscard]] auto crend() const noexcept -> const_reverse_iterator + { + return rend(); + } + + [[nodiscard]] auto front() const noexcept -> const_reference + { + return m_modules.front(); + } + + [[nodiscard]] auto back() const noexcept -> const_reference + { + return m_modules.back(); + } + + [[nodiscard]] auto size() const noexcept -> std::size_t + { + return m_modules.size(); + } + + [[nodiscard]] auto empty() const noexcept -> bool + { + return m_modules.empty(); + } + + [[nodiscard]] auto at(std::size_t index) const -> const_reference + { + return m_modules.at(index); + } + + [[nodiscard]] auto operator[](std::size_t index) const noexcept -> const_reference + { + return m_modules[index]; + } + + auto add_boot_module(boot_module module) -> void + { + m_modules.push_back(module); + } + + private: + range_type m_modules{}; + }; +} // namespace kapi::boot_modules + +#endif \ No newline at end of file diff --git a/kapi/kapi/boot_modules.hpp b/kapi/kapi/boot_modules.hpp new file mode 100644 index 0000000..026479d --- /dev/null +++ b/kapi/kapi/boot_modules.hpp @@ -0,0 +1,31 @@ +#ifndef TEACHOS_KAPI_BOOT_MODULES_HPP +#define TEACHOS_KAPI_BOOT_MODULES_HPP + +#include // IWYU pragma: export + +namespace kapi::boot_modules +{ + + //! @qualifier platform-defined + //! Initialize the boot module registry. + //! + //! @note This function must be implemented by the target platform. + //! + //! This function initializes the boot module registry, which is responsible for keeping track of the modules loaded + //! by the bootloader, and providing access to them for the rest of the kernel. + auto init() -> void; + + //! @qualifier kernel-defined + //! Set the boot module registry + //! + //! @param registry A new boot module registry. + auto set_boot_module_registry(boot_module_registry & registry) -> void; + + //! @qualifier kernel-defined + //! Get the boot module registry. + //! + //! @returns The boot module registry. + auto get_boot_module_registry() -> boot_module_registry &; + +} // namespace kapi::boot_modules +#endif \ No newline at end of file diff --git a/kapi/kapi/cio.hpp b/kapi/kapi/cio.hpp new file mode 100644 index 0000000..9bbf7fa --- /dev/null +++ b/kapi/kapi/cio.hpp @@ -0,0 +1,48 @@ +#ifndef TEACHOS_KAPI_CIO_HPP +#define TEACHOS_KAPI_CIO_HPP + +#include // IWYU pragma: export + +#include + +#include +#include + +namespace kapi::cio +{ + + //! @addtogroup kapi-cio + //! @{ + //! @} + + //! @addtogroup kapi-cio-kernel-defined + //! @{ + + //! Set the currently active output device. + //! + //! @param device A new output device. + //! @return The previously active output device. + auto set_output_device(output_device & device) -> std::optional; + + //! Write a string to the given output stream. + //! + //! @param stream The output stream to write to. + //! @param text The text to write to the stream. + auto write(output_stream stream, std::string_view text) -> void; + + //! @} + + //! @addtogroup kapi-cio-platform-defined + //! @{ + + //! Initialize the character I/O subsystem. + //! + //! If a platform support character output, it shall ensure that when this function returns, basic character + //! output can be performed on the system. + auto init() -> void; + + //! @} + +} // namespace kapi::cio + +#endif diff --git a/kapi/kapi/cio/output_device.hpp b/kapi/kapi/cio/output_device.hpp new file mode 100644 index 0000000..9fe2557 --- /dev/null +++ b/kapi/kapi/cio/output_device.hpp @@ -0,0 +1,39 @@ +#ifndef TEACHOS_KAPI_CIO_OUTPUT_DEVICE_HPP +#define TEACHOS_KAPI_CIO_OUTPUT_DEVICE_HPP + +// IWYU pragma: private, include + +#include + +namespace kapi::cio +{ + + enum struct output_stream + { + stdout, + stderr, + }; + + //! The interface of a device able to perform character output on a platform. + struct output_device + { + output_device(output_device const &) = delete; + output_device(output_device &&) = delete; + auto operator=(output_device const &) -> output_device & = delete; + auto operator=(output_device &&) -> output_device & = delete; + + virtual ~output_device() = default; + + //! Write the given text to the output device. + //! + //! @param stream The stream to write to. + //! @param text The text to write. + auto virtual write(output_stream stream, std::string_view text) -> void = 0; + + protected: + output_device() = default; + }; + +} // namespace kapi::cio + +#endif diff --git a/kapi/kapi/cpu.hpp b/kapi/kapi/cpu.hpp new file mode 100644 index 0000000..deaf5cd --- /dev/null +++ b/kapi/kapi/cpu.hpp @@ -0,0 +1,135 @@ +#ifndef TEACHOS_KAPI_CPU_HPP +#define TEACHOS_KAPI_CPU_HPP + +#include + +#include +#include + +#include + +namespace kapi::cpu +{ + + //! @addtogroup kapi-cpu + //! @{ + + //! An exception originating from the CPU directly. + //! + //! Exception generally model interrupts that are synchronous to the instruction stream. This means that they do not + //! originate from external hardware, but rather are a product of program execution. + struct exception + { + //! The type of the exception, which identifies the reason for it being raised. + enum class type : std::uint8_t + { + //! The reason for the exception is unknown or platform-specific + unknown, + //! A page fault occurred + page_fault, + //! A memory access (either in the data or instruction stream) violated it's alignment constraints. + alignment_fault, + //! A memory access (either in the data or instruction stream) violated it's permissions. + memory_access_fault, + //! An invalid instruction was present in the instruction stream. + illegal_instruction, + //! The preconditions for the execution of an instruction were not met. + privilege_violation, + //! An arithmetic error occurred. + arithmetic_error, + //! A breakpoint was hit in the instruction stream. + breakpoint, + //! The CPU is single-stepping through the instruction stream. + single_step, + }; + + //! The type of this exception. + type type{}; + + //! The value of the instruction pointer at the time this exception was raised. + kapi::memory::linear_address instruction_pointer{}; + + //! The memory address that caused this exception. + kapi::memory::linear_address access_address{}; + + //! Whether the page was present at the time of the exception. + bool is_present{}; + + //! Whether the exception was caused by a write access. + bool is_write_access{}; + + //! Whether the exception was caused by a user mode access. + bool is_user_mode{}; + }; + + //! @} + + //! @addtogroup kapi-cpu-kernel-defined + //! @{ + + //! Dispatch an exception to the appropriate handler. + //! + //! @param context The exception context. + //! @return Whether the exception was handled. + [[nodiscard]] auto dispatch(exception const & context) -> bool; + + //! @} + + //! @addtogroup kapi-cpu-platform-defined + //! @{ + + //! Halt the CPU. + //! + //! This function terminates execution of the kernel. + [[noreturn]] auto halt() -> void; + + //! Perform early CPU initialization. + //! + //! When this function returns, the CPU is in a state where interrupt could be enabled. This function must not enable + //! interrupts itself. + auto init() -> void; + + //! Discover the CPU topology of the platform and attach it to the given CPU bus. + //! + //! @return true iff. the CPU topology was discovered successfully, false otherwise. + auto discover_topology() -> bool; + + //! @} + +} // namespace kapi::cpu + +template<> +struct kstd::formatter +{ + constexpr auto parse(kstd::format_parse_context & ctx) -> decltype(ctx.begin()) + { + return ctx.begin(); + } + + constexpr auto format(enum kapi::cpu::exception::type type, kstd::format_context & ctx) const -> void + { + switch (type) + { + case kapi::cpu::exception::type::unknown: + return ctx.push("unknown"); + case kapi::cpu::exception::type::page_fault: + return ctx.push("page fault"); + case kapi::cpu::exception::type::alignment_fault: + return ctx.push("alignment fault"); + case kapi::cpu::exception::type::memory_access_fault: + return ctx.push("memory access fault"); + case kapi::cpu::exception::type::illegal_instruction: + return ctx.push("illegal instruction"); + case kapi::cpu::exception::type::privilege_violation: + return ctx.push("privilege violation"); + case kapi::cpu::exception::type::arithmetic_error: + return ctx.push("arithmetic error"); + case kapi::cpu::exception::type::breakpoint: + return ctx.push("breakpoint"); + case kapi::cpu::exception::type::single_step: + return ctx.push("single step"); + } + } +}; + +#endif diff --git a/kapi/kapi/devices.hpp b/kapi/kapi/devices.hpp new file mode 100644 index 0000000..b597aa8 --- /dev/null +++ b/kapi/kapi/devices.hpp @@ -0,0 +1,37 @@ +#ifndef TEACHOS_KAPI_DEVICES_HPP +#define TEACHOS_KAPI_DEVICES_HPP + +#include // IWYU pragma: export +#include // IWYU pragma: export +#include // IWYU pragma: export +#include // IWYU pragma: export + +namespace kapi::devices +{ + + //! @addtogroup kapi-devices-kernel-defined + //! @{ + + //! Initialize the kernel's device management subsystem. + auto init() -> void; + + //! Get the virtual system root bus. + //! + //! @warning This function will panic if the root bus has not been initialized. + //! + //! @return a reference to the root bus. + auto get_root_bus() -> bus &; + + //! @} + + //! @addtogroup kapi-devices-platform-defined + //! @{ + + //! Initialize the platform's device tree. + auto init_platform_devices() -> void; + + //! @} + +} // namespace kapi::devices + +#endif \ No newline at end of file diff --git a/kapi/kapi/devices/bus.hpp b/kapi/kapi/devices/bus.hpp new file mode 100644 index 0000000..59f49f7 --- /dev/null +++ b/kapi/kapi/devices/bus.hpp @@ -0,0 +1,63 @@ +#ifndef TEACHOS_KAPI_DEVICES_BUS_HPP +#define TEACHOS_KAPI_DEVICES_BUS_HPP + +// IWYU pragma: private, include + +#include + +#include +#include +#include +#include + +#include +#include + +namespace kapi::devices +{ + + //! @addtogroup kapi-devices-kernel-defined + //! @{ + + //! A bus device that represents a logical/physical tree of devices and busses. + struct bus : device + { + //! Construct a bus with the given major number, minor number, and name. + //! + //! @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); + + //! 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; + + //! 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 child) -> void; + + [[nodiscard]] auto children() const -> kstd::vector> const &; + + protected: + //! Probe the bus hardware state. + //! + //! @return true iff. the bus hardware is healthy, false otherwise. + auto virtual probe() -> bool; + + private: + kstd::vector> m_devices; + kstd::vector> m_observers; + std::atomic_flag m_init_was_called{}; + std::atomic_flag m_initialized{}; + }; + + //! @} + +} // namespace kapi::devices + +#endif \ No newline at end of file diff --git a/kapi/kapi/devices/cpu.hpp b/kapi/kapi/devices/cpu.hpp new file mode 100644 index 0000000..f8ff60c --- /dev/null +++ b/kapi/kapi/devices/cpu.hpp @@ -0,0 +1,37 @@ +#ifndef TEACHOS_KAPI_DEVICES_CPU_HPP +#define TEACHOS_KAPI_DEVICES_CPU_HPP + +#include + +#include +#include + +namespace kapi::devices +{ + + //! A virtual CPU bus to host all CPUs in the system. + struct cpu final : kapi::devices::bus + { + //! A virtual CPU Core to host all core local devices. + 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; + }; + + //! Create a new CPU with the given major and minor numbers. + //! + //! @param major The major number of this CPU + //! @param minor The minor number of this CPU, identifying the physical CPU + cpu(std::size_t major, std::size_t minor); + }; + +} // namespace kapi::devices + +#endif \ No newline at end of file diff --git a/kapi/kapi/devices/device.hpp b/kapi/kapi/devices/device.hpp new file mode 100644 index 0000000..70cf01f --- /dev/null +++ b/kapi/kapi/devices/device.hpp @@ -0,0 +1,80 @@ +#ifndef TEACH_OS_KAPI_DEVICES_DEVICE_HPP +#define TEACH_OS_KAPI_DEVICES_DEVICE_HPP + +// IWYU pragma: private, include + +#include +#include + +#include + +namespace kapi::devices +{ + + //! @addtogroup kapi-devices-kernel-defined + //! @{ + + /** + * @brief Base device identified by a major, minor number and name. + */ + struct device + { + /** + * @brief Create a device identifier from @p major, @p minor and @p name. + * @param major Device major number. + * @param minor Device minor number. + * @param name Device name. + */ + device(size_t major, size_t minor, kstd::string const & name); + + /** + * @brief Virtual destructor for device. + */ + virtual ~device() = default; + + /** + * @brief Initialize the device. + * @return true on success, false otherwise. + */ + virtual auto init() -> bool = 0; + + /** + * @brief Returns the major number of the device. + * @return Device major number. + */ + [[nodiscard]] auto major() const -> size_t; + + /** + * @brief Returns the minor number of the device. + * @return Device minor number. + */ + [[nodiscard]] auto minor() const -> size_t; + + /** + * @brief Returns the name of the device. + * @return Device 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; + + private: + friend struct bus; + + auto set_parent(kstd::observer_ptr parent) -> void; + + size_t m_major; + size_t m_minor; + kstd::string m_name; + kstd::observer_ptr m_parent; + }; + + //! @} + +} // namespace kapi::devices + +#endif \ No newline at end of file diff --git a/kapi/kapi/devices/manager.hpp b/kapi/kapi/devices/manager.hpp new file mode 100644 index 0000000..c9b90b4 --- /dev/null +++ b/kapi/kapi/devices/manager.hpp @@ -0,0 +1,53 @@ +#ifndef TEACHOS_KAPI_DEVICES_MANAGER_HPP +#define TEACHOS_KAPI_DEVICES_MANAGER_HPP + +// IWYU pragma: private, include + +#include + +#include + +#include +#include + +namespace kapi::devices +{ + + //! @addtogroup kapi-devices-kernel-defined + //! @{ + + //! Ask the kernel to allocate a new major number. + //! + //! @return a new, unused major number. + auto allocate_major_number() -> std::size_t; + + //! Register a new device with the kernel's device manager. + //! + //! @param device The device to register. + //! @return true if the device was registered successfully, false otherwise. + auto register_device(device & device) -> bool; + + //! Unregister a device from the kernel's device manager. + //! + //! @param device The device to unregister. + //! @return true if the device was unregistered successfully, false otherwise. + auto unregister_device(device & device) -> bool; + + //! Find a device by its major and minor numbers. + //! + //! @param major the major number of the device. + //! @param minor the minor number of the device. + //! @return a pointer to the device iff. the device was found, nullptr otherwise. + auto find_device(std::size_t major, std::size_t minor) -> kstd::observer_ptr; + + //! Find a device by its name. + //! + //! @param name the name of the device. + //! @return a pointer to the device iff. the device was found, nullptr otherwise. + auto find_device(std::string_view name) -> kstd::observer_ptr; + + //! @} + +} // namespace kapi::devices + +#endif \ No newline at end of file diff --git a/kapi/kapi/filesystem.hpp b/kapi/kapi/filesystem.hpp new file mode 100644 index 0000000..94d42ce --- /dev/null +++ b/kapi/kapi/filesystem.hpp @@ -0,0 +1,73 @@ +#ifndef TEACHOS_KAPI_FILESYSTEM_HPP +#define TEACHOS_KAPI_FILESYSTEM_HPP + +#include +#include + +#include + +namespace kapi::filesystem +{ + /** + @brief The kapi::filesystem namespace provides the interface for filesystem operations in the kernel. It includes + functions for mounting and unmounting filesystems, as well as basic file operations such as opening, closing, reading + from, and writing to files. The actual implementation of these functions is in the kernel's filesystem subsystem, + which will handle the specifics of different filesystem types and their interactions with the underlying storage + devices. + */ + + /** + @brief Mounts a filesystem from the specified @p source at the specified @p target path. + @param source The source device or filesystem to mount. + @param target The target mount point. + @return 0 on success, -1 on failure. + @qualifier kernel-defined + */ + auto mount(std::string_view source, std::string_view target) -> int; + + /** + @brief Unmounts a filesystem from the specified @p target path. + @param target The target mount point to unmount. + @return 0 on success, -1 on failure. + @qualifier kernel-defined + */ + auto umount(std::string_view target) -> int; + + /** + @brief Opens a file at the specified @p path. + @param path The path to the file to open. + @return A file descriptor on success, -1 on failure. + @qualifier kernel-defined + */ + auto open(std::string_view path) -> int; + + /** + @brief Closes a @p file_descriptor. + @param file_descriptor The file descriptor to close. + @return 0 on success, -1 on failure. + @qualifier kernel-defined + */ + auto close(int file_descriptor) -> int; + + /** + @brief Reads @p size bytes into @p buffer from a @p file_descriptor. + @param file_descriptor The file descriptor to read from. + @param buffer The buffer to store the read data. + @param size The number of bytes to read. + @return The number of bytes read on success, -1 on failure. + @qualifier kernel-defined + */ + auto read(int file_descriptor, void * buffer, size_t size) -> ssize_t; + + /** + @brief Writes @p size bytes from @p buffer to a @p file_descriptor. + @param file_descriptor The file descriptor to write to. + @param buffer The buffer containing the data to write. + @param size The number of bytes to write. + @return The number of bytes written on success, -1 on failure. + @qualifier kernel-defined + */ + auto write(int file_descriptor, void const * buffer, size_t size) -> ssize_t; +} // namespace kapi::filesystem + +#endif // TEACHOS_KAPI_FILESYSTEM_HPP \ No newline at end of file diff --git a/kapi/kapi/interrupts.hpp b/kapi/kapi/interrupts.hpp new file mode 100644 index 0000000..4ba0684 --- /dev/null +++ b/kapi/kapi/interrupts.hpp @@ -0,0 +1,74 @@ +#ifndef TEACHOS_KAPI_INTERRUPTS_HPP +#define TEACHOS_KAPI_INTERRUPTS_HPP + +#include + +namespace kapi::interrupts +{ + + //! @addtogroup kapi-interrupts + //! @{ + + //! A status that indicates whether an interrupt was handled by a handler. + enum class status : bool + { + //! The interrupt was not handled by any handler. + unhandled, + //! The interrupt was handled by at least one handler. + handled, + }; + + //! The interface for all interrupt handlers. + struct handler + { + virtual ~handler() = default; + + //! Handle an interrupt with the given IRQ number. + // + //! This function will be called by the kernel in an interrupt context. As such, the function should complete its + //! task quickly and must take care when acquiring globally shared locks. + //! + //! @param irq_number The identifier of the interrupt request that triggered the handler. + //! @return status::handled if the handler successfully handled the interrupt, status::unhandled otherwise. + virtual auto handle_interrupt(std::uint32_t irq_number) -> status = 0; + }; + + //! @} + + //! @addtogroup kapi-interrupts-kernel-defined + //! @{ + + //! Register an interrupt handler for the given IRQ number. + //! + //! @param irq_number The IRQ number to register the handler for. + //! @param handler The interrupt handler to register. + auto register_handler(std::uint32_t irq_number, handler & handler) -> void; + + //! Unregister a previously registered interrupt handler. + //! + //! @param irq_number The IRQ number to unregister the handler for. + //! @param handler The interrupt handler to unregister. + auto unregister_handler(std::uint32_t irq_number, handler & handler) -> void; + + //! Dispatch an interrupt to all registered handlers. + //! + //! @param irq_number The IRQ number to dispatch. + //! @return status::handled if the interrupt was handled by at least one handler, status::unhandled otherwise. + auto dispatch(std::uint32_t irq_number) -> status; + + //! @} + + //! @addtogroup kapi-interrupts-platform-defined + //! @{ + + //! Enable external interrupts. + auto enable() -> void; + + //! Disable external interrupts. + auto disable() -> void; + + //! @} + +} // namespace kapi::interrupts + +#endif \ No newline at end of file diff --git a/kapi/kapi/memory.hpp b/kapi/kapi/memory.hpp new file mode 100644 index 0000000..8ad8d6e --- /dev/null +++ b/kapi/kapi/memory.hpp @@ -0,0 +1,131 @@ +#ifndef TEACHOS_KAPI_MEMORY_HPP +#define TEACHOS_KAPI_MEMORY_HPP + +#include // IWYU pragma: export +#include // IWYU pragma: export +#include // IWYU pragma: export +#include // IWYU pragma: export +#include // IWYU pragma: export +#include // IWYU pragma: export +#include // IWYU pragma: export + +#include +#include +#include + +namespace kapi::memory +{ + + using mmio_region = std::pair; + + //! @addtogroup kapi-memory-kernel-defined + //! @{ + + //! Initialize the physical memory manager. + //! + //! This function initializes the kernel-wide physical memory manager. The function will invoke the handoff handler to + //! transfer the platform-specific frame allocation state to the physical memory manager. + //! + //! @note Once this function returns, the global allocator has been replaced by the platform-agnostic, kernel-defined + //! allocator. Any state of the platform specific allocator may be released. + //! + //! @param frame_count The number of frames present in the system. + //! @param handoff_handler A function to be invoked to transfer the platform-specific frame allocation state. The + //! allocator to hand off to is passed to the handler. + auto init_pmm(std::size_t frame_count, void (&handoff_handler)(frame_allocator &)) -> void; + + //! Get the currently active frame allocator. + auto get_frame_allocator() -> frame_allocator &; + + //! Set the currently active frame allocator. + //! + //! @param allocator A new frame allocator. + //! @return The previously active frame allocator. + auto set_frame_allocator(frame_allocator & allocator) -> std::optional; + + //! Set the currently active page mapper. + //! + //! @param mapper A new page mapper. + //! @return The previously active page mapper. + auto set_page_mapper(page_mapper & mapper) -> std::optional; + + //! Allocate a new frame of physical memory + //! + //! @warning This function will panic if no frame allocator has been registered. + //! + //! @return An engaged std::optional iff. a frame could be allocated, std::nullopt otherwise. + auto allocate_frame() -> std::optional; + + //! Allocate multiple new frames of physical memory + //! + //! @warning This function will panic if no frame allocator has been registered. + //! + //! @return An engaged std::optional iff. @p count frames could be allocated, std::nullopt otherwise. + auto allocate_many_frames(std::size_t count) -> std::optional>; + + //! Map a page onto a frame. + //! + //! @warning This function will panic if no page mapper has been registered, or the page has already been mapped. + //! This function will not ensure that the frame is not already in use. + //! + //! @param page The page to map. + //! @param frame The frame to map the page into. + //! @param flags The flags to apply to this mapping. + //! @return A pointer to the first byte of the mapped page. + auto map(page page, frame frame, page_mapper::flags flags = page_mapper::flags::empty) -> std::byte *; + + //! Unmap a page. + //! + //! @warning This function will panic if no page mapper has been registered, or the page is not mapped. + //! + //! @param page The page to unmap + auto unmap(page page) -> void; + + //! Initialize the Memory-mapped I/O region system. + //! + //! @param base The base address for the MMIO region. + //! @param page_count The number of pages the MMIO region is spans. + auto init_mmio(linear_address base, std::size_t page_count) -> void; + + //! Allocate a Memory-mapped I/O region of the given size. + //! + //! @warning This function will panic if the MMIO system has not been initialized! + //! @param page_count The number of pages to allocate. + auto allocate_mmio_region(std::size_t page_count) -> mmio_region; + + //! Map a region of Memory-mapped I/O address space to a given hardware address using the given flags. + //! + //! @warning This function will panic if no page mapper has been registered, or the page has already been mapped. + //! This function will not ensure that the frame is not already in use. + //! + //! This function will always set the @p uncached flag. + //! + //! @param region The region to map. + //! @param hw_base The base of the hardware region. + //! @param flags The flags to apply. + auto map_mmio_region(mmio_region region, physical_address hw_base, page_mapper::flags flags = {}) -> std::byte *; + + //! Release a Memory-mapped I/O region. + //! + //! @warning This function will panic if the MMIO system has not been initialized! + //! @param region The region to release. + auto release_mmio_region(mmio_region region) -> void; + + //! @} + + //! @addtogroup kapi-memory-platform-defined + //! @{ + + //! Initialize the memory subsystem. + //! + //! @note This function must be implemented by the target platform. + //! + //! This function initializes the memory subsystem and activates the platform-specific frame allocator and page + //! mapper. When this function returns, a valid frame allocator and page mapper are expected to have been registered. + auto init() -> void; + + //! @} + +} // namespace kapi::memory + +#endif diff --git a/kapi/kapi/memory/address.hpp b/kapi/kapi/memory/address.hpp new file mode 100644 index 0000000..9231cfc --- /dev/null +++ b/kapi/kapi/memory/address.hpp @@ -0,0 +1,252 @@ +#ifndef TEACHOS_KAPI_MEMORY_ADDRESS_HPP +#define TEACHOS_KAPI_MEMORY_ADDRESS_HPP + +// IWYU pragma: private, include + +#include +#include + +#include +#include +#include +#include +#include + +namespace kapi::memory +{ + + //! @qualifier kernel-defined + //! A tag for different address types. + enum struct address_type : bool + { + linear, + physical, + }; + + //! @qualifier kernel-defined + //! A physical or virtual address. + //! + //! This convenience wrapper type is used to ensure that no linear address is passed where a physical one is expected + //! and vice versa. + //! + //! @tparam Type The type of address. + template + struct address + { + //! Construct a null-address. + constexpr address() noexcept = default; + + //! Construct an address representing the given value. + //! + //! @param value The raw value to initialize this address with. + constexpr explicit address(std::uintptr_t value) noexcept + : m_value{value} + {} + + //! Construct an address representing the given pointer value. + //! + //! @param pointer The pointer value to initialize this address with. + explicit address(std::byte * pointer) noexcept + : m_value{std::bit_cast(pointer)} + {} + + //! Convert this address into a C++ pointer. + //! + //! @tparam T The type of the object this address should refer to. + //! @return This address as a typed pointer to the given type. + template + explicit operator ObjectType *() const noexcept + { + return std::bit_cast(m_value); + } + + //! Create a new address n beyond this one. + //! + //! @param n The amount to add to this address. + //! @return A new address, n further than this one. + [[nodiscard]] constexpr auto operator+(std::ptrdiff_t n) const noexcept -> address + { + return address{m_value + n}; + } + + //! Increment this address by a given amount. + //! + //! @param n The amount to Increment the address by. + //! @return A reference to this address. + constexpr auto operator+=(std::ptrdiff_t n) noexcept -> address & + { + m_value += n; + return *this; + } + + //! Increment this address by one. + //! + //! @return A reference to this address. + constexpr auto operator++() noexcept -> address & + { + return (*this += 1); + } + + //! Increment this address by one. + //! + //! @return A copy of this address before the increment. + constexpr auto operator++(int) noexcept -> address + { + auto copy = *this; + ++*this; + return copy; + } + + //! Create a new address n bytes before this one + //! + //! @param n The amount to subtract from this address + //! @return A nre address, @p n ahead of this one + [[nodiscard]] constexpr auto operator-(std::ptrdiff_t n) noexcept -> address + { + return address{m_value - n}; + } + + //! Decrement this address by a given amount. + //! + //! @param n The amount to Decrement the address by. + //! @return A reference to this address. + constexpr auto operator-=(std::ptrdiff_t n) noexcept -> address & + { + m_value -= n; + return *this; + } + + //! Decrement this address by one. + //! + //! @return A reference to this address. + constexpr auto operator--() noexcept -> address & + { + return (*this -= 1); + } + + //! Decrement this address by one. + //! + //! @return A copy of this address before the decrement. + constexpr auto operator--(int) noexcept -> address + { + auto copy = *this; + --*this; + return copy; + } + + //! Calculate the distance between this address and another one + //! + //! @param other The address to calculate the distance to. + //! @return The distance between this address and the given one. + [[nodiscard]] constexpr auto operator-(address const & other) noexcept -> std::ptrdiff_t + { + return m_value - other.m_value; + } + + //! Extract the lower bits of the address + //! + //! @note The only meaningful values for @p n are powers of two. + //! + //! @param n The divisor to use for extraction. + //! @return The lower bits of the address as defined by the divisor. + constexpr auto operator%(std::size_t n) const noexcept -> std::uintptr_t + { + return m_value % n; + } + + //! Extract the upper bits of the address + //! + //! @note The only meaningful values for @p n are powers of two. + //! + //! @param n The divisor to use for extraction. + //! @return The upper bits of the address as defined by the divisor. + constexpr auto operator/(std::size_t n) const noexcept -> std::uintptr_t + { + return m_value / n; + } + + //! Shift this address n bits to the right. + //! + //! @param n The width of the shift. + //! @return A new address representing the result of the shift operation. + constexpr auto operator>>(std::size_t n) const noexcept -> address + { + return address{m_value >> n}; + } + + //! Apply the given mask to this address. + //! + //! @param mask The mask to apply + //! @return A new address representing the result of the masking operation. + template + constexpr auto operator&(MaskType mask) const noexcept -> MaskType + { + return static_cast(m_value & mask); + } + + constexpr auto operator+(kstd::units::bytes n) const noexcept -> address + { + return address{m_value + n.value}; + } + + constexpr auto operator+=(kstd::units::bytes n) noexcept -> address & + { + return *this = *this + n; + } + + //! Check if this address is equal to another one. + constexpr auto operator==(address const &) const noexcept -> bool = default; + + //! Lexicographically compare this address with another one. + constexpr auto operator<=>(address const &) const noexcept -> std::strong_ordering = default; + + //! Extract the raw value from this address. + //! + //! @return The raw value of this address. + [[nodiscard]] constexpr auto raw() const noexcept -> std::uintptr_t + { + return m_value; + } + + private: + //! The raw address value. + std::uintptr_t m_value{}; + }; + + //! A linear/virtual address. + using linear_address = address; + + //! A physical address. + using physical_address = address; + +} // namespace kapi::memory + +namespace kstd +{ + + template + struct formatter> : kstd::formatter + { + constexpr auto static suffix = Type == kapi::memory::address_type::linear ? "%lin" : "%phy"; + + constexpr auto parse(format_parse_context & context) -> format_parse_context::iterator + { + auto result = formatter::parse(context); + if (!this->specifiers.type) + { + this->specifiers.type = 'p'; + this->specifiers.alternative_form = true; + } + return result; + } + + auto format(kapi::memory::address const & address, format_context & context) const -> void + { + formatter::format(address.raw(), context); + context.push(suffix); + } + }; + +} // namespace kstd + +#endif \ No newline at end of file diff --git a/kapi/kapi/memory/chunk.hpp b/kapi/kapi/memory/chunk.hpp new file mode 100644 index 0000000..485a890 --- /dev/null +++ b/kapi/kapi/memory/chunk.hpp @@ -0,0 +1,109 @@ +#ifndef TEACHOS_KAPI_MEMORY_CHUNK_HPP +#define TEACHOS_KAPI_MEMORY_CHUNK_HPP + +// IWYU pragma: private, include + +#include + +#include +#include + +namespace kapi::memory +{ + + //! @qualifier kernel-defined + //! A fixed-size unit of memory, indexed by a number. + //! + //! @tparam ChunkType The CRTP type of the deriving class + //! @tparam AddressType The type of addresses used to index this chunk + //! @tparam Size The size of this chunk. + template + struct chunk + { + //! The type of addresses used to index this chunk + using address_type = AddressType; + + //! The size of this chunk + constexpr auto static size = Size; + + //! Construct a new chunk handle for the chunk containing the given address. + //! + //! @param address An address contained by the desired chunk. + //! @return A handle to a chunk containing the given address. + constexpr auto static containing(address_type address) noexcept -> ChunkType + { + return ChunkType{address / size.value}; + } + + //! Get the start address of the chunk referenced by this handle. + //! + //! @return The address of the first byte contained by the chunk referenced by this handle. + [[nodiscard]] constexpr auto start_address() const noexcept -> address_type + { + return address_type{(m_number * size).value}; + } + + //! Get the number of the chunk referenced by this handle. + //! + //! @return The zero-based number of the chunk referenced by this handle. + [[nodiscard]] constexpr auto number() const noexcept -> std::size_t + { + return m_number; + } + + //! Get a handle n chunks after the one referenced by this handle. + //! + //! @param n The positive offset to this chunk. + //! @return A handle referencing the chunk n chunks after the one referenced by this handle. + constexpr auto operator+(std::size_t n) const noexcept -> ChunkType + { + return ChunkType{m_number + n}; + } + + //! Let this handle reference the next chunk after the currently reference one. + //! + //! @return A handle referencing the same chunk as this handle did before the operation. + constexpr auto operator++(int) noexcept -> ChunkType + { + auto copy = static_cast(*this); + ++*this; + return copy; + } + + //! Let this handle reference the next chunk after the currently reference one. + //! + //! @return A reference to this handle. + constexpr auto operator++() noexcept -> ChunkType & + { + ++m_number; + return static_cast(*this); + } + + //! Check if this chunk handle reference the same chunk as another one. + //! + //! @param other Another chunk handle. + constexpr auto operator==(chunk const & other) const noexcept -> bool = default; + + //! Compare the number of the chunk referenced by this handle to the one reference by another one. + //! + //! @param other Another chunk handle. + constexpr auto operator<=>(chunk const & other) const noexcept -> std::strong_ordering = default; + + private: + friend ChunkType; + + //! Construct a handle referencing the first chunk of the respective address space. + constexpr chunk() noexcept = default; + + //! Construct a handle referencing the chunk of memory with the given number. + explicit constexpr chunk(std::size_t number) noexcept + : m_number{number} + {} + + //! The number of the currently referenced chunk. + std::size_t m_number{}; + }; + +} // namespace kapi::memory + +#endif \ No newline at end of file diff --git a/kapi/kapi/memory/frame.hpp b/kapi/kapi/memory/frame.hpp new file mode 100644 index 0000000..e423fa4 --- /dev/null +++ b/kapi/kapi/memory/frame.hpp @@ -0,0 +1,48 @@ +#ifndef TEACHOS_KAPI_MEMORY_FRAME_HPP +#define TEACHOS_KAPI_MEMORY_FRAME_HPP + +// IWYU pragma: private, include + +#include +#include +#include + +#include + +namespace kapi::memory +{ + + //! @qualifier kernel-defined + //! A handle to a frame of physical memory. + //! + //! @note Contrary to the address types, this type is modeled using inheritance to support future extensions. + struct frame : chunk + { + frame() = default; + + frame(std::size_t number) + : chunk{number} + {} + + using difference_type = std::ptrdiff_t; + + //! @copydoc chunk::containing + //! + //! @note This factory shadows the base factory to aid in type deduction. + constexpr auto static containing(physical_address address) noexcept -> frame + { + return frame{chunk::containing(address)}; + } + + //! Convert a base chunk into a page. + //! + //! This constructor allows for conversion from chunk to a frame for + //! convenience. It is deliberately not explicit. + constexpr frame(chunk other) + : chunk{other} + {} + }; + +} // namespace kapi::memory + +#endif \ No newline at end of file diff --git a/kapi/kapi/memory/frame_allocator.hpp b/kapi/kapi/memory/frame_allocator.hpp new file mode 100644 index 0000000..784ea93 --- /dev/null +++ b/kapi/kapi/memory/frame_allocator.hpp @@ -0,0 +1,66 @@ +#ifndef TEACHOS_KAPI_MEMORY_FRAME_ALLOCATOR_HPP +#define TEACHOS_KAPI_MEMORY_FRAME_ALLOCATOR_HPP + +// IWYU pragma: private, include + +#include + +#include +#include +#include + +namespace kapi::memory +{ + + //! The interface of all frame allocators. + //! + //! A frame allocator is responsible for the allocation, and deallocation, of frames of physical memory. Frames + //! obtained from an allocator shall only be deallocated, or released, via the same allocator. When a frame allocated + //! from one allocator is release via a different one (instance or type), the behavior is undefined. + struct frame_allocator + { + frame_allocator(frame_allocator const &) = delete; + frame_allocator(frame_allocator &&) = delete; + auto operator=(frame_allocator const &) -> frame_allocator & = delete; + auto operator=(frame_allocator &&) -> frame_allocator & = delete; + + virtual ~frame_allocator() = default; + + //! Allocate a frame of physical memory. + //! + //! @return An engaged std::optional iff. a new frame could be allocated, std::nullopt otherwise. + virtual auto allocate() noexcept -> std::optional + { + return allocate_many(1).transform([](auto result) { return result.first; }); + } + + //! Mark the given frame as used + virtual auto mark_used(frame frame) -> void = 0; + + //! Allocate multiple consecutive frames of physical memory. + //! + //! @param count The number of frames to allocate + //! @return an engaged optional iff. a block of consecutive frames could be allocated, std::nullopt otherwise. + virtual auto allocate_many(std::size_t count) noexcept -> std::optional> = 0; + + //! Release a frame of physical memory. + //! + //! @param frame A frame of physical memory, previously acquired by a call to the #allocate function. + virtual auto release(frame frame) -> void + { + return release_many({frame, 1}); + } + + //! Release a frame of physical memory. + //! + //! @param frame_set A set of frames of physical memory, previously acquired by a call to the #allocate_many + //! function. + virtual auto release_many(std::pair frame_set) -> void = 0; + + protected: + frame_allocator() = default; + }; + +} // namespace kapi::memory + +#endif // TEACHOS_KAPI_MEMORY_FRAME_ALLOCATOR_HPP \ No newline at end of file diff --git a/kapi/kapi/memory/layout.hpp b/kapi/kapi/memory/layout.hpp new file mode 100644 index 0000000..733fa96 --- /dev/null +++ b/kapi/kapi/memory/layout.hpp @@ -0,0 +1,54 @@ +#ifndef TEACHOS_KAPI_MEMORY_LAYOUT_HPP +#define TEACHOS_KAPI_MEMORY_LAYOUT_HPP + +// IWYU pragma: private, include + +#include + +#include + +namespace kapi::memory +{ + + //! The size of a single page of virtual memory. + //! + //! Platforms that use different sizes of pages are expected to emulate 4 KiB pages towards the kernel. + constexpr auto page_size = kstd::units::KiB(4); + + //! The size of a single frame of physical memory. + //! + //! Platforms that use different sizes of frames are expected to emulate 4 KiB pages towards the kernel. + constexpr auto frame_size = kstd::units::KiB(4); + + //! The linear base address of the higher-half direct map. + //! + //! Platforms are expected to provide a mapping of at least the first 512 GiB of available memory at this address. + constexpr auto higher_half_direct_map_base = linear_address{0xffff'8000'0000'0000uz}; + + //! The linear base address of the kernel heap. + constexpr auto heap_base = linear_address{0xffff'c000'0000'0000uz}; + + //! The linear base address of the memory region reserved for the metadata required by the PMM. + constexpr auto pmm_metadata_base = linear_address{0xffff'd000'0000'0000uz}; + + //! The linear base address of all Memory Mapped I/O mappings. + constexpr auto mmio_base = linear_address{0xffff'e000'0000'0000uz}; + + //! 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/kapi/memory/page.hpp b/kapi/kapi/memory/page.hpp new file mode 100644 index 0000000..d987534 --- /dev/null +++ b/kapi/kapi/memory/page.hpp @@ -0,0 +1,38 @@ +#ifndef TEACHOS_KAPI_MEMORY_PAGE_HPP +#define TEACHOS_KAPI_MEMORY_PAGE_HPP + +// IWYU pragma: private, include + +#include +#include +#include + +#include + +namespace kapi::memory +{ + + //! @qualifier kernel-defined + //! A handle to a page of virtual memory. + //! + //! @note Contrary to the address types, this type is modeled using inheritance to support future extensions. + struct page : chunk + { + page() = default; + + page(std::size_t number) + : chunk{number} + {} + + //! Convert a base chunk into a page. + //! + //! This constructor allows for conversion from chunk to a page for convenience. + //! It is deliberately not explicit. + constexpr page(chunk other) + : chunk{other} + {} + }; + +} // namespace kapi::memory + +#endif \ No newline at end of file diff --git a/kapi/kapi/memory/page_mapper.hpp b/kapi/kapi/memory/page_mapper.hpp new file mode 100644 index 0000000..fb600b2 --- /dev/null +++ b/kapi/kapi/memory/page_mapper.hpp @@ -0,0 +1,90 @@ +#ifndef TEACHOS_KAPI_MEMORY_PAGE_MAPPER_HPP +#define TEACHOS_KAPI_MEMORY_PAGE_MAPPER_HPP + +// IWYU pragma: private, include + +#include +#include + +#include + +#include +#include +#include + +namespace kapi::memory +{ + + //! @qualifier platform-implemented + //! The interface of a type allowing the mapping, and unmapping, of pages onto frames. + struct page_mapper + { + page_mapper(page_mapper const &) = delete; + page_mapper(page_mapper &&) = delete; + auto operator=(page_mapper const &) -> page_mapper & = delete; + auto operator=(page_mapper &&) -> page_mapper & = delete; + + //! Platform independent page mapping flags + enum struct flags : std::uint64_t + { + empty, + writable = 1 << 0, //! The page is writable. + executable = 1 << 1, //! The page contains executable instructions. + uncached = 1 << 2, //! The page contents must not be cached. + supervisor_only = 1 << 3, //! The page is only accessible in supervisor mode. + global = 1 << 4, //! The page translation persists across context switches. + }; + + virtual ~page_mapper() = default; + + //! Map a page into a given frame, applying the given flags. + //! + //! @param page The page to map. + //! @param frame The frame to map the page into. + //! @param flags The flags to map the page with. + //! @return A pointer to the first byte of mapped page. + virtual auto map(page page, frame frame, flags flags) -> std::byte * = 0; + + //! Unmap the given page. + //! + //! @warning If the provided page is not mapped, the behavior is undefined. Implementation are encourage to + //! terminate execution via a kernel panic. + //! + //! @param page The page to unmap. + virtual auto unmap(page page) -> void = 0; + + //! Try to unmap the given page. + //! + //! @param page The page to unmap + //! @return true iff. the page was successfully unmapped, false otherwise. + virtual auto try_unmap(page page) noexcept -> bool = 0; + + //! @qualifier kernel-defined + //! Map a page into a given frame, applyint the given flags. + //! + //! @tparam T The type of data contained in the page. + //! @param page The page to map. + //! @param frame The frame to map the page into. + //! @param flags The flags to map the page with. + //! @return A pointer to the first T in the page. + template + [[nodiscard]] auto map_as(page page, frame frame, flags flags) -> T * + { + return std::bit_cast(map(page, frame, flags)); + } + + protected: + page_mapper() = default; + }; + +} // namespace kapi::memory + +namespace kstd::ext +{ + template<> + struct is_bitfield_enum : std::true_type + { + }; +} // namespace kstd::ext + +#endif \ No newline at end of file diff --git a/kapi/kapi/system.hpp b/kapi/kapi/system.hpp new file mode 100644 index 0000000..8a20af9 --- /dev/null +++ b/kapi/kapi/system.hpp @@ -0,0 +1,32 @@ +#ifndef TEACHOS_KAPI_SYSTEM_HPP +#define TEACHOS_KAPI_SYSTEM_HPP + +#include +#include + +namespace kapi::system +{ + + //! @addtogroup kapi-system-kernel-defined + //! @{ + + //! Terminate kernel execution with the given error message. + //! + //! This function terminates the execution of the kernel and attempts to issue the given error message to the user. + //! + //! @param message The message associated with the panic + [[noreturn]] auto panic(std::string_view message, std::source_location = std::source_location::current()) -> void; + + //! @} // end group kernel-defined + + //! @addtogroup kapi-system-platform-defined + //! @{ + + //! A hook that runs once the memory subsystem has been initialized. + auto memory_initialized() -> void; + + //! @} // end group platform-defined + +} // namespace kapi::system + +#endif -- cgit v1.2.3