On Thu, Jun 06, 2024 at 03:05:24PM +0000, Alice Ryhl wrote: > Add static_call support by mirroring how C does. When the platform does > not support static calls (right now, that means that it is not x86), > then the function pointer is loaded from a global and called. Otherwise, > we generate a call to a trampoline function, and objtool is used to make > these calls patchable at runtime.
This is absolutely unreadable gibberish -- how am I supposed to keep this in sync with the rest of the static_call infrastructure? > Signed-off-by: Alice Ryhl <alicer...@google.com> > --- > rust/kernel/lib.rs | 1 + > rust/kernel/static_call.rs | 92 > ++++++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 93 insertions(+) > > diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs > index fbd91a48ff8b..d534b1178955 100644 > --- a/rust/kernel/lib.rs > +++ b/rust/kernel/lib.rs > @@ -38,6 +38,7 @@ > pub mod prelude; > pub mod print; > mod static_assert; > +pub mod static_call; > #[doc(hidden)] > pub mod std_vendor; > pub mod str; > diff --git a/rust/kernel/static_call.rs b/rust/kernel/static_call.rs > new file mode 100644 > index 000000000000..f7b8ba7bf1fb > --- /dev/null > +++ b/rust/kernel/static_call.rs > @@ -0,0 +1,92 @@ > +// SPDX-License-Identifier: GPL-2.0 > + > +// Copyright (C) 2024 Google LLC. > + > +//! Logic for static calls. > + > +#[macro_export] > +#[doc(hidden)] > +macro_rules! ty_underscore_for { > + ($arg:expr) => { > + _ > + }; > +} > + > +#[doc(hidden)] > +#[repr(transparent)] > +pub struct AddressableStaticCallKey { > + _ptr: *const bindings::static_call_key, > +} > +unsafe impl Sync for AddressableStaticCallKey {} > +impl AddressableStaticCallKey { > + pub const fn new(ptr: *const bindings::static_call_key) -> Self { > + Self { _ptr: ptr } > + } > +} > + > +#[cfg(CONFIG_HAVE_STATIC_CALL)] > +#[doc(hidden)] > +#[macro_export] > +macro_rules! _static_call { > + ($name:ident($($args:expr),* $(,)?)) => {{ > + // Symbol mangling will give this symbol a unique name. > + #[cfg(CONFIG_HAVE_STATIC_CALL_INLINE)] > + #[link_section = ".discard.addressable"] > + #[used] > + static __ADDRESSABLE: $crate::static_call::AddressableStaticCallKey > = unsafe { > + > $crate::static_call::AddressableStaticCallKey::new(::core::ptr::addr_of!( > + $crate::macros::paste! { $crate::bindings:: [<__SCK__ $name > >]; } > + )) > + }; > + > + let fn_ptr: unsafe extern "C" > fn($($crate::static_call::ty_underscore_for!($args)),*) -> _ = > + $crate::macros::paste! { $crate::bindings:: [<__SCT__ $name >]; > }; > + (fn_ptr)($($args),*) > + }}; > +} > + > +#[cfg(not(CONFIG_HAVE_STATIC_CALL))] > +#[doc(hidden)] > +#[macro_export] > +macro_rules! _static_call { > + ($name:ident($($args:expr),* $(,)?)) => {{ > + let void_ptr_fn: *mut ::core::ffi::c_void = > + $crate::macros::paste! { $crate::bindings:: [<__SCK__ $name >]; > }.func; > + > + let fn_ptr: unsafe extern "C" > fn($($crate::static_call::ty_underscore_for!($args)),*) -> _ = > + if true { > + ::core::mem::transmute(void_ptr_fn) > + } else { > + // This is dead code, but it influences type inference on > `fn_ptr` so that we > + // transmute the function pointer to the right type. > + $crate::macros::paste! { $crate::bindings:: [<__SCT__ $name > >]; } > + }; > + > + (fn_ptr)($($args),*) > + }}; > +} > + > +/// Statically call a global function. > +/// > +/// # Safety > +/// > +/// This macro will call the provided function. It is up to the caller to > uphold the safety > +/// guarantees of the function. > +/// > +/// # Examples > +/// > +/// ```ignore > +/// fn call_static() { > +/// unsafe { > +/// static_call! { your_static_call() }; > +/// } > +/// } > +/// ``` > +#[macro_export] > +macro_rules! static_call { > + // Forward to the real implementation. Separated like this so that we > don't have to duplicate > + // the documentation. > + ($($args:tt)*) => { $crate::static_call::_static_call! { $($args)* } }; > +} > + > +pub use {_static_call, static_call, ty_underscore_for}; > > -- > 2.45.2.505.gda0bf45e8d-goog >