aboutsummaryrefslogtreecommitdiff
path: root/kapi
diff options
context:
space:
mode:
authorFelix Morgner <felix.morgner@ost.ch>2026-04-02 17:46:49 +0200
committerFelix Morgner <felix.morgner@ost.ch>2026-04-02 17:47:03 +0200
commitb2c3f25b453f1b71552fd93de8d11efbda36fcd1 (patch)
treeb9f097cbcf14e264a6818103a73c48a31830ffe4 /kapi
parent1f010078983e6ab4e74ee3d1efcfb3284620b002 (diff)
parentc5afb5c1ce1c084c840dbb58d73af6fe2b235ec7 (diff)
downloadteachos-b2c3f25b453f1b71552fd93de8d11efbda36fcd1.tar.xz
teachos-b2c3f25b453f1b71552fd93de8d11efbda36fcd1.zip
Merge branch 'fmorgner/develop-BA-FS26/pit-device' into develop-BA-FS26
This changeset introduces a central device management system. The system comprises the following components: - kapi::devices::bus (type) A bus can be both a real (physically present inside the machine) or virtual (purely conceptual) bus. Busses form a hierarchy rooted in the virtual root_bus (accessible via `kapi::devices::get_root_bus`). Busses are derived from `kapi::devices::device`, and own devices. This means that a bus can be attached to another bus. This facilitates a uniform structure for device ownership. Each device needs to be attached to exactly one bus. Virtual devices, e.g. RAM disks, should be attached to the root root bus (via the `add_child` member function). Once a device, or bus, has been attached to a bus, it will be initialized (by means of a call to the `init` member function). Busses are responsible to initialize their children. If a bus has already been initialized, any newly attached children will automatically be initialized. During initialization, the `probe` member function of the bus under initialization weill be invoked. This allows a bus implementation to determine if the hardware, if any, is ready to be initialized and to also perform any required initialization steps. IMPORTANT: busses take ownership of their children in the form of a `unique_ptr`. - kapi::devices (namespace) The functions `allocate_major_number`, `register_device`, `unregister_device`, and `find_device` form the device manager. The device manager is responsible for keeping a record of active devices, allowing O(log n) lookup of devices by major and minor, and O(n) lookup by name. Additionally, the device manager is responsible for handing out major numbers (via `allocate_major_number`) and keeping track of active devices. When a child is attached to a bus, it will also automatically be registered with the device manager. Lookup of devices via the device manager can be achieved by means of either overload of `find_device`. Devices should never ask the manager directly for a major number. Instead, a controller should be used, which requests a major number per device "class" (as in kind, not language class). For example, a RAM disk controller may request a single major number for all RAM disks it is going to create. When the controller creates a new device of a given "class", e.g. a RAM disk, it should then supply that major number to the new device instance. IMPORTANT: the device manager does not own the active devices. Rather it holds a `flat_map` indexed by `pair{major, minor}` and resolving to `kstd::observer_ptr<device>`. - kstd::observer_ptr (type) An observer pointer is a simple vocabulary type to express the concept of having no ownership of the pointed-to object. In essence it is equivalent to a standard C-style pointer, but expresses semantics by virtue of being a separate type.
Diffstat (limited to 'kapi')
-rw-r--r--kapi/include/kapi/devices.hpp36
-rw-r--r--kapi/include/kapi/devices/bus.hpp95
-rw-r--r--kapi/include/kapi/devices/manager.hpp53
3 files changed, 184 insertions, 0 deletions
diff --git a/kapi/include/kapi/devices.hpp b/kapi/include/kapi/devices.hpp
new file mode 100644
index 0000000..5c01b2f
--- /dev/null
+++ b/kapi/include/kapi/devices.hpp
@@ -0,0 +1,36 @@
+#ifndef TEACHOS_KAPI_DEVICES_HPP
+#define TEACHOS_KAPI_DEVICES_HPP
+
+#include "kapi/devices/bus.hpp" // IWYU pragma: export
+#include "kapi/devices/device.hpp" // IWYU pragma: export
+#include "kapi/devices/manager.hpp" // IWYU pragma: export
+
+namespace kapi::devices
+{
+
+ //! @addtogroup 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 platform-defined
+ //! @{
+
+ //! Initialize the platform's device tree.
+ auto init_platform_devices() -> void;
+
+ //! @}
+
+} // namespace kapi::devices
+
+#endif \ No newline at end of file
diff --git a/kapi/include/kapi/devices/bus.hpp b/kapi/include/kapi/devices/bus.hpp
new file mode 100644
index 0000000..ee774b7
--- /dev/null
+++ b/kapi/include/kapi/devices/bus.hpp
@@ -0,0 +1,95 @@
+#ifndef TEACHOS_KAPI_DEVICES_BUS_HPP
+#define TEACHOS_KAPI_DEVICES_BUS_HPP
+
+#include "kapi/devices/device.hpp"
+#include "kapi/devices/manager.hpp"
+#include "kapi/system.hpp"
+
+#include <kstd/memory>
+#include <kstd/print>
+#include <kstd/string>
+#include <kstd/vector>
+
+#include <algorithm>
+#include <atomic>
+#include <cstddef>
+#include <utility>
+
+namespace kapi::devices
+{
+ //! 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)
+ : device(major, minor, name)
+ {}
+
+ //! Initialize the bus and all of its children.
+ //!
+ //! @return true iff. the bus and all of its children are healthy, false otherwise.
+ auto init() -> bool final
+ {
+ if (m_initialized.test_and_set())
+ {
+ return true;
+ }
+
+ if (!probe())
+ {
+ return false;
+ }
+
+ return std::ranges::fold_left(m_devices, true, [&](bool acc, auto & child) -> bool {
+ kstd::println("[kAPI:BUS] Initializing child device {}@{}", child->name(), name());
+ return child->init() && acc;
+ });
+ }
+
+ //! Attach a child device to this bus.
+ //!
+ //! Whenever a device is attached to a bus, the bus takes sole ownership of the device.
+ //!
+ //! @param child The child device to attach.
+ auto add_child(kstd::unique_ptr<device> child) -> void
+ {
+ auto observer = m_observers.emplace_back(child.get());
+ m_devices.push_back(std::move(child));
+ kapi::devices::register_device(*observer);
+
+ if (m_initialized.test())
+ {
+ kstd::println("[kAPI:BUS] Initializing child device {}@{}", observer->name(), name());
+ if (!observer->init())
+ {
+ kapi::system::panic("[kAPI:BUS] Failed to initialize child device");
+ }
+ }
+ }
+
+ [[nodiscard]] auto children() const -> kstd::vector<kstd::observer_ptr<device>> const &
+ {
+ return m_observers;
+ }
+
+ protected:
+ //! Probe the bus hardware state.
+ //!
+ //! @return true iff. the bus hardware is healthy, false otherwise.
+ auto virtual probe() -> bool
+ {
+ return true;
+ }
+
+ private:
+ kstd::vector<kstd::unique_ptr<device>> m_devices;
+ kstd::vector<kstd::observer_ptr<device>> m_observers;
+ std::atomic_flag m_initialized{};
+ };
+} // namespace kapi::devices
+
+#endif \ No newline at end of file
diff --git a/kapi/include/kapi/devices/manager.hpp b/kapi/include/kapi/devices/manager.hpp
new file mode 100644
index 0000000..7817fbc
--- /dev/null
+++ b/kapi/include/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 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