diff options
Diffstat (limited to 'kapi')
| -rw-r--r-- | kapi/kapi/interrupts.hpp | 21 | ||||
| -rw-r--r-- | kapi/kapi/interrupts/irq_lock.hpp | 163 | ||||
| -rw-r--r-- | kapi/kapi/interrupts/state.hpp | 26 |
3 files changed, 193 insertions, 17 deletions
diff --git a/kapi/kapi/interrupts.hpp b/kapi/kapi/interrupts.hpp index 9e41b727..f5b992e2 100644 --- a/kapi/kapi/interrupts.hpp +++ b/kapi/kapi/interrupts.hpp @@ -1,6 +1,9 @@ #ifndef TEACHOS_KAPI_INTERRUPTS_HPP #define TEACHOS_KAPI_INTERRUPTS_HPP +#include <kapi/interrupts/irq_lock.hpp> +#include <kapi/interrupts/state.hpp> + #include <kstd/memory.hpp> #include <cstdint> @@ -8,9 +11,6 @@ namespace kapi::interrupts { - //! @addtogroup kapi-interrupts - //! @{ - //! A status that indicates whether an interrupt was handled by a handler. enum struct status : bool { @@ -36,9 +36,7 @@ namespace kapi::interrupts virtual auto handle_interrupt(std::uint32_t irq_number, kstd::weak_ptr<void> context) -> status = 0; }; - //! @} - - //! @addtogroup kapi-interrupts-kernel-defined + //! @name Kernel-defined API //! @{ //! Register an interrupt handler for the given IRQ number. @@ -62,17 +60,6 @@ namespace kapi::interrupts //! @} - //! @addtogroup kapi-interrupts-platform-defined - //! @{ - - //! Enable external interrupts. - auto enable() -> void; - - //! Disable external interrupts. - auto disable() -> void; - - //! @} - } // namespace kapi::interrupts #endif
\ No newline at end of file diff --git a/kapi/kapi/interrupts/irq_lock.hpp b/kapi/kapi/interrupts/irq_lock.hpp new file mode 100644 index 00000000..72a9a564 --- /dev/null +++ b/kapi/kapi/interrupts/irq_lock.hpp @@ -0,0 +1,163 @@ +#ifndef TEACHOS_KAPI_INTERRUPTS_IRQ_LOCK_HPP +#define TEACHOS_KAPI_INTERRUPTS_IRQ_LOCK_HPP + +// IWYU pragma: private, include <kapi/interrupts.hpp> + +#include <kapi/cpu.hpp> +#include <kapi/interrupts/state.hpp> +#include <kapi/system.hpp> + +#include <kstd/mutex.hpp> + +namespace kapi::interrupts +{ + + template<typename = void> + struct irq_lock; + + //! @name Kernel-defined API + //! @{ + + //! A lock to temporarily disable IRQs. + template<> + struct irq_lock<void> + { + //! Create a new IRQ lock + //! + //! This function records the creator CPU of the new lock to ensure instances are not passed across cores. + constexpr irq_lock() + : m_owner{kapi::cpu::current_id()} + {} + + constexpr irq_lock(irq_lock const &) = delete; + constexpr irq_lock(irq_lock &&) = delete; + + //! Destroy this IRQ lock. + //! + //! @warning This functions panics if the CPU executing is not the creator of this lock, or the lock is still + //! locked. + ~irq_lock() noexcept(false) + { + assert_owner(); + if (m_locked) + { + kapi::system::panic("[OS:INT] IRQ lock destroyed while it is still locked!"); + } + }; + + constexpr auto operator=(irq_lock const &) = delete; + constexpr auto operator=(irq_lock &&) = delete; + + //! Save the current IRQ state and disable further IRQs. + auto lock() -> void + { + if (!try_lock()) + { + kapi::system::panic("[OS:INT] IRQ lock reacquired while it is already held!"); + } + } + + //! Restore the previously saved IRQ state. + auto unlock() -> void + { + assert_owner(); + + if (!m_locked) + { + kapi::system::panic("[OS:INT] IRQ lock unlocked while it is not being held!"); + } + + enabled(m_old_irq_state); + m_locked = false; + } + + //! Save the current IRQ state and disable further IRQs. + auto try_lock() -> bool + { + assert_owner(); + auto old_state = enabled(); + enabled(false); + if (m_locked) + { + enabled(old_state); + return false; + } + m_locked = true; + m_old_irq_state = old_state; + return true; + } + + private: + auto assert_owner() -> void + { + if (m_owner != kapi::cpu::current_id()) + { + kapi::system::panic("[OS:INT] Tried to modify IRQ lock on a CPU that does not own it!"); + } + } + + bool m_locked{}; + bool m_old_irq_state{}; + kapi::cpu::id m_owner{}; + }; + + //! A lock to temporarily disable IRQs while also acquiring a further lock. + template<kstd::basic_lockable BasicLockable> + struct irq_lock<BasicLockable> : irq_lock<void> + { + using lockable_type = BasicLockable; + + explicit irq_lock(BasicLockable & lockable) + : m_lockable{lockable} + {} + + //! Save the current IRQ state, disable further IRQs, and lock this lock's lockable object. + auto lock() -> void + { + irq_lock<>::lock(); + m_lockable.lock(); + } + + //! Unlock this lock's lockable objects and restore the previously saved IRQ state. + auto unlock() -> void + { + m_lockable.unlock(); + irq_lock<>::unlock(); + } + + //! Save the current IRQ state, disable further IRQs, and attempt to lock this lock's lockable object. + //! + //! This function will restore the previous IRQ state if this lock's lockable object cannot be locked. + //! + //! @return @p true iff. this lock's lockable object could successfully be locked, @p false otherwise. + [[nodiscard]] auto try_lock() -> bool + requires(kstd::lockable<BasicLockable>) + { + if (!irq_lock<>::try_lock()) + { + return false; + } + + if (m_lockable.try_lock()) + { + return true; + } + + irq_lock<>::unlock(); + return false; + } + + private: + lockable_type & m_lockable; + }; + + //! @} + + irq_lock() -> irq_lock<void>; + + template<kstd::basic_lockable Lockable> + irq_lock(Lockable &) -> irq_lock<Lockable>; + +} // namespace kapi::interrupts + +#endif
\ No newline at end of file diff --git a/kapi/kapi/interrupts/state.hpp b/kapi/kapi/interrupts/state.hpp new file mode 100644 index 00000000..a33a871b --- /dev/null +++ b/kapi/kapi/interrupts/state.hpp @@ -0,0 +1,26 @@ +#ifndef TEACHOS_KAPI_INTERRUPTS_STATE_HPP +#define TEACHOS_KAPI_INTERRUPTS_STATE_HPP + +// IWYU pragma: private, include <kapi/interrupts.hpp> + +namespace kapi::interrupts +{ + + //! @name Platform-defined API + //! @{ + + //! Check if interrupts are currently enabled or not. + //! + //! @return @p true iff. interrupts are currently enabled, @p false otherwise. + auto enabled() -> bool; + + //! Enable or disable interrupts. + //! + //! @param value @p true if interrupts shall be enabled, @p false otherwise. + auto enabled(bool value) -> void; + + //! @} + +} // namespace kapi::interrupts + +#endif
\ No newline at end of file |
