aboutsummaryrefslogtreecommitdiff
path: root/kapi
diff options
context:
space:
mode:
Diffstat (limited to 'kapi')
-rw-r--r--kapi/CMakeLists.txt29
-rw-r--r--kapi/gdb/__init__.py35
-rw-r--r--kapi/gdb/boot_modules/__init__.py2
-rw-r--r--kapi/gdb/boot_modules/boot_module.py44
-rw-r--r--kapi/gdb/boot_modules/boot_module_registry.py20
-rw-r--r--kapi/gdb/devices/__init__.py1
-rw-r--r--kapi/gdb/devices/device.py20
-rw-r--r--kapi/gdb/memory/__init__.py4
-rw-r--r--kapi/gdb/memory/address.py31
-rw-r--r--kapi/gdb/memory/chunk.py41
-rw-r--r--kapi/include/kapi/cpu.hpp13
-rw-r--r--kapi/include/kapi/memory/layout.hpp26
-rw-r--r--kapi/kapi.dox8
-rw-r--r--kapi/kapi/acpi.hpp40
-rw-r--r--kapi/kapi/boot.hpp (renamed from kapi/include/kapi/boot.hpp)0
-rw-r--r--kapi/kapi/boot_module/boot_module.hpp23
-rw-r--r--kapi/kapi/boot_module/boot_module_registry.hpp107
-rw-r--r--kapi/kapi/boot_modules.hpp31
-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.hpp135
-rw-r--r--kapi/kapi/devices.hpp37
-rw-r--r--kapi/kapi/devices/bus.hpp63
-rw-r--r--kapi/kapi/devices/cpu.hpp37
-rw-r--r--kapi/kapi/devices/device.hpp80
-rw-r--r--kapi/kapi/devices/manager.hpp53
-rw-r--r--kapi/kapi/filesystem.hpp73
-rw-r--r--kapi/kapi/interrupts.hpp74
-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.hpp54
-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