[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20241018055125.2784186-3-boqun.feng@gmail.com>
Date: Thu, 17 Oct 2024 22:51:21 -0700
From: Boqun Feng <boqun.feng@...il.com>
To: "Thomas Gleixner" <tglx@...utronix.de>
Cc: Dirk Behme <dirk.behme@...il.com>,
Lyude Paul <lyude@...hat.com>,
rust-for-linux@...r.kernel.org,
Danilo Krummrich <dakr@...hat.com>,
airlied@...hat.com,
Ingo Molnar <mingo@...hat.com>,
will@...nel.org,
Waiman Long <longman@...hat.com>,
Peter Zijlstra <peterz@...radead.org>,
linux-kernel@...r.kernel.org,
Miguel Ojeda <ojeda@...nel.org>,
Alex Gaynor <alex.gaynor@...il.com>,
wedsonaf@...il.com,
Gary Guo <gary@...yguo.net>,
Björn Roy Baron <bjorn3_gh@...tonmail.com>,
Benno Lossin <benno.lossin@...ton.me>,
Andreas Hindborg <a.hindborg@...sung.com>,
aliceryhl@...gle.com,
Trevor Gross <tmgross@...ch.edu>,
Boqun Feng <boqun.feng@...il.com>
Subject: [POC 2/6] rust: Introduce interrupt module
From: Lyude Paul <lyude@...hat.com>
This introduces a module for dealing with interrupt-disabled contexts,
including the ability to enable and disable interrupts along with the
ability to annotate functions as expecting that IRQs are already
disabled on the local CPU.
[Boqun: This is based on Lyude's work on interrupt disable abstraction,
I port to the new local_interrupt_disable() mechanism to make it work
as a guard type. I cannot even take the credit of this design, since
Lyude also brought up the same idea in zulip. Anyway, this is only for
POC purpose, and of course all bugs are mine]
Co-Developed-by: Lyude Paul <lyude@...hat.com>
Signed-off-by: Lyude Paul <lyude@...hat.com>
Signed-off-by: Boqun Feng <boqun.feng@...il.com>
---
rust/helpers/helpers.c | 1 +
rust/helpers/interrupt.c | 18 +++++++++++
rust/kernel/interrupt.rs | 64 ++++++++++++++++++++++++++++++++++++++++
rust/kernel/lib.rs | 1 +
4 files changed, 84 insertions(+)
create mode 100644 rust/helpers/interrupt.c
create mode 100644 rust/kernel/interrupt.rs
diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c
index 30f40149f3a9..f6e5b33eaff8 100644
--- a/rust/helpers/helpers.c
+++ b/rust/helpers/helpers.c
@@ -12,6 +12,7 @@
#include "build_assert.c"
#include "build_bug.c"
#include "err.c"
+#include "interrupt.c"
#include "kunit.c"
#include "mutex.c"
#include "page.c"
diff --git a/rust/helpers/interrupt.c b/rust/helpers/interrupt.c
new file mode 100644
index 000000000000..e58da42916da
--- /dev/null
+++ b/rust/helpers/interrupt.c
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/irqflags.h>
+
+void rust_helper_local_interrupt_disable(void)
+{
+ local_interrupt_disable();
+}
+
+void rust_helper_local_interrupt_enable(void)
+{
+ local_interrupt_enable();
+}
+
+bool rust_helper_irqs_disabled(void)
+{
+ return irqs_disabled();
+}
diff --git a/rust/kernel/interrupt.rs b/rust/kernel/interrupt.rs
new file mode 100644
index 000000000000..fe5a36877538
--- /dev/null
+++ b/rust/kernel/interrupt.rs
@@ -0,0 +1,64 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Interrupt controls
+//!
+//! This module allows Rust code to control processor interrupts. [`with_interrupt_disabled()`] may be
+//! used for nested disables of interrupts, whereas [`InterruptDisabled`] can be used for annotating code
+//! that requires interrupts to be disabled.
+
+use bindings;
+use core::marker::*;
+
+/// XXX: Temporarily definition for NotThreadSafe
+pub type NotThreadSafe = PhantomData<*mut ()>;
+
+/// XXX: Temporarily const for NotThreadSafe
+#[allow(non_upper_case_globals)]
+pub const NotThreadSafe: NotThreadSafe = PhantomData;
+
+/// A guard that represent interrupt disable protection.
+///
+/// [`InterruptDisabled`] is a guard type that represent interrupts have been disabled. Certain
+/// functions take an immutable reference of [`InterruptDisabled`] in order to require that they may
+/// only be run in interrupt-disabled contexts.
+///
+/// This is a marker type; it has no size, and is simply used as a compile-time guarantee that
+/// interrupts are disabled where required.
+///
+/// This token can be created by [`with_interrupt_disabled`]. See [`with_interrupt_disabled`] for examples and
+/// further information.
+///
+/// # Invariants
+///
+/// Interrupts are disabled with `local_interrupt_disable()` when an object of this type exists.
+pub struct InterruptDisabled(NotThreadSafe);
+
+/// Disable interrupts.
+pub fn interrupt_disable() -> InterruptDisabled {
+ // SAFETY: It's always safe to call `local_interrupt_disable()`.
+ unsafe { bindings::local_interrupt_disable() };
+
+ InterruptDisabled(NotThreadSafe)
+}
+
+impl Drop for InterruptDisabled {
+ fn drop(&mut self) {
+ // SAFETY: Per type invariants, a `local_interrupt_disable()` must be called to create this
+ // object, hence call the corresponding `local_interrupt_enable()` is safe.
+ unsafe { bindings::local_interrupt_enable() };
+ }
+}
+
+impl InterruptDisabled {
+ const ASSUME_INTERRUPT_DISABLED: &'static InterruptDisabled = &InterruptDisabled(NotThreadSafe);
+
+ /// Assume that interrupts are disabled.
+ ///
+ /// # Safety
+ ///
+ /// For the whole life `'a`, interrupts must be considered disabled, for example an interrupt
+ /// handler.
+ pub unsafe fn assume_interrupt_disabled<'a>() -> &'a InterruptDisabled {
+ Self::ASSUME_INTERRUPT_DISABLED
+ }
+}
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
index b5f4b3ce6b48..56ff464b7905 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -35,6 +35,7 @@
#[cfg(CONFIG_RUST_FW_LOADER_ABSTRACTIONS)]
pub mod firmware;
pub mod init;
+pub mod interrupt;
pub mod ioctl;
#[cfg(CONFIG_KUNIT)]
pub mod kunit;
--
2.45.2
Powered by blists - more mailing lists