diff options
| author | Lukas Oesch <lukas.oesch@ost.ch> | 2026-06-10 10:40:46 +0200 |
|---|---|---|
| committer | Lukas Oesch <lukas.oesch@ost.ch> | 2026-06-10 10:40:46 +0200 |
| commit | 33abd5cf264cb9e34121082105b0bc17b3cf7a36 (patch) | |
| tree | 36b15d53fea04f4f9d9af817100f7ad013bd9b5c /kapi | |
| parent | d01caf1c4aef3c89c68b9d1cc9fe56445f0860b5 (diff) | |
| parent | 7e27130c342b7299a1d2188a7192a7f17b5ac2ad (diff) | |
| download | kernel-33abd5cf264cb9e34121082105b0bc17b3cf7a36.tar.xz kernel-33abd5cf264cb9e34121082105b0bc17b3cf7a36.zip | |
Merge of BA-FS26 branch into develop
See merge request teachos/kernel!49
Diffstat (limited to 'kapi')
| -rw-r--r-- | kapi/CMakeLists.txt | 29 | ||||
| -rw-r--r-- | kapi/gdb/__init__.py | 35 | ||||
| -rw-r--r-- | kapi/gdb/boot_modules/__init__.py | 2 | ||||
| -rw-r--r-- | kapi/gdb/boot_modules/boot_module.py | 44 | ||||
| -rw-r--r-- | kapi/gdb/boot_modules/boot_module_registry.py | 20 | ||||
| -rw-r--r-- | kapi/gdb/devices/__init__.py | 1 | ||||
| -rw-r--r-- | kapi/gdb/devices/device.py | 20 | ||||
| -rw-r--r-- | kapi/gdb/memory/__init__.py | 4 | ||||
| -rw-r--r-- | kapi/gdb/memory/address.py | 31 | ||||
| -rw-r--r-- | kapi/gdb/memory/chunk.py | 41 | ||||
| -rw-r--r-- | kapi/include/kapi/cpu.hpp | 13 | ||||
| -rw-r--r-- | kapi/include/kapi/memory/layout.hpp | 26 | ||||
| -rw-r--r-- | kapi/kapi.dox | 8 | ||||
| -rw-r--r-- | kapi/kapi/acpi.hpp | 40 | ||||
| -rw-r--r-- | kapi/kapi/boot.hpp (renamed from kapi/include/kapi/boot.hpp) | 0 | ||||
| -rw-r--r-- | kapi/kapi/boot_module/boot_module.hpp | 23 | ||||
| -rw-r--r-- | kapi/kapi/boot_module/boot_module_registry.hpp | 107 | ||||
| -rw-r--r-- | kapi/kapi/boot_modules.hpp | 31 | ||||
| -rw-r--r-- | kapi/kapi/cio.hpp (renamed from kapi/include/kapi/cio.hpp) | 32 | ||||
| -rw-r--r-- | kapi/kapi/cio/output_device.hpp (renamed from kapi/include/kapi/cio/output_device.hpp) | 2 | ||||
| -rw-r--r-- | kapi/kapi/cpu.hpp | 135 | ||||
| -rw-r--r-- | kapi/kapi/devices.hpp | 37 | ||||
| -rw-r--r-- | kapi/kapi/devices/bus.hpp | 63 | ||||
| -rw-r--r-- | kapi/kapi/devices/cpu.hpp | 37 | ||||
| -rw-r--r-- | kapi/kapi/devices/device.hpp | 80 | ||||
| -rw-r--r-- | kapi/kapi/devices/manager.hpp | 53 | ||||
| -rw-r--r-- | kapi/kapi/filesystem.hpp | 73 | ||||
| -rw-r--r-- | kapi/kapi/interrupts.hpp | 74 | ||||
| -rw-r--r-- | kapi/kapi/memory.hpp (renamed from kapi/include/kapi/memory.hpp) | 79 | ||||
| -rw-r--r-- | kapi/kapi/memory/address.hpp (renamed from kapi/include/kapi/memory/address.hpp) | 23 | ||||
| -rw-r--r-- | kapi/kapi/memory/chunk.hpp (renamed from kapi/include/kapi/memory/chunk.hpp) | 10 | ||||
| -rw-r--r-- | kapi/kapi/memory/frame.hpp (renamed from kapi/include/kapi/memory/frame.hpp) | 8 | ||||
| -rw-r--r-- | kapi/kapi/memory/frame_allocator.hpp (renamed from kapi/include/kapi/memory/frame_allocator.hpp) | 4 | ||||
| -rw-r--r-- | kapi/kapi/memory/layout.hpp | 54 | ||||
| -rw-r--r-- | kapi/kapi/memory/page.hpp (renamed from kapi/include/kapi/memory/page.hpp) | 8 | ||||
| -rw-r--r-- | kapi/kapi/memory/page_mapper.hpp (renamed from kapi/include/kapi/memory/page_mapper.hpp) | 6 | ||||
| -rw-r--r-- | kapi/kapi/system.hpp (renamed from kapi/include/kapi/system.hpp) | 12 |
37 files changed, 1153 insertions, 112 deletions
diff --git a/kapi/CMakeLists.txt b/kapi/CMakeLists.txt index 5e914bb..f74cfb3 100644 --- a/kapi/CMakeLists.txt +++ b/kapi/CMakeLists.txt @@ -1,34 +1,31 @@ add_library("kapi" INTERFACE) -add_library("os::kapi" ALIAS "kapi") +add_library("kapi::lib" ALIAS "kapi") + +file(GLOB_RECURSE KAPI_HEADERS + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + CONFIGURE_DEPENDS + "include/**.hpp" +) target_sources("kapi" PUBLIC FILE_SET HEADERS BASE_DIRS "include" FILES - "include/kapi/boot.hpp" - "include/kapi/cio.hpp" - "include/kapi/memory.hpp" - "include/kapi/memory/address.hpp" - "include/kapi/memory/frame_allocator.hpp" - "include/kapi/memory/frame.hpp" - "include/kapi/memory/page_mapper.hpp" - "include/kapi/memory/page.hpp" - "include/kapi/system.hpp" + ${KAPI_HEADERS} ) target_include_directories("kapi" INTERFACE - "include" + "${CMAKE_CURRENT_SOURCE_DIR}" ) target_link_libraries("kapi" INTERFACE - "libs::kstd" + "acpi::lib" + "kstd::lib" "gcc" "stdc++" ) -target_compile_definitions("kapi" INTERFACE - "PLATFORM_PAGE_SIZE=${TEACHOS_PLATFORM_PAGE_SIZE}uz" - "PLATFORM_PAGING_LEVELS=${TEACHOS_PLATFORM_PAGING_LEVELS}uz" - "PLATFORM_FRAME_SIZE=${TEACHOS_PLATFORM_FRAME_SIZE}uz" +set_target_properties("kapi" PROPERTIES + VERIFY_INTERFACE_HEADER_SETS YES ) diff --git a/kapi/gdb/__init__.py b/kapi/gdb/__init__.py new file mode 100644 index 0000000..1b36753 --- /dev/null +++ b/kapi/gdb/__init__.py @@ -0,0 +1,35 @@ +import gdb.printing + +from .boot_modules import * +from .devices import * +from .memory import * + + +def build_pretty_printers(): + pp = gdb.printing.RegexpCollectionPrettyPrinter("kapi") + pp.add_printer( + "kapi_memory_address", "^kapi::memory::address<.*>$", KapiMemoryAddressPrinter + ) + pp.add_printer( + "kapi_memory_chunk", "^kapi::memory::chunk<.*>$", KapiMemoryChunkPrinter + ) + pp.add_printer("kapi_memory_frame", "^kapi::memory::frame$", KapiMemoryFramePrinter) + pp.add_printer("kapi_memory_page", "^kapi::memory::page$", KapiMemoryPagePrinter) + pp.add_printer( + "kapi_devices_device", "^kapi::devices::device$", KapiDevicesDevicePrinter + ) + pp.add_printer( + "kapi_boot_modules_boot_module", + "^kapi::boot_modules::boot_module$", + KapiBootModulesBootModulePrinter, + ) + pp.add_printer( + "kapi_boot_modules_boot_module_registry", + "^kapi::boot_modules::boot_module_registry$", + KapiBootModulesBootModuleRegistryPrinter, + ) + return pp + + +def register_printers(objfile): + gdb.printing.register_pretty_printer(objfile, build_pretty_printers(), replace=True) diff --git a/kapi/gdb/boot_modules/__init__.py b/kapi/gdb/boot_modules/__init__.py new file mode 100644 index 0000000..2a54136 --- /dev/null +++ b/kapi/gdb/boot_modules/__init__.py @@ -0,0 +1,2 @@ +from .boot_module import KapiBootModulesBootModulePrinter +from .boot_module_registry import KapiBootModulesBootModuleRegistryPrinter diff --git a/kapi/gdb/boot_modules/boot_module.py b/kapi/gdb/boot_modules/boot_module.py new file mode 100644 index 0000000..97e6584 --- /dev/null +++ b/kapi/gdb/boot_modules/boot_module.py @@ -0,0 +1,44 @@ +import gdb +from teachos import format_size + + +class KapiBootModulesBootModulePrinter(gdb.ValuePrinter): + class Iterator: + def __init__(self, begin: gdb.Value, end: gdb.Value): + self._item = begin + self._end = end + self._count = 0 + + def __iter__(self): + return self + + def __next__(self): + count = self._count + self._count = count + 1 + + if self._item == self._end: + raise StopIteration + + element = self._item.dereference() + self._item += 1 + return (f"[{count}]", element) + + def __init__(self, val): + self.__pointer_type = gdb.lookup_type("std::byte").pointer() + + self.__val = val + self.__name = val["name"] + self.__start = val["start_address"] + self.__size = int(val["size"]) + self.__begin = val["start_address"]["m_value"].cast(self.__pointer_type) + self.__end = self.__begin + self.__size + self.__pretty_name = " " + str(self.__name) if str(self.__name) != '""' else "" + + def to_string(self): + return f"boot module{self.__pretty_name} of size {format_size(self.__size)}, at {self.__start.cast(self.__pointer_type)}" + + def children(self): + return self.Iterator(self.__begin, self.__end) + + def display_hint(self): + return "array" diff --git a/kapi/gdb/boot_modules/boot_module_registry.py b/kapi/gdb/boot_modules/boot_module_registry.py new file mode 100644 index 0000000..599a823 --- /dev/null +++ b/kapi/gdb/boot_modules/boot_module_registry.py @@ -0,0 +1,20 @@ +import gdb +from teachos import format_size + + +class KapiBootModulesBootModuleRegistryPrinter(gdb.ValuePrinter): + def __init__(self, val: gdb.Value): + self.__val = val + self.__modules = val["m_modules"] + self.__size = int(self.__modules["m_size"]) + self.__element_type = gdb.lookup_type("kapi::boot_modules::boot_module") + + def to_string(self): + return f"boot module registry of size {self.__size}" + + def children(self): + yield ("[size]", self.__size) + yield ("m_modules", self.__modules) + + def display_hint(self): + return None diff --git a/kapi/gdb/devices/__init__.py b/kapi/gdb/devices/__init__.py new file mode 100644 index 0000000..3bab1ea --- /dev/null +++ b/kapi/gdb/devices/__init__.py @@ -0,0 +1 @@ +from .device import KapiDevicesDevicePrinter diff --git a/kapi/gdb/devices/device.py b/kapi/gdb/devices/device.py new file mode 100644 index 0000000..8e515ef --- /dev/null +++ b/kapi/gdb/devices/device.py @@ -0,0 +1,20 @@ +import gdb + + +class KapiDevicesDevicePrinter(gdb.ValuePrinter): + def __init__(self, val): + self.__val = val + + def to_string(self): + return ( + f"{self.__val['m_name']} @ {self.__val['m_major']}:{self.__val['m_minor']}" + ) + + def children(self): + yield ("major", self.__val["m_major"]) + yield ("minor", self.__val["m_minor"]) + yield ("name", self.__val["m_name"]) + yield ("parent", self.__val["m_parent"]) + + def display_hint(self): + return None diff --git a/kapi/gdb/memory/__init__.py b/kapi/gdb/memory/__init__.py new file mode 100644 index 0000000..2aa6564 --- /dev/null +++ b/kapi/gdb/memory/__init__.py @@ -0,0 +1,4 @@ +from .address import KapiMemoryAddressPrinter +from .chunk import KapiMemoryFramePrinter +from .chunk import KapiMemoryPagePrinter +from .chunk import KapiMemoryChunkPrinter diff --git a/kapi/gdb/memory/address.py b/kapi/gdb/memory/address.py new file mode 100644 index 0000000..429db1d --- /dev/null +++ b/kapi/gdb/memory/address.py @@ -0,0 +1,31 @@ +import gdb + + +class KapiMemoryAddressPrinter(gdb.ValuePrinter): + def __init__(self, val): + self.__val = val + self.__type = val.type.template_argument(0) + + def to_string(self): + try: + raw_address = int(self.__val["m_value"]) + type_string = str(self.__type) + + if "linear" in type_string: + suffix = "%lin" + elif "physical" in type_string: + suffix = "%phy" + else: + suffix = "%???" + + return f"{raw_address:#018x}{suffix}" + except Exception as e: + return f"{self.__val}: {e}" + + def children(self): + if "linear" in str(self.__type): + pointer_type = gdb.lookup_type("std::byte").pointer() + yield ("[bytes]", self.__val["m_value"].cast(pointer_type)) + + def display_hint(self): + return None diff --git a/kapi/gdb/memory/chunk.py b/kapi/gdb/memory/chunk.py new file mode 100644 index 0000000..74b1407 --- /dev/null +++ b/kapi/gdb/memory/chunk.py @@ -0,0 +1,41 @@ +import gdb +from teachos import format_size + + +class KapiMemoryChunkPrinter(gdb.ValuePrinter): + + def __init__(self, val: gdb.Value, typename="chunk"): + self.__val = val + try: + self.__number = int(val["m_number"]) + except gdb.error: + self.__number = "<number unreadable>" + + try: + self.__size = int(gdb.parse_and_eval(f"{val.type.name}::size")["value"]) + except gdb.error: + self.__size = "<size unreadable>" + + self.__typename = typename + + def to_string(self): + return f"{self.__typename} {self.__number} of size {format_size(self.__size)}" + + def children(self): + yield ("number", self.__number) + yield ("size", self.__size) + + def display_hint(self): + return None + + +class KapiMemoryFramePrinter(KapiMemoryChunkPrinter): + + def __init__(self, val): + super().__init__(val, "frame") + + +class KapiMemoryPagePrinter(KapiMemoryChunkPrinter): + + def __init__(self, val): + super().__init__(val, "page") diff --git a/kapi/include/kapi/cpu.hpp b/kapi/include/kapi/cpu.hpp deleted file mode 100644 index 05b84b7..0000000 --- a/kapi/include/kapi/cpu.hpp +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef TEACHOS_KAPI_CPU_HPP -#define TEACHOS_KAPI_CPU_HPP - -namespace kapi::cpu -{ - //! @qualifier platform-defined - //! Halt the CPU. - //! - //! This function terminates execution of the kernel. - [[noreturn]] auto halt() -> void; -} // namespace kapi::cpu - -#endif diff --git a/kapi/include/kapi/memory/layout.hpp b/kapi/include/kapi/memory/layout.hpp deleted file mode 100644 index f5ba0f9..0000000 --- a/kapi/include/kapi/memory/layout.hpp +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef TEACHOS_KAPI_MEMORY_LAYOUT_HPP -#define TEACHOS_KAPI_MEMORY_LAYOUT_HPP - -// IWYU pragma: private, include "kapi/memory.hpp" - -#include "kapi/memory/address.hpp" - -namespace kapi::memory -{ - - constexpr auto page_size = PLATFORM_PAGE_SIZE; - constexpr auto frame_size = PLATFORM_FRAME_SIZE; - - constexpr auto higher_half_direct_map_base = linear_address{0xffff'8000'0000'0000uz}; - - constexpr auto heap_base = linear_address{0xffff'c000'0000'0000uz}; - - constexpr auto pmm_metadata_base = linear_address{0xffff'd000'0000'0000uz}; - - constexpr auto mmio_base = linear_address{0xffff'e000'0000'0000uz}; - - constexpr auto kernel_base = linear_address{0xffff'ffff'8000'0000uz}; - -} // namespace kapi::memory - -#endif
\ No newline at end of file diff --git a/kapi/kapi.dox b/kapi/kapi.dox new file mode 100644 index 0000000..929fc1f --- /dev/null +++ b/kapi/kapi.dox @@ -0,0 +1,8 @@ +//! @namespace kapi +//! The Kernel/Platform API +//! +//! This namespace defines the interface between the platform independent kernel and each supported platform. + +//! @defgroup kapi-kernel-defined Kernel-defined API + +//! @defgroup kapi-platform-defined Platform-defined API 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 <acpi/acpi.hpp> + +#include <kstd/memory> +#include <kstd/units> + +#include <string_view> + +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<char const * Signature> + auto get_table() -> kstd::observer_ptr<::acpi::table_type_t<Signature> const> + { + return kstd::make_observer(static_cast<::acpi::table_type_t<Signature> const *>(get_table(Signature).get())); + } + +} // namespace kapi::acpi + +#endif diff --git a/kapi/include/kapi/boot.hpp b/kapi/kapi/boot.hpp index 55ca941..55ca941 100644 --- a/kapi/include/kapi/boot.hpp +++ b/kapi/kapi/boot.hpp 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 <kapi/memory.hpp> + +#include <cstddef> +#include <string_view> + +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 <kapi/boot_module/boot_module.hpp> + +#include <kstd/vector> + +#include <cstddef> + +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<boot_module>; + 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..2a88f74 --- /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 <kapi/boot_module/boot_module_registry.hpp> // 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 const &; + +} // namespace kapi::boot_modules +#endif
\ No newline at end of file diff --git a/kapi/include/kapi/cio.hpp b/kapi/kapi/cio.hpp index 48f3000..9bbf7fa 100644 --- a/kapi/include/kapi/cio.hpp +++ b/kapi/kapi/cio.hpp @@ -1,7 +1,7 @@ #ifndef TEACHOS_KAPI_CIO_HPP #define TEACHOS_KAPI_CIO_HPP -#include "kapi/cio/output_device.hpp" // IWYU pragma: export +#include <kapi/cio/output_device.hpp> // IWYU pragma: export #include <kstd/format> @@ -11,22 +11,38 @@ namespace kapi::cio { - //! @qualifier platform-defined - //! Initialize the character I/O subsystem. - //! - //! @note 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; + //! @addtogroup kapi-cio + //! @{ + //! @} + + //! @addtogroup kapi-cio-kernel-defined + //! @{ - //! @qualifier 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<output_device *>; + //! 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/kapi/cio/output_device.hpp index f08d7ba..9fe2557 100644 --- a/kapi/include/kapi/cio/output_device.hpp +++ b/kapi/kapi/cio/output_device.hpp @@ -1,7 +1,7 @@ #ifndef TEACHOS_KAPI_CIO_OUTPUT_DEVICE_HPP #define TEACHOS_KAPI_CIO_OUTPUT_DEVICE_HPP -// IWYU pragma: private, include "kapi/cio.hpp" +// IWYU pragma: private, include <kapi/cio.hpp> #include <string_view> 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 <kapi/memory.hpp> + +#include <kstd/format> +#include <kstd/memory> + +#include <cstdint> + +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<enum kapi::cpu::exception::type> +{ + 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 <kapi/devices/bus.hpp> // IWYU pragma: export +#include <kapi/devices/cpu.hpp> // IWYU pragma: export +#include <kapi/devices/device.hpp> // IWYU pragma: export +#include <kapi/devices/manager.hpp> // 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 <kapi/devices.hpp> + +#include <kapi/devices/device.hpp> + +#include <kstd/memory> +#include <kstd/print> +#include <kstd/string> +#include <kstd/vector> + +#include <atomic> +#include <cstddef> + +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<device> child) -> void; + + [[nodiscard]] auto children() const -> kstd::vector<kstd::observer_ptr<device>> const &; + + protected: + //! Probe the bus hardware state. + //! + //! @return true iff. the bus hardware is healthy, false otherwise. + auto virtual probe() -> bool; + + private: + kstd::vector<kstd::unique_ptr<device>> m_devices; + kstd::vector<kstd::observer_ptr<device>> 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 <kapi/devices/bus.hpp> + +#include <cstddef> +#include <cstdint> + +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 <kapi/devices.hpp> + +#include <kstd/memory> +#include <kstd/string> + +#include <cstddef> + +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<struct bus> parent) -> void; + + size_t m_major; + size_t m_minor; + kstd::string m_name; + kstd::observer_ptr<bus> 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 <kapi/devices.hpp> + +#include <kapi/devices/device.hpp> + +#include <kstd/memory> + +#include <cstddef> +#include <string_view> + +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<device>; + + //! 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<device>; + + //! @} + +} // 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..3bd9aaf --- /dev/null +++ b/kapi/kapi/filesystem.hpp @@ -0,0 +1,73 @@ +#ifndef TEACHOS_KAPI_FILESYSTEM_HPP +#define TEACHOS_KAPI_FILESYSTEM_HPP + +#include <kstd/unikstd.h> + +#include <cstddef> +#include <string_view> + +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) -> kstd::ssize_t; + + /** + @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) -> kstd::ssize_t; + + /** + @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) -> kstd::ssize_t; + + /** + @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(size_t file_descriptor) -> kstd::ssize_t; + + /** + @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(size_t file_descriptor, void * buffer, size_t size) -> kstd::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(size_t file_descriptor, void const * buffer, size_t size) -> kstd::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 <cstdint> + +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/kapi/memory.hpp index e31fa34..8ad8d6e 100644 --- a/kapi/include/kapi/memory.hpp +++ b/kapi/kapi/memory.hpp @@ -1,13 +1,13 @@ #ifndef TEACHOS_KAPI_MEMORY_HPP #define TEACHOS_KAPI_MEMORY_HPP -#include "kapi/memory/address.hpp" // IWYU pragma: export -#include "kapi/memory/chunk.hpp" // IWYU pragma: export -#include "kapi/memory/frame.hpp" // IWYU pragma: export -#include "kapi/memory/frame_allocator.hpp" // IWYU pragma: export -#include "kapi/memory/layout.hpp" // IWYU pragma: export -#include "kapi/memory/page.hpp" // IWYU pragma: export -#include "kapi/memory/page_mapper.hpp" // IWYU pragma: export +#include <kapi/memory/address.hpp> // IWYU pragma: export +#include <kapi/memory/chunk.hpp> // IWYU pragma: export +#include <kapi/memory/frame.hpp> // IWYU pragma: export +#include <kapi/memory/frame_allocator.hpp> // IWYU pragma: export +#include <kapi/memory/layout.hpp> // IWYU pragma: export +#include <kapi/memory/page.hpp> // IWYU pragma: export +#include <kapi/memory/page_mapper.hpp> // IWYU pragma: export #include <cstddef> #include <optional> @@ -16,16 +16,11 @@ namespace kapi::memory { - //! @qualifier 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; + using mmio_region = std::pair<linear_address, std::size_t>; + + //! @addtogroup kapi-memory-kernel-defined + //! @{ - //! @qualifier kernel-defined //! Initialize the physical memory manager. //! //! This function initializes the kernel-wide physical memory manager. The function will invoke the handoff handler to @@ -39,25 +34,21 @@ namespace kapi::memory //! allocator to hand off to is passed to the handler. auto init_pmm(std::size_t frame_count, void (&handoff_handler)(frame_allocator &)) -> void; - //! @qualifier kernel-defined //! Get the currently active frame allocator. auto get_frame_allocator() -> frame_allocator &; - //! @qualifier kernel-defined //! 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<frame_allocator *>; - //! @qualifier kernel-defined //! 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<page_mapper *>; - //! @qualifier kernel-defined //! Allocate a new frame of physical memory //! //! @warning This function will panic if no frame allocator has been registered. @@ -65,7 +56,6 @@ namespace kapi::memory //! @return An engaged std::optional iff. a frame could be allocated, std::nullopt otherwise. auto allocate_frame() -> std::optional<frame>; - //! @qualifier kernel-defined //! Allocate multiple new frames of physical memory //! //! @warning This function will panic if no frame allocator has been registered. @@ -73,7 +63,6 @@ namespace kapi::memory //! @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<std::pair<frame, std::size_t>>; - //! @qualifier kernel-defined //! 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. @@ -85,7 +74,6 @@ namespace kapi::memory //! @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 *; - //! @qualifier kernel-defined //! Unmap a page. //! //! @warning This function will panic if no page mapper has been registered, or the page is not mapped. @@ -93,6 +81,51 @@ namespace kapi::memory //! @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/kapi/memory/address.hpp index 3bef358..9231cfc 100644 --- a/kapi/include/kapi/memory/address.hpp +++ b/kapi/kapi/memory/address.hpp @@ -1,9 +1,10 @@ #ifndef TEACHOS_KAPI_MEMORY_ADDRESS_HPP #define TEACHOS_KAPI_MEMORY_ADDRESS_HPP -// IWYU pragma: private, include "kapi/memory.hpp" +// IWYU pragma: private, include <kapi/memory.hpp> #include <kstd/format> +#include <kstd/units> #include <bit> #include <compare> @@ -33,7 +34,7 @@ namespace kapi::memory struct address { //! Construct a null-address. - constexpr explicit address() noexcept = default; + constexpr address() noexcept = default; //! Construct an address representing the given value. //! @@ -183,6 +184,16 @@ namespace kapi::memory return static_cast<MaskType>(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; @@ -218,13 +229,13 @@ namespace kstd { constexpr auto static suffix = Type == kapi::memory::address_type::linear ? "%lin" : "%phy"; - constexpr auto parse(std::string_view context) -> std::string_view + constexpr auto parse(format_parse_context & context) -> format_parse_context::iterator { auto result = formatter<std::uintptr_t>::parse(context); - if (!this->specs.type) + if (!this->specifiers.type) { - this->specs.type = 'p'; - this->specs.alternative_form = true; + this->specifiers.type = 'p'; + this->specifiers.alternative_form = true; } return result; } diff --git a/kapi/include/kapi/memory/chunk.hpp b/kapi/kapi/memory/chunk.hpp index 4529535..485a890 100644 --- a/kapi/include/kapi/memory/chunk.hpp +++ b/kapi/kapi/memory/chunk.hpp @@ -1,7 +1,9 @@ #ifndef TEACHOS_KAPI_MEMORY_CHUNK_HPP #define TEACHOS_KAPI_MEMORY_CHUNK_HPP -// IWYU pragma: private, include "kapi/memory.hpp" +// IWYU pragma: private, include <kapi/memory.hpp> + +#include <kstd/units> #include <compare> #include <cstddef> @@ -15,7 +17,7 @@ namespace kapi::memory //! @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<typename ChunkType, typename AddressType, std::size_t Size> + template<typename ChunkType, typename AddressType, kstd::units::bytes Size> struct chunk { //! The type of addresses used to index this chunk @@ -30,7 +32,7 @@ namespace kapi::memory //! @return A handle to a chunk containing the given address. constexpr auto static containing(address_type address) noexcept -> ChunkType { - return ChunkType{address / size}; + return ChunkType{address / size.value}; } //! Get the start address of the chunk referenced by this handle. @@ -38,7 +40,7 @@ namespace kapi::memory //! @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}; + return address_type{(m_number * size).value}; } //! Get the number of the chunk referenced by this handle. diff --git a/kapi/include/kapi/memory/frame.hpp b/kapi/kapi/memory/frame.hpp index a55b6ff..e423fa4 100644 --- a/kapi/include/kapi/memory/frame.hpp +++ b/kapi/kapi/memory/frame.hpp @@ -1,11 +1,11 @@ #ifndef TEACHOS_KAPI_MEMORY_FRAME_HPP #define TEACHOS_KAPI_MEMORY_FRAME_HPP -// IWYU pragma: private, include "kapi/memory.hpp" +// IWYU pragma: private, include <kapi/memory.hpp> -#include "kapi/memory/address.hpp" -#include "kapi/memory/chunk.hpp" -#include "kapi/memory/layout.hpp" +#include <kapi/memory/address.hpp> +#include <kapi/memory/chunk.hpp> +#include <kapi/memory/layout.hpp> #include <cstddef> diff --git a/kapi/include/kapi/memory/frame_allocator.hpp b/kapi/kapi/memory/frame_allocator.hpp index cfa8a1c..784ea93 100644 --- a/kapi/include/kapi/memory/frame_allocator.hpp +++ b/kapi/kapi/memory/frame_allocator.hpp @@ -1,9 +1,9 @@ #ifndef TEACHOS_KAPI_MEMORY_FRAME_ALLOCATOR_HPP #define TEACHOS_KAPI_MEMORY_FRAME_ALLOCATOR_HPP -// IWYU pragma: private, include "kapi/memory.hpp" +// IWYU pragma: private, include <kapi/memory.hpp> -#include "kapi/memory/frame.hpp" +#include <kapi/memory/frame.hpp> #include <cstddef> #include <optional> 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 <kapi/memory.hpp> + +#include <kapi/memory/address.hpp> + +#include <kstd/units> + +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/kapi/memory/page.hpp index aa161ee..d987534 100644 --- a/kapi/include/kapi/memory/page.hpp +++ b/kapi/kapi/memory/page.hpp @@ -1,11 +1,11 @@ #ifndef TEACHOS_KAPI_MEMORY_PAGE_HPP #define TEACHOS_KAPI_MEMORY_PAGE_HPP -// IWYU pragma: private, include "kapi/memory.hpp" +// IWYU pragma: private, include <kapi/memory.hpp> -#include "kapi/memory/address.hpp" -#include "kapi/memory/chunk.hpp" -#include "kapi/memory/layout.hpp" +#include <kapi/memory/address.hpp> +#include <kapi/memory/chunk.hpp> +#include <kapi/memory/layout.hpp> #include <cstddef> diff --git a/kapi/include/kapi/memory/page_mapper.hpp b/kapi/kapi/memory/page_mapper.hpp index c6052e9..fb600b2 100644 --- a/kapi/include/kapi/memory/page_mapper.hpp +++ b/kapi/kapi/memory/page_mapper.hpp @@ -1,10 +1,10 @@ #ifndef TEACHOS_KAPI_MEMORY_PAGE_MAPPER_HPP #define TEACHOS_KAPI_MEMORY_PAGE_MAPPER_HPP -// IWYU pragma: private, include "kapi/memory.hpp" +// IWYU pragma: private, include <kapi/memory.hpp> -#include "kapi/memory/frame.hpp" -#include "kapi/memory/page.hpp" +#include <kapi/memory/frame.hpp> +#include <kapi/memory/page.hpp> #include <kstd/ext/bitfield_enum> diff --git a/kapi/include/kapi/system.hpp b/kapi/kapi/system.hpp index e5c43c5..8a20af9 100644 --- a/kapi/include/kapi/system.hpp +++ b/kapi/kapi/system.hpp @@ -7,7 +7,9 @@ namespace kapi::system { - //! @qualifier kernel-defined + //! @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. @@ -15,10 +17,16 @@ namespace kapi::system //! @param message The message associated with the panic [[noreturn]] auto panic(std::string_view message, std::source_location = std::source_location::current()) -> void; - //! @qualifier platform-defined + //! @} // 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 |
