From fa5cb0bba6347a016016cb2045213e20958d999f Mon Sep 17 00:00:00 2001 From: Frances Wingerter Date: Thu, 9 Jan 2025 13:36:04 -0500 Subject: [PATCH] add Rust for Linux material --- src/SUMMARY.md | 32 +++++++ src/rust-for-linux/basic-requirements.md | 53 ++++++++++++ src/rust-for-linux/bindgen-mapping.png | Bin 0 -> 56420 bytes src/rust-for-linux/bindings-interfaces.md | 71 ++++++++++++++++ src/rust-for-linux/bloat.md | 20 +++++ src/rust-for-linux/complications.md | 39 +++++++++ src/rust-for-linux/complications/async.md | 35 ++++++++ src/rust-for-linux/complications/code-size.md | 48 +++++++++++ .../complications/fallible-allocation.md | 57 +++++++++++++ .../complications/kernel-doc.md | 23 +++++ .../complications/memory-models.md | 54 ++++++++++++ .../complications/mitigations.md | 22 +++++ src/rust-for-linux/complications/pin.md | 80 ++++++++++++++++++ src/rust-for-linux/complications/safety.md | 49 +++++++++++ .../complications/separate-compilation.md | 46 ++++++++++ src/rust-for-linux/complications/sleeping.md | 43 ++++++++++ src/rust-for-linux/hands-on.md | 7 ++ src/rust-for-linux/kernel-module.md | 49 +++++++++++ src/rust-for-linux/macros.md | 53 ++++++++++++ src/rust-for-linux/modules.md | 23 +++++ src/rust-for-linux/modules/module-macro.md | 22 +++++ src/rust-for-linux/modules/parameters.md | 13 +++ .../modules/setup-and-teardown.md | 29 +++++++ src/rust-for-linux/next-steps.md | 12 +++ src/rust-for-linux/rust-analyzer.md | 25 ++++++ src/rust-for-linux/rust-for-linux.md | 35 ++++++++ src/rust-for-linux/types.md | 19 +++++ src/rust-for-linux/using-abstractions.md | 11 +++ src/rust-for-linux/welcome.md | 25 ++++++ 29 files changed, 995 insertions(+) create mode 100644 src/rust-for-linux/basic-requirements.md create mode 100644 src/rust-for-linux/bindgen-mapping.png create mode 100644 src/rust-for-linux/bindings-interfaces.md create mode 100644 src/rust-for-linux/bloat.md create mode 100644 src/rust-for-linux/complications.md create mode 100644 src/rust-for-linux/complications/async.md create mode 100644 src/rust-for-linux/complications/code-size.md create mode 100644 src/rust-for-linux/complications/fallible-allocation.md create mode 100644 src/rust-for-linux/complications/kernel-doc.md create mode 100644 src/rust-for-linux/complications/memory-models.md create mode 100644 src/rust-for-linux/complications/mitigations.md create mode 100644 src/rust-for-linux/complications/pin.md create mode 100644 src/rust-for-linux/complications/safety.md create mode 100644 src/rust-for-linux/complications/separate-compilation.md create mode 100644 src/rust-for-linux/complications/sleeping.md create mode 100644 src/rust-for-linux/hands-on.md create mode 100644 src/rust-for-linux/kernel-module.md create mode 100644 src/rust-for-linux/macros.md create mode 100644 src/rust-for-linux/modules.md create mode 100644 src/rust-for-linux/modules/module-macro.md create mode 100644 src/rust-for-linux/modules/parameters.md create mode 100644 src/rust-for-linux/modules/setup-and-teardown.md create mode 100644 src/rust-for-linux/next-steps.md create mode 100644 src/rust-for-linux/rust-analyzer.md create mode 100644 src/rust-for-linux/rust-for-linux.md create mode 100644 src/rust-for-linux/types.md create mode 100644 src/rust-for-linux/using-abstractions.md create mode 100644 src/rust-for-linux/welcome.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index ebf5779e92dc..8bc6936d32b4 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -407,6 +407,38 @@ - [Broadcast Chat Application](concurrency/async-exercises/chat-app.md) - [Solutions](concurrency/async-exercises/solutions.md) +# Rust for Linux + +--- + +- [Welcome](rust-for-linux/welcome.md) +- [Interoperation Requirements](rust-for-linux/basic-requirements.md) + - [Building Kernel Modules](rust-for-linux/modules.md) + - [Type Mapping](rust-for-linux/types.md) + - [Bindings and Safe Interfaces](rust-for-linux/bindings-interfaces.md) + - [Avoiding Bloat](rust-for-linux/bloat.md) +- [Hands-on With Kernel Rust](rust-for-linux/hands-on.md) + - [Rust for Linux](rust-for-linux/rust-for-linux.md) + - [`rust-analyzer` Setup](rust-for-linux/rust-analyzer.md) + - [Macros](rust-for-linux/macros.md) + - [A Rust Kernel Module](rust-for-linux/kernel-module.md) + - [The `module!` Macro](rust-for-linux/modules/module-macro.md) + - [Module Setup and Teardown](rust-for-linux/modules/setup-and-teardown.md) + - [Module Parameters](rust-for-linux/modules/parameters.md) + - [Using Abstractions](rust-for-linux/using-abstractions.md) +- [Complications and Conflicts](rust-for-linux/complications.md) + - [`Pin` and Self-Reference](rust-for-linux/complications/pin.md) + - [The Kernel Rust Safety Model](rust-for-linux/complications/safety.md) + - [Atomic/Task Contexts and Sleep](rust-for-linux/complications/sleeping.md) + - [Memory Models](rust-for-linux/complications/memory-models.md) + - [Separate Compilation and Linking](rust-for-linux/complications/separate-compilation.md) + - [Fallible Allocation](rust-for-linux/complications/fallible-allocation.md) + - [Code Size](rust-for-linux/complications/code-size.md) + - [Documentation](rust-for-linux/complications/kernel-doc.md) + - [Security Mitigations](rust-for-linux/complications/mitigations.md) + - [Async](rust-for-linux/complications/async.md) +- [Next Steps](rust-for-linux/next-steps.md) + # Final Words --- diff --git a/src/rust-for-linux/basic-requirements.md b/src/rust-for-linux/basic-requirements.md new file mode 100644 index 000000000000..e8b349d283cb --- /dev/null +++ b/src/rust-for-linux/basic-requirements.md @@ -0,0 +1,53 @@ +# Interoperation Requirements + +To use Rust code in Linux, we can start by comparing this situation with C/Rust +interop in userspace. + +## Building + +In userspace, the most common setup is to use Cargo to compile our Rust and +later integrate into a C build system if needed. +Meanwhile, the Linux Kernel compiles its C code with its custom Kbuild build +system. +In Rust for Linux, the kernel build system invokes the Rust compiler directly, +without Cargo. + +## No `libstd` + +Unlike typical usage of Rust in userspace, which makes use of the rust standard +library through the `std` crate, Rust in the kernel does not run atop an +operating system, so kernel Rust will have to eschew the standard library. + +## Module Support + +Much code in the kernel is compiled into kernel modules rather than as part of +the core kernel. +To write kernel modules in Rust we'll need to be able to match the ABI of kernel +modules. + +## Safe Wrappers + +To reap the benefits of Rust, we want to be able to write as much code as +possible in safe Rust. +This means that we want safe wrappers for as much kernel functionality as +possible. + +## Mapping Types + +When writing these wrappers, we'll need to refer to the data types of values +passed to and from existing kernel functions in C. +Unlike userspace C, the kernel uses its own set of primitive types rather than +those provided by the C standard. +We'll have to map back and forth between those kernel types and compatible Rust +ones when doing foreign calls. + +## Keeping the Kernel Lean + +Finally, even the core Rust library assumes a basic level of functionality that +includes some costly operations (e.g. unicode processing) for which the kernel +does not want to pay implementation costs. +To use Rust in the kernel we'll need a way to disable this functionality. + +# Outline + +{{%segment outline}} diff --git a/src/rust-for-linux/bindgen-mapping.png b/src/rust-for-linux/bindgen-mapping.png new file mode 100644 index 0000000000000000000000000000000000000000..9f5eb1736981ea038e323e935b53ea649c68270a GIT binary patch literal 56420 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

6j{@ko?` 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 raSWXZ`ic1OV4Mh`k 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 literal 0 HcmV?d00001 diff --git a/src/rust-for-linux/bindings-interfaces.md b/src/rust-for-linux/bindings-interfaces.md new file mode 100644 index 000000000000..43c70f280213 --- /dev/null +++ b/src/rust-for-linux/bindings-interfaces.md @@ -0,0 +1,71 @@ +--- +minutes: 18 +--- + +# Bindings and Safe Interfaces + +`bindgen` is used to generate low-level, unsafe bindings for C interfaces. + +But to reap the benefits of Rust, we want to use safe, foolproof interfaces to unsafe functionality. + +Subsystems are expected to implement safe interfaces on top of the low-level generated bindings. +These safe interfaces are exposed as top-level modules within the [`kernel` crate](https://rust.docs.kernel.org/kernel/). +The top-level `bindings` module holds the unsafe `bindgen`-generated bindings, +which are generated from the C headers included by `rust/bindings/bindings_helper.h`. + +In Rust for Linux, unsafe `bindgen`-generated bindings should not be used outside the `kernel` crate. +Drivers and other subsystems will make use of the safe abstractions from this crate. + +Only a subset of Linux subsystems currently have such abstractions. + +It's worth browsing the [list of modules](https://rust.docs.kernel.org/kernel/#modules) +exposed by the `kernel` crate to see what exists currently. +Many of these subsystems have only partial bindings based on the needs of consumers so far. + +## Adding a Module + +To add a module for some subsystem, first its header must be added to `bindings_helper.h`. +It may be necessary to write some custom code to wrap macros or `inline` functions +that are not automatically handled by `bindgen`; this code lives in the `rust/helpers/` directory. + +Then we need to write a safe abstraction using these bindings and exposing them to the rest of kernel Rust. + +Some commits from work-in-progress bindings and abstractions +can provide an idea of what it looks like to expose new kernel functionality: + +- GPIO Consumer: [fecb4bd73f06bb2cac8e16aca7ef0e2f1b6acb50](https://github.com/Fabo/linux/commit/fecb4bd73f06bb2cac8e16aca7ef0e2f1b6acb50) +- Regmap: [ec0b740ac5ab299e4c86011a0002919e5bbe5c2d](https://github.com/Fabo/linux/commit/ec0b740ac5ab299e4c86011a0002919e5bbe5c2d) +- I2C: [70ed30fcdf8ec62fa91485c3c0a161a9d0194668](https://github.com/Fabo/linux/commit/70ed30fcdf8ec62fa91485c3c0a161a9d0194668) + +## Guidelines for Abstractions + +Abstractions may not be perfectly safe, but should try to be as safe as possible. +Unsafe functionality exposed should have its safety conditions documented +so that users have guidance on how to use the functionality and justify such use. + +Abstractions should also attempt to present relatively idiomatic Rust in their interfaces: +- Follow Rust naming/capitalization conventions while remaining unsurprising to kernel developers. +- Use RAII instead of manual resource management where possible. +- Avoid raw pointers to bound kernel objects in favor of safer, more limited interfaces. + + When exposing types from generated bindings, code should make use of the + [`Opaque`](https://rust.docs.kernel.org/kernel/types/struct.Opaque.html) type + along with native Rust references and the + [`ARef`](https://rust.docs.kernel.org/kernel/types/struct.ARef.html) type for types that are inherently reference-counted. + This type links types' built-in reference count operations to the `Clone` and `Drop` traits. + +## Submitting the cyclic dependency + +We already know that drivers should not use unsafe bindings directly. +But subsystem maintainers may balk if they see patches submitted that add Rust abstractions without motivation or consumers. +But drivers and subsystem abstractions may have to be submitted separately to different maintainers +due to the distributed nature of Linux development. + +So how should a developer submit a driver that requires bindings/abstractions for a subsystem not yet exposed to Rust? + +There are two main approaches[^1]: + +1. Submit the driver as an RFC before submitting the abstractions it relies upon while referencing the RFC as a potential consumer. +2. Submit a stub driver and fill out non-stub functionality as subsystem abstractions land. + +[^1]: diff --git a/src/rust-for-linux/bloat.md b/src/rust-for-linux/bloat.md new file mode 100644 index 000000000000..b94a1ff0d06f --- /dev/null +++ b/src/rust-for-linux/bloat.md @@ -0,0 +1,20 @@ +--- +minutes: 5 +--- + +# Avoiding Bloat + +Rust for Linux makes use of `libcore` to avoid reimplementing all functionality of the Rust standard library. +But even `libcore` has some functionality built-in that is not portable to all targets the kernel +would like to support or that is not necessary for the kernel while occupying valuable code space. + +This includes[^1]: + +- Support for math with 128-bit integers +- String formatting for floating-point numbers +- Unicode support for strings + +Work is ongoing to make these features optional. +In the meantime, the `libcore` used by Rust for Linux is larger and less portable than it could be. + +[^1]: diff --git a/src/rust-for-linux/complications.md b/src/rust-for-linux/complications.md new file mode 100644 index 000000000000..b38b0cc2d56a --- /dev/null +++ b/src/rust-for-linux/complications.md @@ -0,0 +1,39 @@ +--- +minutes: 5 +--- + +# Complications and Conflicts + +{{%segment outline}} + +There are a number of subtleties and unresolved conflicts between the Rust paradigm and the kernel one. +These must be resolved to ship Rust code in the kernel. + +Some issues are deeper problems that require additional research and development +before Rust for Linux is ready for the prime-time; +others merely require some additional learning and attention +on behalf of aspiring Rust for Linux developers. + +## + +Resolving these conflicts involves changes on both sides of the collaboration. +On the Rust side, new features land first in the Nightly edition of the compiler +before being stabilized. + +To avoid waiting for stabilization, the kernel uses an +[escape hatch](https://rustc-dev-guide.rust-lang.org/building/bootstrapping/what-bootstrapping-does.html#complications-of-bootstrapping) +to access unstable features even in stable releases of the compiler. +This assists in the goal of eventually deploying Rust for Linux in Linux +distributions that ship only a stable version of the Rust toolchain. + +Nonetheless, being able to build Rust for Linux using only stable Rust features +is a significant goal; +the issues blocking this are tracked specifically by both the Rust for Linux +project[^1] and the Rust developers themselves[^2]. + +In the next slides we'll explore the most significant sources of friction between +Rust and Linux kernel development to be aware of challenges we are likely to encounter +when trying to implement kernel functionality in Rust. + +[^1]: +[^2]: diff --git a/src/rust-for-linux/complications/async.md b/src/rust-for-linux/complications/async.md new file mode 100644 index 000000000000..0f4043523d6f --- /dev/null +++ b/src/rust-for-linux/complications/async.md @@ -0,0 +1,35 @@ +--- +minutes: 8 +--- + +# Async + +The kernel performs many operations concurrently and involves significant amounts of interaction +between CPU cores and other devices. +For this reason, it would be no surprise to see that async Rust would be a fundamental requirement +for using Rust in the kernel. +But the kernel is central arbitrer of most synchronization and is currently written in regular, synchronous C. + +Rust code making use of `async` mostly exists to write composable code that will run atop event loops, +but the Linux kernel is not really organized as an event loop: +user tasks call directly into the kernel; control flow for interrupts is handled by hardware. + +As such, `async` support is not critical for most kernel programming tasks. +However, it is possible to view some components of the kernel as async executors, +and some work has been done in this direction. +Wedson Almeida Filho implemented both workqueue-based[^1] and single-threaded async executors as proofs of concept. + +There is not a fundamental incompatibility between Rust-for-Linux and Rust `async`, +which is a similar situation to the amenability of `async` to use in embedded Rust programming +(e.g. the Embassy project). + +Nonetheless, no killer application of `async` in Rust for Linux has made it a priority. + +

+ +[^1]: + +An example of an async server using the kernel async executor may be found +[here](https://github.com/Rust-for-Linux/linux/blob/rust/samples/rust/rust_echo_server.rs). + +
diff --git a/src/rust-for-linux/complications/code-size.md b/src/rust-for-linux/complications/code-size.md new file mode 100644 index 000000000000..ac053de4e0aa --- /dev/null +++ b/src/rust-for-linux/complications/code-size.md @@ -0,0 +1,48 @@ +--- +minutes: 10 +--- + +# Code Size + +One pitfall when writing Rust code can be the multiplicative increase in generated machine code when using generics. + +For the Linux kernel, which must be suitable for space-limited embedded environments, +keeping code size low is a significant concern. + +Experiments with Rust in the kernel so far have shown that Rust code can be of similar code size to C, +but may also be larger in some cases[^1]. + +## Assessing Bloat + +Tools exist to help analyze different source code's contribution to the size of compiled code, +such as [`cargo-bloat`](https://github.com/RazrFalcon/cargo-bloat). + +## Shrinking Code Size + +The reasons for code bloat vary and are not generally specific to Linux kernel usage of Rust. +The most common causes for code bloat are excessive use of generics and forced inlining. +In general, generics should be prefered over trait objects when writing abstractions +that are expected to "compile out" or where generating separate code for different types is critical +for performance (e.g. inner loops or arithmetic on values of a generic type). + +In other situations, trait objects should be prefered to allow reusing definitions +without machine-code duplication, which may closer mirror patterns that would be most natural in C. + +When accepting generic parameters that get converted to a concrete type before use, +follow the pattern of defining an inner monomorphic function that can be shared[^2]: + +```rust +pub fn read_to_string>(path: P) -> io::Result { + fn inner(path: &Path) -> io::Result { + let mut file = File::open(path)?; + let size = file.metadata().map(|m| m.len() as usize).ok(); + let mut string = String::with_capacity(size.unwrap_or(0)); + io::default_read_to_string(&mut file, &mut string, size)?; + Ok(string) + } + inner(path.as_ref()) +} +``` + +[^1]: +[^2]: diff --git a/src/rust-for-linux/complications/fallible-allocation.md b/src/rust-for-linux/complications/fallible-allocation.md new file mode 100644 index 000000000000..e227d0eb6193 --- /dev/null +++ b/src/rust-for-linux/complications/fallible-allocation.md @@ -0,0 +1,57 @@ +--- +minutes: 13 +--- + +# Fallible Allocation + +Allocation in Rust is assumed to be infallible: + +```rust +let x = Box::new(5); +``` + +In the Linux kernel, memory allocation is much more complex. + +```C +void * kmalloc(size_t size, int flags) +``` + +`flags` is one of `GFP_KERNEL`, `GFP_NOWAIT`, `GFP_ATOMIC`, etc.[^1] + +The return value must be checked against `NULL` to see whether allocation succeeded. + +In Rust for Linux, rather than using the infallible allocation APIs provided by `liballoc`, +the kernel library has its own allocation interfaces: + +## `KBox` + +```rust +let b = KBox::new(24_u64, GFP_KERNEL)?; +assert_eq!(*b, 24_u64); +``` + +[`KBox::new`](https://rust.docs.kernel.org/kernel/alloc/kbox/struct.Box.html#tymethod.new) +returns a `Result`. +Here we propagate this error with the `?` operator. + +## `KVec` + +Similarly, [`KVec`](https://rust.docs.kernel.org/kernel/alloc/kvec/type.KVec.html) +presents a similar API to the standard `Vec`, but where operations that may allocate +take a flags parameter: + +```rust +let mut v = KVec::new(); +v.push(1, GFP_KERNEL)?; +assert_eq!(&v, &[1]); +``` + +## `FromIterator` + +Because the standard [`FromIterator`](https://doc.rust-lang.org/std/iter/trait.FromIterator.html) trait also involves making new collections +often involving memory allocation, the `.collect()` method on iterators +is not available in Rust for Linux in its original form. +Work is ongoing to design an equivalent API[^2], but for now we do without its convenience. + +[^1]: +[^2]: diff --git a/src/rust-for-linux/complications/kernel-doc.md b/src/rust-for-linux/complications/kernel-doc.md new file mode 100644 index 000000000000..8463f08f5df7 --- /dev/null +++ b/src/rust-for-linux/complications/kernel-doc.md @@ -0,0 +1,23 @@ +--- +minutes: 3 +--- + +# Documentation + +Documentation in Rust for Linux is built with the `rustdoc` tool just like for regular Rust code. + +Running rustdoc on the kernel is done with the `rustdoc` Make target: + +```sh +$ make LLVM=1 rustdoc +``` + +after which generated docs can be viewed by opening `Documentation/output/rust/rustdoc/kernel/index.html`. + +Pre-generated documentation for the current kernel release is available at: + + + +## More information + + diff --git a/src/rust-for-linux/complications/memory-models.md b/src/rust-for-linux/complications/memory-models.md new file mode 100644 index 000000000000..99cae267d35f --- /dev/null +++ b/src/rust-for-linux/complications/memory-models.md @@ -0,0 +1,54 @@ +--- +minutes: 10 +--- + +# Memory Models: LKMM vs. Rust (C11) Memory Model + +Memory models are their own complex topic which we will not cover in depth, +but it's important to understand how they relate to the Rust for Linux project. + +The Linux Kernel and the Rust language itself use different memory models, +which specify what guarantees are made when different threads interact through +shared memory and low-level synchronization primitives. + +- The kernel has its own memory model (Linux Kernel Memory Model or "LKMM"). + + This is because it predates standardized formal memory models for concurrency + and needs high performance for synchronization as used in RCU and elsewhere. +- Rust inherits the semantics promised by LLVM - from the C++11 specification + (and adopted by the C11 spec). + So Rust essentially uses the C11 MM. +- LKMM relies on orderings provided by address, data, and control dependencies. +- The C11 MM does not provide all of these, so it isn't simple to express the + LKMM in terms of the C11 MM. + - LKMM relies on semantics not guaranteed by the C spec but merely by + compiler behavior. + + This means that conforming to the C standard is not sufficient for an + arbitrary compiler to compile a working kernel. + In practice, the kernel is only compiled with GCC or Clang, which both + implement the desired semantics, so this is fine. + +Because Rust atomics and Linux kernel atomics do not necessarily provide +the same guarantees, using them together could have very surprising results. + +Instead, Kernel Rust should probably re-implement corresponding atomics the +same way the kernel does in C[^1]. + + - This should allow Rust for Linux to interoperate with the rest of the + kernel in an understandable way, + but could subtly alter the behavior of other crates that use atomics if + used in the kernel atop kernel atomics. + +
+ +See these links for more background: + +- +- +- +- + +[^1]: + +
diff --git a/src/rust-for-linux/complications/mitigations.md b/src/rust-for-linux/complications/mitigations.md new file mode 100644 index 000000000000..6145db5dffcc --- /dev/null +++ b/src/rust-for-linux/complications/mitigations.md @@ -0,0 +1,22 @@ +--- +minutes: 5 +--- + +# Security Mitigations + +Even though Rust is memory-safe, larger systems using Rust are not necessarily memory-safe. +The kernel is no exception. +The kernel is often compiled with various security mitigations and hardening flags, +and to avoid undermining these (e.g. by providing gadgets or running afoul of CPU errata), +Rust code compiled into the kernel should also be built with the same set of mitigations. + +Many of these mitigations are already supported by the Rust compiler, +which merely needs to expose the same underlying LLVM functionality offered by Clang. + +## Speculative execution (Meltdown/Spectre) mitigations + +Recent CPU side-channel vulnerabilities in particular require changes to compilers' code generation +("retpolines", etc.) in order to prevent userspace access to kernel data. +Support for these code-generation changes is still pending in `rustc`[^1]. + +[^1]: diff --git a/src/rust-for-linux/complications/pin.md b/src/rust-for-linux/complications/pin.md new file mode 100644 index 000000000000..f63ed0a24d98 --- /dev/null +++ b/src/rust-for-linux/complications/pin.md @@ -0,0 +1,80 @@ +--- +minutes: 15 +--- + +# `Pin` and Self-Reference + +The Linux kernel pervasively relies on intrusive data structures and +programming patterns that rely on the stability of objects' addresses. + +In C, these patterns show up in places like `struct list_head` and the `container_of` macro. + +The programming rules for these data structures require being careful about where instances are +allocated and how they are linked into and removed from containing data structures. + +## Moves + +In Rust, however, instances of data types may change their addresses any time they are moved, and +the compiler is relied on to be aware of any outstanding references that would prevent moving them. +The most common pattern for constructing values in Rust even involves a move-- +simply returning the value from a constructor function. + +This paradigm does not work for values that must be constructed "in-place" to avoid moves, +but the C approach of writing into a blob of uninitialized memory until fully initialized is also an anathema in Rust: +it would force us into writing unsafe code any place we wanted to construct an instance of our type. + +## `Pin` + +A similar concern already exists in Rust for compiler-generated types +that internally contain self references; +these can be occur in the state machines generated by the compiler for `async` functions. + +The `Pin` wrapper type exists to wrap an indirection (such as `&mut T` or `Box`) +in such a way that an `&mut T` cannot be created to the underlying `T` +(as this would allow using a function like `mem::swap` that would effectively change its address). + +## Field projection + +`Pin` also has the effect of requiring a choice for each field of the pinned type: +will it be accessed through a `Pin<&mut Field>` or simply through `&mut Field`? +Either may be acceptable, depending on the semantics of the type, but the two options +must not coexist for a single field as that would allow the `Pin<&mut Field>` to be moved +via `mem::swap` on the `&mut Field`. + +The boilerplate for exposing access to each field of a pinned struct ("projecting" the field) +via only one of `Pin<_>` or directly is handled by the `pin-project` crate in userspace Rust. + +Unfortunately, this crate uses procedural macros to parse Rust code +and these in turn have heavy dependencies that the Rust for Linux project does not want to take on. + +Instead, Rust for Linux has its own solution to pinned initialization and pin projection. + +## `pinned-init` + +The solution employed for these concerns in Rust for Linux is the `pinned-init` crate. +Using this crate looks like the following: + +```rust +use kernel::{prelude::*, sync::Mutex, new_mutex}; +#[pin_data] +struct Foo { + #[pin] + a: Mutex, + b: u32, +} + +let foo = pin_init!(Foo { + a <- new_mutex!(42, "Foo::a"), + b: 24, +}); + +// `foo` now is of the type `impl PinInit`. +// We can now use any smart pointer that we like (or just the stack) to actually initialize a Foo: + +let foo: Result>> = Box::pin_init(foo); +``` + +### Further reading + +- +- diff --git a/src/rust-for-linux/complications/safety.md b/src/rust-for-linux/complications/safety.md new file mode 100644 index 000000000000..a81c136721f6 --- /dev/null +++ b/src/rust-for-linux/complications/safety.md @@ -0,0 +1,49 @@ +--- +minutes: 15 +--- + +# The Kernel Rust Safety Model + +## Soundness + +Safety in normal, userspace Rust is already a subtle topic. +The verification boundary for `unsafe` code is not the unsafe block or even the containing function, +but the privacy boundary of the public interface of the containing module. +And the guarantees that unsafe code can rely on depend on a combination of the semantics of +regular Rust along with the behavior of the underlying compiler, operating system, and hardware. + +In kernel Rust, things are even more complicated. +The golden standard for Rust code making use of `unsafe` is that it must be impossible +for any consumer of the code to trigger undefined behavior through safe interfaces. +But there are many parts of the Linux kernel in which we might want to use Rust that cannot be +fully compartmentalized from the rest of the kernel by a safe, water-tight API. + +Many tasks performed by the kernel are only understandable outside the model of C or Rust language semantics: +for example, writing to CPU registers that control paging or DMA may alter the meaning of pointers, +but models of language semantics do not include notions of the underlying architecture's paging or memory-management system. +Tools like miri cannot analyze programs that perform low-level operations like these, +and static analysis tools similarly lack models of their effects. +So we're forced to live with a less thorough notion of safety than we might have in userspace Rust. + +For now, some kernel components will be suitable for writing fully safe Rust interfaces +(perhaps those with limited interactions with the rest of the system, such as GPIOs), +while others can only offer limited safety. + +This is an area where Rust for Linux is pushing the boundaries of +what Rust's paradigm of memory safety can achieve. + +## Limitations of Type and Memory Safety + +Rust's guarantees of memory safety provide a baseline that can raise our confidence in Rust code +head and shoulders above the status quo writing other low-level languages. +But some desirable properties are difficult or impossible to guarantee through Rust's type system. + +For example, because variables can always be dropped, it's difficult to guarantee liveness properties. + +Similarly, because Rust type- and borrow-checking are local analyses, +they cannot be used to ensure global properties like lock ordering. + +Other tools can perform useful static analyses for Rust code +similar to those that might be performed with standalone C static analysis packages or gcc compiler plugins. +[`Clippy`](https://doc.rust-lang.org/clippy/usage.html) is the most common static analysis tool for Rust code, +but for kernel-specific analyses the [`klint`](https://github.com/Rust-for-Linux/klint) tool also exists. diff --git a/src/rust-for-linux/complications/separate-compilation.md b/src/rust-for-linux/complications/separate-compilation.md new file mode 100644 index 000000000000..f9a2356518b8 --- /dev/null +++ b/src/rust-for-linux/complications/separate-compilation.md @@ -0,0 +1,46 @@ +--- +minutes: 7 +--- + +# Separate Compilation and Linking + +One hiccup integrating Rust into the kernel compilation process is that C is +designed for full separate compilation, +where each source file can be compiled into an object file, +and then these object files are linked into a single loadable archive by the C toolchain's linker. +Rust, however, expects to compile its programs at the granularity of individual crates +and control the linking process. + +In C, the compiler is not responsible for safety, +so the correctness of linking C built with different flags or compilers is left up to the user. +But compiled Rust code has no stable ABI, and so the compiler must be careful not to link together +two libraries compiled with different versions of the Rust compiler, or with different code-generation flags. + +## Target modifiers + +In cases where two crates are linked together, the Rust compiler will attempt to verify that they +have been compiled by the same version of the compiler to ensure that no ABI incompatibility will +undermine the memory safety of their composition. + +However, if one crate was compiled with modifications to its effective ABI relative to the other +(such as forbidding usage of a register, like the `-ffixed-x18` flag does), +then it may not be valid to conclude that the resulting program will behave as intended. + +The Rust compiler currently avoids this situation primarily +by treating each compiler configuration as an entirely separate target; +crates compiled for different targets may not be linked together. +But defining a fully custom target when running the compiler is a feature +only exposed by the unstable nightly version of the compiler, +which Rust for Linux does not want to commit to doing indefinitely. + +The way out is a proposal[^1] to create "target modifiers", +a stable way of specifying variants of standard targets at compile-time. +Compiled crates will be stamped with the target variant +so that the Rust compiler can ensure the target modifiers match at link-time, +but users will not be required to create an entirely new compilation target. + +
+ +[^1]: + +
diff --git a/src/rust-for-linux/complications/sleeping.md b/src/rust-for-linux/complications/sleeping.md new file mode 100644 index 000000000000..28d26d478d50 --- /dev/null +++ b/src/rust-for-linux/complications/sleeping.md @@ -0,0 +1,43 @@ +--- +minutes: 10 +--- + +# Atomic/Task Contexts and Sleep + +One of the safety conditions that the Rust type system does not help us establish is freedom from deadlocks. +In the Linux kernel, a related concern is only sleeping in contexts where doing so is allowed. +In particular, code executing in a task context may sleep, but code executing in an atomic context +(for example, within an interrupt handlers, while holding a spinlock, or in an RCU critical section) +may not. + +Sleeping in the wrong place may lead to kernel hangs, but in the context of RCU, +it can even threaten memory safety: +if a CPU sleeps in an RCU read-side critical section, it will be mistakenly considered to have exited that critical section, +potentially leading to use-after-free[^1]. + +Existing C code in the kernel relies on [`might_sleep`](https://elixir.bootlin.com/linux/v6.12.6/source/include/linux/kernel.h#L93) +and similar annotations which facilitate debugging via runtime tracking when `CONFIG_DEBUG_ATOMIC_SLEEP` is enabled. + +Because of the need to forbid sleep, it is not sufficient to simply use RAII to model RCU in Rust +as we might intuitively want to do. +We need some additional checking to ensure that while RCU guards exist, no sleeps or context switches +are performed. + +# `klint` + +The [`klint`](https://rust-for-linux.com/klint) tool performs static analysis on kernel Rust code +and addresses this problem by tracking preemption count across all functions at compile-time. + +It does so based on annotations added to our functions that specify: +- the expected range of preemption counts when calling the function +- the adjustment performed to the preemption count after the function returns + +If a function is called from a context where preemption count may be outside the function's expectation, +`klint` will emit an error message. + +Recursive functions, generics, and function pointers complicate this analysis, so it is not foolproof, +and conditional control flow around also means `klint`'s analysis is approximate. +But this still catches obvious mistakes in straightforward code, +and `klint` is only likely to improve its analyses. + +[^1] diff --git a/src/rust-for-linux/hands-on.md b/src/rust-for-linux/hands-on.md new file mode 100644 index 000000000000..5f772fa3146c --- /dev/null +++ b/src/rust-for-linux/hands-on.md @@ -0,0 +1,7 @@ +# Hands-on With Kernel Rust + +{{%segment outline}} + +We've talked about the general requirements for using Rust in the Linux kernel. + +Now let's dig into the code as it stands and see how to work with the present state of Rust for Linux. diff --git a/src/rust-for-linux/kernel-module.md b/src/rust-for-linux/kernel-module.md new file mode 100644 index 000000000000..8bef28883f3a --- /dev/null +++ b/src/rust-for-linux/kernel-module.md @@ -0,0 +1,49 @@ +# A Rust Kernel Module + +A minimal Rust kernel module looks like the below +(from [`samples/rust/rust_minimal.rs`](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/samples/rust/rust_minimal.rs) in the Rust for Linux tree): + +```rust +use kernel::prelude::*; + +module! { + type: RustMinimal, + name: "rust_minimal", + author: "Rust for Linux Contributors", + description: "Rust minimal sample", + license: "GPL", +} + +struct RustMinimal { + numbers: KVec, +} + +impl kernel::Module for RustMinimal { + fn init(_module: &'static ThisModule) -> Result { + pr_info!("Rust minimal sample (init)\n"); + pr_info!("Am I built-in? {}\n", !cfg!(MODULE)); + + let mut numbers = KVec::new(); + numbers.push(72, GFP_KERNEL)?; + numbers.push(108, GFP_KERNEL)?; + numbers.push(200, GFP_KERNEL)?; + + Ok(RustMinimal { numbers }) + } +} + +impl Drop for RustMinimal { + fn drop(&mut self) { + pr_info!("My numbers are {:?}\n", self.numbers); + pr_info!("Rust minimal sample (exit)\n"); + } +} +``` + +We'll examine each part of the module definition in the following slides. + +
+ +It is also possible to build Rust kernel modules [out-of-tree](https://github.com/Rust-for-Linux/rust-out-of-tree-module). + +
diff --git a/src/rust-for-linux/macros.md b/src/rust-for-linux/macros.md new file mode 100644 index 000000000000..3a544db363ae --- /dev/null +++ b/src/rust-for-linux/macros.md @@ -0,0 +1,53 @@ +--- +minutes: 10 +--- + +# Macros + +The `kernel` crate exposes some kernel functionality through macros, +and provides other macros to facilitate definitions that follow kernel patterns. + +## Printing macros + +The kernel provides [`pr_info!`](https://rust.docs.kernel.org/kernel/macro.pr_info.html) and +[`dev_info!`](https://rust.docs.kernel.org/kernel/macro.dev_info.html), +which correspond to the identically-named kernel macros in C. +These support string formatting compatible with Rust's `std::print!`. + +```rust +pr_info!("hello {}\n", "there"); +``` + +## Conditional Compilation + +In C, conditional compilation is done with the preprocessor using `#if`/`#ifdef`. + +Rust in the kernel may want to perform conditional compilation +(which is done with `#[cfg]` attributes in Rust) based on the same `CONFIG_FOO` macros as C code might consider. + +The kernel build system exports these as `cfg`s, so they can be used as shown below[^1]: + +```rust +#[cfg(CONFIG_X)] // Enabled (`y` or `m`) +#[cfg(CONFIG_X="y")] // Enabled as a built-in (`y`) +#[cfg(CONFIG_X="m")] // Enabled as a module (`m`) +#[cfg(not(CONFIG_X))] // Disabled +``` + +## Kernel Vtables + +The kernel has slightly different requirements for its vtables than Rust traits provide. +For kernel vtables, unimplemented functions are represented by `NULL` function pointers, +while Rust traits always implement all methods. + +This mismatch is resolved by providing Rust with the +[`vtable!`](https://rust-for-linux.github.io/docs/macros/attr.vtable.html) attribute macro. + +This macro is placed above trait definitions and impls and provides +constant `bool` `HAS_METHODNAME` members for each method. + +## The `module!` macro + +Kernel modules are defined with the `macro!` module, which we'll examine on its own. + +[^1]: diff --git a/src/rust-for-linux/modules.md b/src/rust-for-linux/modules.md new file mode 100644 index 000000000000..5f61a41cd05c --- /dev/null +++ b/src/rust-for-linux/modules.md @@ -0,0 +1,23 @@ +--- +minutes: 5 +--- + +# Building Kernel Modules + +To build kernel modules in Rust, we need to build `.ko` shared objects +that link against the rest of the kernel. + +In C, kernel modules use the `module_init` and `module_exit` macros to specify how to initialize and +deinitialize the module. +For Rust, we'll need some equivalent of these macros. +Ultimately, these macros specify the values of two fields in a `struct this_module` +which is placed in the `.gnu.linkonce.this_module` section of the kernel module object file. + +We can achieve this in Rust with by defining an equivalent struct as a `static` item +and using the `#[unsafe(link_section = ".gnu.linkonce.this_module")]` attribute. +The `.init` and `.exit` fields of our struct will need to be pointers to the appropriate functions, +which leads to our next question: +how do we define Rust functions with the types and calling convention expected here? + +In practice, Rust for Linux has a convenient and safe wrapper around this pattern +which we'll see when we look at a real-world Rust kernel module. diff --git a/src/rust-for-linux/modules/module-macro.md b/src/rust-for-linux/modules/module-macro.md new file mode 100644 index 000000000000..037201c02ed2 --- /dev/null +++ b/src/rust-for-linux/modules/module-macro.md @@ -0,0 +1,22 @@ +--- +minutes: 2 +--- + +# The `module!` Macro + +A kernel module itself is declared with the [`module!`](https://rust.docs.kernel.org/macros/macro.module.html) macro. + +Here we specify the type for the module, upon which we will implement the `kernel::Module` trait, +as well as metadata like the module's name and description. + +```rust +module! { + type: RustMinimal, + name: "rust_minimal", + author: "Rust for Linux Contributors", + description: "Rust minimal sample", + license: "GPL", +} + +struct RustMinimal; +``` diff --git a/src/rust-for-linux/modules/parameters.md b/src/rust-for-linux/modules/parameters.md new file mode 100644 index 000000000000..fcca4e233261 --- /dev/null +++ b/src/rust-for-linux/modules/parameters.md @@ -0,0 +1,13 @@ +--- +minutes: 2 +--- + +# Module Parameters + +Support for defining and accessing module parameters from Rust has not yet landed in mainline Linux. + +However, there is outstanding work toward supporting module parameters[^1]. + +In the meantime, it may be preferable to configure modules through sysfs. + +[^1]: diff --git a/src/rust-for-linux/modules/setup-and-teardown.md b/src/rust-for-linux/modules/setup-and-teardown.md new file mode 100644 index 000000000000..f2496b03da33 --- /dev/null +++ b/src/rust-for-linux/modules/setup-and-teardown.md @@ -0,0 +1,29 @@ +--- +minutes: 4 +--- + +# Module Setup and Teardown + +Our module implements the [`kernel::Module`](https://rust.docs.kernel.org/kernel/trait.Module.html) trait +to specify its entrypoint and perform any necessary set-up: + +```rust +pub trait Module: Sized + Sync { + fn init(name: &'static CStr, module: &'static ThisModule) -> Result; +} +``` + +If some setup fails (e.g. finding device tree nodes or acquiring needed resources), +the `init` method can return `Err`. + +## `Drop` impl + +By implementing `Drop` on our module struct, we can perform any necessary cleanup and teardown. + +```rust +impl Drop for MyModule { + fn drop(&mut self) { + // ... + } +} +``` diff --git a/src/rust-for-linux/next-steps.md b/src/rust-for-linux/next-steps.md new file mode 100644 index 000000000000..b8c8f96d40a1 --- /dev/null +++ b/src/rust-for-linux/next-steps.md @@ -0,0 +1,12 @@ +--- +minutes: 5 +--- + +# Next Steps + +The Linux documentation has a number of +[pointers to further resources](https://docs.kernel.org/process/kernel-docs.html#rust) on using Rust in the kernel. + +The Rust for Linux project lists various avenues for [contacting the project](https://rust-for-linux.com/contact). + +The [Rust for Linux Zulip](https://rust-for-linux.zulipchat.com/) is particularly active and a good starting point for inquiries. diff --git a/src/rust-for-linux/rust-analyzer.md b/src/rust-for-linux/rust-analyzer.md new file mode 100644 index 000000000000..cc358b56c3ed --- /dev/null +++ b/src/rust-for-linux/rust-analyzer.md @@ -0,0 +1,25 @@ +--- +minutes: 3 +--- + +# `rust-analyzer` Setup + +The `rust-analyzer` LSP server provides IDE support for working with Rust. + +First, we install rust-analyzer normally: + +```sh +$ rustup component add rust-analyzer +``` + +To use it with Rust for Linux, we need to generate a configuration file for +`rust-analyzer`[^1]: + +```sh +$ make rust-analyzer +``` + +Then, opening our editor in the directory where the `rust-project.json` file +was created should run the language server with the appropriate settings. + +[^1]: diff --git a/src/rust-for-linux/rust-for-linux.md b/src/rust-for-linux/rust-for-linux.md new file mode 100644 index 000000000000..6608418f4f68 --- /dev/null +++ b/src/rust-for-linux/rust-for-linux.md @@ -0,0 +1,35 @@ +--- +minutes: 4 +--- + +# Getting Rust for Linux + +First, we want a checkout of Linux with Rust support. +The basics have been upstream since + +Then, we can follow the instructions from the Rust for Linux +[quick-start guide](https://github.com/Rust-for-Linux/linux/blob/rust/Documentation/rust/quick-start.rst#rust-analyzer): + +1. Install a Rust toolchain, including standard library sources: + +```sh +$ rustup override set $(scripts/min-tool-version.sh rustc) +$ rustup component add rust-src rustfmt clippy +``` + +This installs the oldest version of the Rust compiler supported by Rust for Linux. +Any changes should also be tested against the latest stable rustc release. + +2. Install bindgen: + +```sh +$ cargo install --locked --version $(scripts/min-tool-version.sh bindgen) bindgen +``` + +2. Enable `CONFIG_RUST` in your kernel build configuration. + +3. When building the kernel, use an LLVM toolchain: + +```sh +$ make LLVM=1 +``` diff --git a/src/rust-for-linux/types.md b/src/rust-for-linux/types.md new file mode 100644 index 000000000000..d24af85b6161 --- /dev/null +++ b/src/rust-for-linux/types.md @@ -0,0 +1,19 @@ +--- +minutes: 5 +--- + +# Type Mapping + +The kernel uses slightly different conventions for its types than other C code. +As such, the normal use of `bindgen` to generate bindings can introduce some problems when applied to the kernel. + +The explicit `{u,s}{8,16,32,64}` types map in the obvious way to Rust `{u,i}{8,16,32,64}` types, +but the potential signedness of `char` as well as +the kernel's requirement that `long`s can hold pointers +introduce some deviations from the expectations of C as implemented by bindgen. + +As such, an alternative bindgen mapping is used for the kernel[^1]: + +![the kernel bindgen mapping](bindgen-mapping.png) + +[^1]: diff --git a/src/rust-for-linux/using-abstractions.md b/src/rust-for-linux/using-abstractions.md new file mode 100644 index 000000000000..ab5d67a07e0a --- /dev/null +++ b/src/rust-for-linux/using-abstractions.md @@ -0,0 +1,11 @@ +--- +minutes: 12 +--- + +# Using Abstractions + +Now that we've seen a trivial driver, let's look at a real one for the +[`Asix ax88796b network PHY`](https://github.com/Rust-for-Linux/linux/blob/rust-next/drivers/net/phy/ax88796b_rust.rs). + +Here we'll see what it looks like to register a driver for a particular subsystem +and implement the needed functionality using abstractions from a subsystem. diff --git a/src/rust-for-linux/welcome.md b/src/rust-for-linux/welcome.md new file mode 100644 index 000000000000..589a0455c02e --- /dev/null +++ b/src/rust-for-linux/welcome.md @@ -0,0 +1,25 @@ +--- +course: Rust for Linux +session: Morning +target_minutes: 180 +--- + +# Welcome to Rust for Linux + +The Linux Kernel is currently working to add support for developing with the +Rust programming language. + +This involves considerations on both sides of the equation - Linux and Rust. + +Rust must conform to the non-negotiable requirements Linux imposes on compile- +and run-time behavior of its core and modules. Meanwhile, Linux must expose its +existing functionality in ways that Rust can access as efficiently and safely +as possible. + +We'll look at the general background, get our hands dirty with some existing +Rust code in Linux, and then explore particular integration challenges, both +resolved and ongoing. + +## Schedule + +{{%session outline}}