Skip to content

Commit 2a840f8

Browse files
committed
rust: generate bindings for helpers
Helper functions are now only compiled if the wrapped function is not made directly available via bindgen. For the compiled helper functions, bindings for them are automatically generated via a second invocation to bindgen, and the corresponding binding will have its `rust_helper_` prefix removed, so Rust code can call `bindings::foo` regardless whether `foo` is directly exposed or exposed via a helper. Details about how this works: * `bindings_generated.rs` is first created via bindgen; * List of functions are extracted from `bindings_generated.rs` and a `rust_helper_foo` macro is generated for each function directly exposed this way; * `helpers.c` can then use C preprocessor to conditionally compile helpers only if they are not directly exposed. * bindgen invokes again to create bindings for `helpers.c`. * bindgen output is then postprocessed to remove the `rust_helper` prefix and add `#[link_name = ""]`. Signed-off-by: Gary Guo <[email protected]>
1 parent bfe9ec6 commit 2a840f8

File tree

13 files changed

+107
-124
lines changed

13 files changed

+107
-124
lines changed

drivers/android/process.rs

+3-7
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,6 @@ use crate::{
3232
// TODO: Review this:
3333
// Lock order: Process::node_refs -> Process::inner -> Thread::inner
3434

35-
extern "C" {
36-
fn rust_helper_current_pid() -> c_types::c_int;
37-
}
38-
3935
pub(crate) struct AllocationInfo {
4036
/// Range within the allocation where we can find the offsets to the object descriptors.
4137
pub(crate) offsets: Range<usize>,
@@ -762,7 +758,7 @@ impl Process {
762758

763759
impl IoctlHandler for Process {
764760
fn write(&self, _file: &File, cmd: u32, reader: &mut UserSlicePtrReader) -> Result<i32> {
765-
let thread = self.get_thread(unsafe { rust_helper_current_pid() })?;
761+
let thread = self.get_thread(unsafe { bindings::current_pid() })?;
766762
match cmd {
767763
bindings::BINDER_SET_MAX_THREADS => self.set_max_threads(reader.read()?),
768764
bindings::BINDER_SET_CONTEXT_MGR => self.set_as_manager(None, &thread)?,
@@ -776,7 +772,7 @@ impl IoctlHandler for Process {
776772
}
777773

778774
fn read_write(&self, file: &File, cmd: u32, data: UserSlicePtr) -> Result<i32> {
779-
let thread = self.get_thread(unsafe { rust_helper_current_pid() })?;
775+
let thread = self.get_thread(unsafe { bindings::current_pid() })?;
780776
match cmd {
781777
bindings::BINDER_WRITE_READ => thread.write_read(data, file.is_blocking())?,
782778
bindings::BINDER_GET_NODE_DEBUG_INFO => self.get_node_debug_info(data)?,
@@ -913,7 +909,7 @@ impl FileOperations for Process {
913909
}
914910

915911
fn poll(&self, file: &File, table: &PollTable) -> Result<u32> {
916-
let thread = self.get_thread(unsafe { rust_helper_current_pid() })?;
912+
let thread = self.get_thread(unsafe { bindings::current_pid() })?;
917913
let (from_proc, mut mask) = thread.poll(file, table);
918914
if mask == 0 && from_proc && !self.inner.lock().work.is_empty() {
919915
mask |= bindings::POLLIN;

rust/.gitignore

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

33
bindings_generated.rs
4+
bindings_generated.h
5+
bindings_helpers_generated.rs
46
exports_*_generated.h
5-
doc/
7+
doc/

rust/Makefile

+25-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

@@ -21,15 +21,14 @@ RUSTDOC = rustdoc
2121

2222
quiet_cmd_rustdoc_host = RUSTDOC $<
2323
cmd_rustdoc_host = \
24-
RUST_BINDINGS_FILE=$(abspath $(objtree)/rust/bindings_generated.rs) \
2524
$(RUSTDOC) $(filter-out --emit=%, $(rustc_flags)) \
2625
$(rustdoc_target_flags) -L $(objtree)/rust/ \
2726
--output $(objtree)/rust/doc --crate-name $(subst rustdoc-,,$@) \
2827
-Fmissing-docs @$(objtree)/include/generated/rustc_cfg $<
2928

3029
quiet_cmd_rustdoc = RUSTDOC $<
3130
cmd_rustdoc = \
32-
RUST_BINDINGS_FILE=$(abspath $(objtree)/rust/bindings_generated.rs) \
31+
OBJTREE=$(abspath $(objtree)) \
3332
$(RUSTDOC) $(rustc_cross_flags) $(filter-out --emit=%, $(rustc_flags)) \
3433
$(rustdoc_target_flags) -L $(objtree)/rust/ \
3534
--output $(objtree)/rust/doc --crate-name $(subst rustdoc-,,$@) \
@@ -49,7 +48,7 @@ rustdoc-kernel: private rustdoc_target_flags = --extern alloc \
4948
--extern build_error \
5049
--extern macros=$(objtree)/rust/libmacros.so
5150
rustdoc-kernel: $(srctree)/rust/kernel/lib.rs rustdoc-macros \
52-
$(objtree)/rust/libmacros.so $(objtree)/rust/bindings_generated.rs FORCE
51+
$(objtree)/rust/libmacros.so $(objtree)/rust/bindings_generated.rs $(objtree)/rust/bindings_generated2.rs FORCE
5352
$(call if_changed,rustdoc)
5453

5554
ifdef CONFIG_CC_IS_CLANG
@@ -92,12 +91,30 @@ quiet_cmd_bindgen = BINDGEN $@
9291
$(BINDGEN) $< $(shell grep -v '^\#\|^$$' $(srctree)/rust/bindgen_parameters) \
9392
--use-core --with-derive-default --ctypes-prefix c_types \
9493
--no-debug '.*' \
95-
--size_t-is-usize -o $@ -- $(bindgen_c_flags_final) -DMODULE
94+
--size_t-is-usize -o $@ -- $(bindgen_c_flags_final) -DMODULE; \
95+
sed -En 's/^.*pub fn ([a-zA-Z0-9_]*).*$$/\#define rust_helper_\1/pg' $@ \
96+
> $(patsubst %.rs,%.h,$@)
9697

9798
$(objtree)/rust/bindings_generated.rs: $(srctree)/rust/kernel/bindings_helper.h \
9899
$(srctree)/rust/bindgen_parameters FORCE
99100
$(call if_changed_dep,bindgen)
100101

102+
quiet_cmd_bindgen_helper = BINDGEN $@
103+
cmd_bindgen_helper = \
104+
$(BINDGEN) $< --blacklist-type '.*' --whitelist-var '' \
105+
--whitelist-function 'rust_helper_.*' \
106+
--use-core --with-derive-default --ctypes-prefix c_types \
107+
--no-debug '.*' \
108+
--size_t-is-usize -o $@ -- $(bindgen_c_flags_final) \
109+
-I$(objtree)/rust/ -DMODULE; \
110+
sed -Ei 's/pub fn rust_helper_([a-zA-Z0-9_]*)/\#[link_name="rust_helper_\1"]\n pub fn \1/g' $@
111+
112+
CFLAGS_helpers.o = -I$(objtree)/rust/
113+
114+
$(objtree)/rust/bindings_helpers_generated.rs: $(srctree)/rust/helpers.c \
115+
$(objtree)/rust/bindings_generated.rs FORCE
116+
$(call if_changed_dep,bindgen_helper)
117+
101118
quiet_cmd_exports = EXPORTS $@
102119
cmd_exports = \
103120
$(NM) -p --defined-only $< \
@@ -135,7 +152,7 @@ $(objtree)/rust/libmacros.so: $(srctree)/rust/macros/lib.rs \
135152

136153
quiet_cmd_rustc_library = $(if $(skip_clippy),RUSTC,$(RUSTC_OR_CLIPPY_QUIET)) L $@
137154
cmd_rustc_library = \
138-
RUST_BINDINGS_FILE=$(abspath $(objtree)/rust/bindings_generated.rs) \
155+
OBJTREE=$(abspath $(objtree)) \
139156
$(if $(skip_clippy),$(RUSTC),$(RUSTC_OR_CLIPPY)) \
140157
$(rustc_flags) $(rustc_cross_flags) $(rustc_target_flags) \
141158
--crate-type rlib --out-dir $(objtree)/rust/ -L $(objtree)/rust/ \
@@ -166,7 +183,8 @@ $(objtree)/rust/kernel.o: private rustc_target_flags = --extern alloc \
166183
--extern macros=$(objtree)/rust/libmacros.so
167184
$(objtree)/rust/kernel.o: $(srctree)/rust/kernel/lib.rs $(objtree)/rust/alloc.o \
168185
$(objtree)/rust/build_error.o \
169-
$(objtree)/rust/libmacros.so $(objtree)/rust/bindings_generated.rs FORCE
186+
$(objtree)/rust/libmacros.so $(objtree)/rust/bindings_generated.rs \
187+
$(objtree)/rust/bindings_helpers_generated.rs FORCE
170188
$(call if_changed_dep,rustc_library)
171189

172190
# Targets that need to expand twice

rust/helpers.c

+43-8
Original file line numberDiff line numberDiff line change
@@ -2,34 +2,39 @@
22

33
#include <linux/bug.h>
44
#include <linux/build_bug.h>
5-
#include <linux/uaccess.h>
6-
#include <linux/sched/signal.h>
7-
#include <linux/gfp.h>
8-
#include <linux/highmem.h>
9-
#include <linux/uio.h>
10-
#include <linux/errname.h>
5+
#include "kernel/bindings_helper.h"
6+
#include "bindings_generated.h"
117

8+
#ifndef rust_helper_BUG
129
void rust_helper_BUG(void)
1310
{
1411
BUG();
1512
}
13+
#endif
1614

15+
#ifndef rust_helper_copy_from_user
1716
unsigned long rust_helper_copy_from_user(void *to, const void __user *from, unsigned long n)
1817
{
1918
return copy_from_user(to, from, n);
2019
}
20+
#endif
2121

22+
#ifndef rust_helper_copy_to_user
2223
unsigned long rust_helper_copy_to_user(void __user *to, const void *from, unsigned long n)
2324
{
2425
return copy_to_user(to, from, n);
2526
}
27+
#endif
2628

29+
#ifndef rust_helper_clear_user
2730
unsigned long rust_helper_clear_user(void __user *to, unsigned long n)
2831
{
2932
return clear_user(to, n);
3033
}
34+
#endif
3135

32-
void rust_helper_spin_lock_init(spinlock_t *lock, const char *name,
36+
#ifndef rust_helper___spin_lock_init
37+
void rust_helper___spin_lock_init(spinlock_t *lock, const char *name,
3338
struct lock_class_key *key)
3439
{
3540
#ifdef CONFIG_DEBUG_SPINLOCK
@@ -38,90 +43,120 @@ void rust_helper_spin_lock_init(spinlock_t *lock, const char *name,
3843
spin_lock_init(lock);
3944
#endif
4045
}
41-
EXPORT_SYMBOL_GPL(rust_helper_spin_lock_init);
46+
EXPORT_SYMBOL_GPL(rust_helper___spin_lock_init);
47+
#endif
4248

49+
#ifndef rust_helper_spin_lock
4350
void rust_helper_spin_lock(spinlock_t *lock)
4451
{
4552
spin_lock(lock);
4653
}
4754
EXPORT_SYMBOL_GPL(rust_helper_spin_lock);
55+
#endif
4856

57+
#ifndef rust_helper_spin_unlock
4958
void rust_helper_spin_unlock(spinlock_t *lock)
5059
{
5160
spin_unlock(lock);
5261
}
5362
EXPORT_SYMBOL_GPL(rust_helper_spin_unlock);
63+
#endif
5464

65+
#ifndef rust_helper_init_wait
5566
void rust_helper_init_wait(struct wait_queue_entry *wq_entry)
5667
{
5768
init_wait(wq_entry);
5869
}
5970
EXPORT_SYMBOL_GPL(rust_helper_init_wait);
71+
#endif
6072

73+
#ifndef rust_helper_current_pid
6174
int rust_helper_current_pid(void)
6275
{
6376
return current->pid;
6477
}
6578
EXPORT_SYMBOL_GPL(rust_helper_current_pid);
79+
#endif
6680

81+
#ifndef rust_helper_signal_pending
6782
int rust_helper_signal_pending(void)
6883
{
6984
return signal_pending(current);
7085
}
7186
EXPORT_SYMBOL_GPL(rust_helper_signal_pending);
87+
#endif
7288

89+
#ifndef rust_helper_alloc_pages
7390
struct page *rust_helper_alloc_pages(gfp_t gfp_mask, unsigned int order)
7491
{
7592
return alloc_pages(gfp_mask, order);
7693
}
7794
EXPORT_SYMBOL_GPL(rust_helper_alloc_pages);
95+
#endif
7896

97+
#ifndef rust_helper_kamp
7998
void *rust_helper_kmap(struct page *page)
8099
{
81100
return kmap(page);
82101
}
83102
EXPORT_SYMBOL_GPL(rust_helper_kmap);
103+
#endif
84104

105+
#ifndef rust_helper_kunmap
85106
void rust_helper_kunmap(struct page *page)
86107
{
87108
return kunmap(page);
88109
}
89110
EXPORT_SYMBOL_GPL(rust_helper_kunmap);
111+
#endif
90112

113+
#ifndef rust_helper_cond_resched
91114
int rust_helper_cond_resched(void)
92115
{
93116
return cond_resched();
94117
}
95118
EXPORT_SYMBOL_GPL(rust_helper_cond_resched);
119+
#endif
96120

121+
#ifndef rust_helper_copy_from_iter
97122
size_t rust_helper_copy_from_iter(void *addr, size_t bytes, struct iov_iter *i)
98123
{
99124
return copy_from_iter(addr, bytes, i);
100125
}
101126
EXPORT_SYMBOL_GPL(rust_helper_copy_from_iter);
127+
#endif
102128

129+
#ifndef rust_helper_copy_to_iter
103130
size_t rust_helper_copy_to_iter(const void *addr, size_t bytes, struct iov_iter *i)
104131
{
105132
return copy_to_iter(addr, bytes, i);
106133
}
107134
EXPORT_SYMBOL_GPL(rust_helper_copy_to_iter);
135+
#endif
108136

137+
#ifndef rust_helper_is_err
109138
bool rust_helper_is_err(__force const void *ptr)
110139
{
111140
return IS_ERR(ptr);
112141
}
113142
EXPORT_SYMBOL_GPL(rust_helper_is_err);
143+
#endif
114144

145+
#ifndef rust_helper_ptr_err
115146
long rust_helper_ptr_err(__force const void *ptr)
116147
{
117148
return PTR_ERR(ptr);
118149
}
119150
EXPORT_SYMBOL_GPL(rust_helper_ptr_err);
151+
#endif
120152

153+
#ifndef rust_helper_errname
121154
const char *rust_helper_errname(int err)
122155
{
123156
return errname(err);
124157
}
158+
EXPORT_SYMBOL_GPL(rust_helper_errname);
159+
#endif
125160

126161
/* We use bindgen's --size_t-is-usize option to bind the C size_t type
127162
* as the Rust usize type, so we can use it in contexts where Rust

rust/kernel/bindings.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,11 @@
1414
)]
1515
mod bindings_raw {
1616
use crate::c_types;
17-
include!(env!("RUST_BINDINGS_FILE"));
17+
include!(concat!(env!("OBJTREE"), "/rust/bindings_generated.rs"));
18+
include!(concat!(
19+
env!("OBJTREE"),
20+
"/rust/bindings_helpers_generated.rs"
21+
));
1822
}
1923
pub use bindings_raw::*;
2024

rust/kernel/bindings_helper.h

+3
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@
33
#include <linux/cdev.h>
44
#include <linux/errname.h>
55
#include <linux/fs.h>
6+
#include <linux/gfp.h>
7+
#include <linux/highmem.h>
68
#include <linux/module.h>
79
#include <linux/random.h>
10+
#include <linux/sched/signal.h>
811
#include <linux/slab.h>
912
#include <linux/sysctl.h>
1013
#include <linux/uaccess.h>

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.
@@ -196,7 +193,7 @@ where
196193
/// ) -> c_types::c_int {
197194
/// from_kernel_result! {
198195
/// let ptr = devm_alloc(pdev)?;
199-
/// rust_helper_platform_set_drvdata(pdev, ptr);
196+
/// bindings::platform_set_drvdata(pdev, ptr);
200197
/// Ok(0)
201198
/// }
202199
/// }
@@ -236,28 +233,20 @@ macro_rules! from_kernel_result {
236233
// TODO: remove `dead_code` marker once an in-kernel client is available.
237234
#[allow(dead_code)]
238235
pub(crate) fn from_kernel_err_ptr<T>(ptr: *mut T) -> Result<*mut T> {
239-
extern "C" {
240-
#[allow(improper_ctypes)]
241-
fn rust_helper_is_err(ptr: *const c_types::c_void) -> bool;
242-
243-
#[allow(improper_ctypes)]
244-
fn rust_helper_ptr_err(ptr: *const c_types::c_void) -> c_types::c_long;
245-
}
246-
247236
// CAST: casting a pointer to `*const c_types::c_void` is always valid.
248237
let const_ptr: *const c_types::c_void = ptr.cast();
249238
// SAFETY: the FFI function does not deref the pointer.
250-
if unsafe { rust_helper_is_err(const_ptr) } {
239+
if unsafe { bindings::is_err(const_ptr) } {
251240
// SAFETY: the FFI function does not deref the pointer.
252-
let err = unsafe { rust_helper_ptr_err(const_ptr) };
253-
// CAST: if `rust_helper_is_err()` returns `true`,
254-
// then `rust_helper_ptr_err()` is guaranteed to return a
241+
let err = unsafe { bindings::ptr_err(const_ptr) };
242+
// CAST: if `is_err()` returns `true`,
243+
// then `ptr_err()` is guaranteed to return a
255244
// negative value greater-or-equal to `-bindings::MAX_ERRNO`,
256245
// which always fits in an `i16`, as per the invariant above.
257246
// And an `i16` always fits in an `i32`. So casting `err` to
258247
// an `i32` can never overflow, and is always valid.
259248
//
260-
// SAFETY: `rust_helper_is_err()` ensures `err` is a
249+
// SAFETY: `is_err()` ensures `err` is a
261250
// negative value greater-or-equal to `-bindings::MAX_ERRNO`
262251
return Err(unsafe { Error::from_kernel_errno_unchecked(err as i32) });
263252
}

0 commit comments

Comments
 (0)