Skip to content

Commit 18192de

Browse files
committed
rust: generate bindings for helpers
Automatically generate rust bindings for helper functions via bindgen. The corresponding Rust bindings will have their `rust_helper_` prefix removed, so Rust code can call `bindings::foo` regardless whether `foo` is directly exposed or exposed via a helper. When both a directly exposed symbol and a helper exists, the directly exposed symbol will take precedence. Signed-off-by: Gary Guo <[email protected]>
1 parent a8079fc commit 18192de

17 files changed

+90
-168
lines changed

Makefile

+1
Original file line numberDiff line numberDiff line change
@@ -1834,6 +1834,7 @@ rustfmt:
18341834
-o -path $(abs_objtree)/rust/test -prune \
18351835
| grep -Fv $(abs_srctree)/rust/alloc \
18361836
| grep -Fv $(abs_objtree)/rust/test \
1837+
| grep -Fv generated \
18371838
| xargs $(RUSTFMT) $(rustfmt_flags)
18381839

18391840
rustfmtcheck: rustfmt_flags = --check

rust/.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# SPDX-License-Identifier: GPL-2.0
22

33
bindings_generated.rs
4+
bindings_helpers_generated.rs
45
exports_*_generated.h
56
doc/
67
test/

rust/Makefile

+24-7
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ extra-$(CONFIG_RUST) += exports_core_generated.h
55

66
extra-$(CONFIG_RUST) += libmacros.so
77

8-
extra-$(CONFIG_RUST) += bindings_generated.rs
8+
extra-$(CONFIG_RUST) += bindings_generated.rs bindings_helpers_generated.rs
99
obj-$(CONFIG_RUST) += alloc.o kernel.o
1010
extra-$(CONFIG_RUST) += exports_alloc_generated.h exports_kernel_generated.h
1111

@@ -30,7 +30,7 @@ endif
3030

3131
quiet_cmd_rustdoc = RUSTDOC $(if $(rustdoc_host),H, ) $<
3232
cmd_rustdoc = \
33-
RUST_BINDINGS_FILE=$(abspath $(objtree)/rust/bindings_generated.rs) \
33+
OBJTREE=$(abspath $(objtree)) \
3434
$(RUSTDOC) $(if $(rustdoc_host),,$(rustc_cross_flags)) \
3535
$(filter-out -Cpanic=abort, $(filter-out --emit=%, $(rustc_flags))) \
3636
$(rustc_target_flags) -L $(objtree)/rust \
@@ -61,12 +61,13 @@ rustdoc-kernel: private rustc_target_flags = --extern alloc \
6161
--extern build_error \
6262
--extern macros=$(objtree)/rust/libmacros.so
6363
rustdoc-kernel: $(srctree)/rust/kernel/lib.rs rustdoc-macros \
64-
$(objtree)/rust/libmacros.so $(objtree)/rust/bindings_generated.rs FORCE
64+
$(objtree)/rust/libmacros.so $(objtree)/rust/bindings_generated.rs \
65+
$(objtree)/rust/bindings_helpers_generated.rs FORCE
6566
$(call if_changed,rustdoc)
6667

6768
quiet_cmd_rustc_test_library = RUSTC TL $<
6869
cmd_rustc_test_library = \
69-
RUST_BINDINGS_FILE=$(abspath $(objtree)/rust/bindings_generated.rs) \
70+
OBJTREE=$(abspath $(objtree)) \
7071
$(RUSTC) $(filter-out --sysroot=%, $(filter-out -Cpanic=abort, $(filter-out --emit=%, $(rustc_flags)))) \
7172
$(rustc_target_flags) --crate-type $(if $(rustc_test_library_proc),proc-macro,rlib) \
7273
--out-dir $(objtree)/rust/test/ --cfg testlib \
@@ -95,7 +96,7 @@ quiet_cmd_rustdoc_test = RUSTDOC T $<
9596
# so for the moment we skip `-Cpanic=abort`.
9697
quiet_cmd_rustc_test = RUSTC T $<
9798
cmd_rustc_test = \
98-
RUST_BINDINGS_FILE=$(abspath $(objtree)/rust/bindings_generated.rs) \
99+
OBJTREE=$(abspath $(objtree)) \
99100
$(RUSTC) --test $(filter-out --sysroot=%, $(filter-out -Cpanic=abort, $(filter-out --emit=%, $(rustc_flags)))) \
100101
$(rustc_target_flags) --out-dir $(objtree)/rust/test \
101102
--sysroot $(objtree)/rust/test/sysroot \
@@ -216,6 +217,21 @@ $(objtree)/rust/bindings_generated.rs: $(srctree)/rust/kernel/bindings_helper.h
216217
$(srctree)/rust/bindgen_parameters FORCE
217218
$(call if_changed_dep,bindgen)
218219

220+
quiet_cmd_bindgen_helper = BINDGEN $@
221+
cmd_bindgen_helper = \
222+
$(BINDGEN) $< --blacklist-type '.*' --whitelist-var '' \
223+
--whitelist-function 'rust_helper_.*' \
224+
--use-core --with-derive-default --ctypes-prefix c_types \
225+
--no-debug '.*' \
226+
--size_t-is-usize -o $@ -- $(bindgen_c_flags_final) \
227+
-I$(objtree)/rust/ -DMODULE; \
228+
sed -Ei 's/pub fn rust_helper_([a-zA-Z0-9_]*)/\#[link_name="rust_helper_\1"]\n pub fn \1/g' $@
229+
230+
CFLAGS_helpers.o = -I$(objtree)/rust/
231+
232+
$(objtree)/rust/bindings_helpers_generated.rs: $(srctree)/rust/helpers.c FORCE
233+
$(call if_changed_dep,bindgen_helper)
234+
219235
quiet_cmd_exports = EXPORTS $@
220236
cmd_exports = \
221237
$(NM) -p --defined-only $< \
@@ -253,7 +269,7 @@ $(objtree)/rust/libmacros.so: $(srctree)/rust/macros/lib.rs \
253269

254270
quiet_cmd_rustc_library = $(if $(skip_clippy),RUSTC,$(RUSTC_OR_CLIPPY_QUIET)) L $@
255271
cmd_rustc_library = \
256-
RUST_BINDINGS_FILE=$(abspath $(objtree)/rust/bindings_generated.rs) \
272+
OBJTREE=$(abspath $(objtree)) \
257273
$(if $(skip_clippy),$(RUSTC),$(RUSTC_OR_CLIPPY)) \
258274
$(rustc_flags) $(rustc_cross_flags) $(rustc_target_flags) \
259275
--crate-type rlib --out-dir $(objtree)/rust/ -L $(objtree)/rust/ \
@@ -291,7 +307,8 @@ $(objtree)/rust/kernel.o: private rustc_target_flags = --extern alloc \
291307
--extern macros=$(objtree)/rust/libmacros.so
292308
$(objtree)/rust/kernel.o: $(srctree)/rust/kernel/lib.rs $(objtree)/rust/alloc.o \
293309
$(objtree)/rust/build_error.o \
294-
$(objtree)/rust/libmacros.so $(objtree)/rust/bindings_generated.rs FORCE
310+
$(objtree)/rust/libmacros.so $(objtree)/rust/bindings_generated.rs \
311+
$(objtree)/rust/bindings_helpers_generated.rs FORCE
295312
$(call if_changed_dep,rustc_library)
296313

297314
# Targets that need to expand twice

rust/helpers.c

+7-6
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ unsigned long rust_helper_clear_user(void __user *to, unsigned long n)
3131
return clear_user(to, n);
3232
}
3333

34-
void rust_helper_spin_lock_init(spinlock_t *lock, const char *name,
34+
void rust_helper___spin_lock_init(spinlock_t *lock, const char *name,
3535
struct lock_class_key *key)
3636
{
3737
#ifdef CONFIG_DEBUG_SPINLOCK
@@ -40,7 +40,7 @@ void rust_helper_spin_lock_init(spinlock_t *lock, const char *name,
4040
spin_lock_init(lock);
4141
#endif
4242
}
43-
EXPORT_SYMBOL_GPL(rust_helper_spin_lock_init);
43+
EXPORT_SYMBOL_GPL(rust_helper___spin_lock_init);
4444

4545
void rust_helper_spin_lock(spinlock_t *lock)
4646
{
@@ -102,22 +102,23 @@ size_t rust_helper_copy_to_iter(const void *addr, size_t bytes, struct iov_iter
102102
}
103103
EXPORT_SYMBOL_GPL(rust_helper_copy_to_iter);
104104

105-
bool rust_helper_is_err(__force const void *ptr)
105+
bool rust_helper_IS_ERR(__force const void *ptr)
106106
{
107107
return IS_ERR(ptr);
108108
}
109-
EXPORT_SYMBOL_GPL(rust_helper_is_err);
109+
EXPORT_SYMBOL_GPL(rust_helper_IS_ERR);
110110

111-
long rust_helper_ptr_err(__force const void *ptr)
111+
long rust_helper_PTR_ERR(__force const void *ptr)
112112
{
113113
return PTR_ERR(ptr);
114114
}
115-
EXPORT_SYMBOL_GPL(rust_helper_ptr_err);
115+
EXPORT_SYMBOL_GPL(rust_helper_PTR_ERR);
116116

117117
const char *rust_helper_errname(int err)
118118
{
119119
return errname(err);
120120
}
121+
EXPORT_SYMBOL_GPL(rust_helper_errname);
121122

122123
void rust_helper_mutex_lock(struct mutex *lock)
123124
{

rust/kernel/bindings.rs

+21-3
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,37 @@
88
#![cfg_attr(test, allow(deref_nullptr))]
99
#![cfg_attr(test, allow(unaligned_references))]
1010
#![cfg_attr(test, allow(unsafe_op_in_unsafe_fn))]
11-
12-
#[allow(
11+
#![allow(
1312
clippy::all,
1413
non_camel_case_types,
1514
non_upper_case_globals,
1615
non_snake_case,
1716
improper_ctypes,
1817
unsafe_op_in_unsafe_fn
1918
)]
19+
2020
mod bindings_raw {
21+
// Use glob import here to expose all helpers.
22+
// Symbols defined within the module will take precedence to the glob import.
23+
pub use super::bindings_helper::*;
24+
use crate::c_types;
25+
include!(concat!(env!("OBJTREE"), "/rust/bindings_generated.rs"));
26+
}
27+
28+
// When both a directly exposed symbol and a helper exists for the same function,
29+
// the directly exposed symbol is preferred and the helper becomes dead code, so
30+
// ignore the warning here.
31+
#[allow(dead_code)]
32+
mod bindings_helper {
33+
// Import the generated bindings for types.
34+
use super::bindings_raw::*;
2135
use crate::c_types;
22-
include!(env!("RUST_BINDINGS_FILE"));
36+
include!(concat!(
37+
env!("OBJTREE"),
38+
"/rust/bindings_helpers_generated.rs"
39+
));
2340
}
41+
2442
pub use bindings_raw::*;
2543

2644
pub const GFP_KERNEL: gfp_t = BINDINGS_GFP_KERNEL;

rust/kernel/error.rs

+7-18
Original file line numberDiff line numberDiff line change
@@ -98,11 +98,8 @@ impl Error {
9898

9999
impl fmt::Debug for Error {
100100
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
101-
extern "C" {
102-
fn rust_helper_errname(err: c_types::c_int) -> *const c_types::c_char;
103-
}
104101
// SAFETY: FFI call.
105-
let name = unsafe { rust_helper_errname(-self.0) };
102+
let name = unsafe { bindings::errname(-self.0) };
106103

107104
if name.is_null() {
108105
// Print out number if no name can be found.
@@ -199,7 +196,7 @@ where
199196
/// ) -> c_types::c_int {
200197
/// from_kernel_result! {
201198
/// let ptr = devm_alloc(pdev)?;
202-
/// rust_helper_platform_set_drvdata(pdev, ptr);
199+
/// bindings::platform_set_drvdata(pdev, ptr);
203200
/// Ok(0)
204201
/// }
205202
/// }
@@ -243,28 +240,20 @@ macro_rules! from_kernel_result {
243240
// TODO: remove `dead_code` marker once an in-kernel client is available.
244241
#[allow(dead_code)]
245242
pub(crate) fn from_kernel_err_ptr<T>(ptr: *mut T) -> Result<*mut T> {
246-
extern "C" {
247-
#[allow(improper_ctypes)]
248-
fn rust_helper_is_err(ptr: *const c_types::c_void) -> bool;
249-
250-
#[allow(improper_ctypes)]
251-
fn rust_helper_ptr_err(ptr: *const c_types::c_void) -> c_types::c_long;
252-
}
253-
254243
// CAST: casting a pointer to `*const c_types::c_void` is always valid.
255244
let const_ptr: *const c_types::c_void = ptr.cast();
256245
// SAFETY: the FFI function does not deref the pointer.
257-
if unsafe { rust_helper_is_err(const_ptr) } {
246+
if unsafe { bindings::IS_ERR(const_ptr) } {
258247
// SAFETY: the FFI function does not deref the pointer.
259-
let err = unsafe { rust_helper_ptr_err(const_ptr) };
260-
// CAST: if `rust_helper_is_err()` returns `true`,
261-
// then `rust_helper_ptr_err()` is guaranteed to return a
248+
let err = unsafe { bindings::PTR_ERR(const_ptr) };
249+
// CAST: if `IS_ERR()` returns `true`,
250+
// then `PTR_ERR()` is guaranteed to return a
262251
// negative value greater-or-equal to `-bindings::MAX_ERRNO`,
263252
// which always fits in an `i16`, as per the invariant above.
264253
// And an `i16` always fits in an `i32`. So casting `err` to
265254
// an `i32` can never overflow, and is always valid.
266255
//
267-
// SAFETY: `rust_helper_is_err()` ensures `err` is a
256+
// SAFETY: `IS_ERR()` ensures `err` is a
268257
// negative value greater-or-equal to `-bindings::MAX_ERRNO`
269258
return Err(unsafe { Error::from_kernel_errno_unchecked(err as i32) });
270259
}

rust/kernel/iov_iter.rs

+3-17
Original file line numberDiff line numberDiff line change
@@ -5,26 +5,12 @@
55
//! C header: [`include/linux/uio.h`](../../../../include/linux/uio.h)
66
77
use crate::{
8-
bindings, c_types,
8+
bindings,
99
error::Error,
1010
io_buffer::{IoBufferReader, IoBufferWriter},
1111
Result,
1212
};
1313

14-
extern "C" {
15-
fn rust_helper_copy_to_iter(
16-
addr: *const c_types::c_void,
17-
bytes: usize,
18-
i: *mut bindings::iov_iter,
19-
) -> usize;
20-
21-
fn rust_helper_copy_from_iter(
22-
addr: *mut c_types::c_void,
23-
bytes: usize,
24-
i: *mut bindings::iov_iter,
25-
) -> usize;
26-
}
27-
2814
/// Wraps the kernel's `struct iov_iter`.
2915
///
3016
/// # Invariants
@@ -70,7 +56,7 @@ impl IoBufferWriter for IovIter {
7056
}
7157

7258
unsafe fn write_raw(&mut self, data: *const u8, len: usize) -> Result {
73-
let res = unsafe { rust_helper_copy_to_iter(data as _, len, self.ptr) };
59+
let res = unsafe { bindings::copy_to_iter(data as _, len, self.ptr) };
7460
if res != len {
7561
Err(Error::EFAULT)
7662
} else {
@@ -85,7 +71,7 @@ impl IoBufferReader for IovIter {
8571
}
8672

8773
unsafe fn read_raw(&mut self, out: *mut u8, len: usize) -> Result {
88-
let res = unsafe { rust_helper_copy_from_iter(out as _, len, self.ptr) };
74+
let res = unsafe { bindings::copy_from_iter(out as _, len, self.ptr) };
8975
if res != len {
9076
Err(Error::EFAULT)
9177
} else {

rust/kernel/pages.rs

+3-17
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,6 @@ use crate::{
1010
};
1111
use core::{marker::PhantomData, ptr};
1212

13-
extern "C" {
14-
#[allow(improper_ctypes)]
15-
fn rust_helper_alloc_pages(
16-
gfp_mask: bindings::gfp_t,
17-
order: c_types::c_uint,
18-
) -> *mut bindings::page;
19-
20-
#[allow(improper_ctypes)]
21-
fn rust_helper_kmap(page: *mut bindings::page) -> *mut c_types::c_void;
22-
23-
#[allow(improper_ctypes)]
24-
fn rust_helper_kunmap(page: *mut bindings::page);
25-
}
26-
2713
/// A set of physical pages.
2814
///
2915
/// `Pages` holds a reference to a set of pages of order `ORDER`. Having the order as a generic
@@ -42,7 +28,7 @@ impl<const ORDER: u32> Pages<ORDER> {
4228
// TODO: Consider whether we want to allow callers to specify flags.
4329
// SAFETY: This only allocates pages. We check that it succeeds in the next statement.
4430
let pages = unsafe {
45-
rust_helper_alloc_pages(
31+
bindings::alloc_pages(
4632
bindings::GFP_KERNEL | bindings::__GFP_ZERO | bindings::__GFP_HIGHMEM,
4733
ORDER,
4834
)
@@ -141,7 +127,7 @@ impl<const ORDER: u32> Pages<ORDER> {
141127
let page = unsafe { self.pages.add(index) };
142128

143129
// SAFETY: `page` is valid based on the checks above.
144-
let ptr = unsafe { rust_helper_kmap(page) };
130+
let ptr = unsafe { bindings::kmap(page) };
145131
if ptr.is_null() {
146132
return None;
147133
}
@@ -171,6 +157,6 @@ impl Drop for PageMapping<'_> {
171157
fn drop(&mut self) {
172158
// SAFETY: An instance of `PageMapping` is created only when `kmap` succeeded for the given
173159
// page, so it is safe to unmap it here.
174-
unsafe { rust_helper_kunmap(self.page) };
160+
unsafe { bindings::kunmap(self.page) };
175161
}
176162
}

rust/kernel/platdev.rs

+2-15
Original file line numberDiff line numberDiff line change
@@ -29,19 +29,6 @@ pub struct Registration {
2929
// (it is fine for multiple threads to have a shared reference to it).
3030
unsafe impl Sync for Registration {}
3131

32-
extern "C" {
33-
#[allow(improper_ctypes)]
34-
fn rust_helper_platform_get_drvdata(
35-
pdev: *const bindings::platform_device,
36-
) -> *mut c_types::c_void;
37-
38-
#[allow(improper_ctypes)]
39-
fn rust_helper_platform_set_drvdata(
40-
pdev: *mut bindings::platform_device,
41-
data: *mut c_types::c_void,
42-
);
43-
}
44-
4532
extern "C" fn probe_callback<P: PlatformDriver>(
4633
pdev: *mut bindings::platform_device,
4734
) -> c_types::c_int {
@@ -52,7 +39,7 @@ extern "C" fn probe_callback<P: PlatformDriver>(
5239
let drv_data = drv_data.into_pointer() as *mut c_types::c_void;
5340
// SAFETY: `pdev` is guaranteed to be a valid, non-null pointer.
5441
unsafe {
55-
rust_helper_platform_set_drvdata(pdev, drv_data);
42+
bindings::platform_set_drvdata(pdev, drv_data);
5643
}
5744
Ok(0)
5845
}
@@ -65,7 +52,7 @@ extern "C" fn remove_callback<P: PlatformDriver>(
6552
// SAFETY: `pdev` is guaranteed to be a valid, non-null pointer.
6653
let device_id = unsafe { (*pdev).id };
6754
// SAFETY: `pdev` is guaranteed to be a valid, non-null pointer.
68-
let ptr = unsafe { rust_helper_platform_get_drvdata(pdev) };
55+
let ptr = unsafe { bindings::platform_get_drvdata(pdev) };
6956
// SAFETY:
7057
// - we allocated this pointer using `P::DrvData::into_pointer`,
7158
// so it is safe to turn back into a `P::DrvData`.

rust/kernel/rbtree.rs

+1-9
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,6 @@ use core::{
1616
ptr::{addr_of_mut, NonNull},
1717
};
1818

19-
extern "C" {
20-
fn rust_helper_rb_link_node(
21-
node: *mut bindings::rb_node,
22-
parent: *const bindings::rb_node,
23-
rb_link: *mut *mut bindings::rb_node,
24-
);
25-
}
26-
2719
struct Node<K, V> {
2820
links: bindings::rb_node,
2921
key: K,
@@ -289,7 +281,7 @@ impl<K, V> RBTree<K, V> {
289281
// "forgot" it with `Box::into_raw`.
290282
// SAFETY: All pointers are non-null and valid (`*new_link` is null, but `new_link` is a
291283
// mutable reference).
292-
unsafe { rust_helper_rb_link_node(node_links, parent, new_link) };
284+
unsafe { bindings::rb_link_node(node_links, parent, new_link) };
293285

294286
// SAFETY: All pointers are valid. `node` has just been inserted into the tree.
295287
unsafe { bindings::rb_insert_color(node_links, &mut self.root) };

0 commit comments

Comments
 (0)