diff --git a/src/rust-for-linux/basic-requirements.md b/src/rust-for-linux/basic-requirements.md index e8b349d283cb..0eea8268e462 100644 --- a/src/rust-for-linux/basic-requirements.md +++ b/src/rust-for-linux/basic-requirements.md @@ -6,11 +6,9 @@ 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. +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` @@ -21,32 +19,29 @@ 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. +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. +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. +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. +does not want to pay implementation costs. To use Rust in the kernel we'll need +a way to disable this functionality. # Outline diff --git a/src/rust-for-linux/bindings-interfaces.md b/src/rust-for-linux/bindings-interfaces.md index 43c70f280213..2bc99dfe1cf8 100644 --- a/src/rust-for-linux/bindings-interfaces.md +++ b/src/rust-for-linux/bindings-interfaces.md @@ -6,66 +6,85 @@ minutes: 18 `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. +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`. +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. +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. +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. +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. +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: +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) +- 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 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. +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. - +- 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. + [`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. +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? +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. 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 index b94a1ff0d06f..0a2167a9a04f 100644 --- a/src/rust-for-linux/bloat.md +++ b/src/rust-for-linux/bloat.md @@ -4,9 +4,10 @@ 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. +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]: @@ -14,7 +15,7 @@ This includes[^1]: - 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. +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 index b38b0cc2d56a..c315cce81b11 100644 --- a/src/rust-for-linux/complications.md +++ b/src/rust-for-linux/complications.md @@ -6,15 +6,16 @@ minutes: 5 {{%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. +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. +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 @@ -22,18 +23,18 @@ 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 +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]. +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. +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 index c3396447a42c..8c81e05028a5 100644 --- a/src/rust-for-linux/complications/async.md +++ b/src/rust-for-linux/complications/async.md @@ -4,26 +4,29 @@ 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 arbiter of most synchronization and is currently written in regular, synchronous C. +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 arbiter 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. +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. +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). +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. +Nonetheless, no killer application of `async` in Rust for Linux has made it a +priority.
diff --git a/src/rust-for-linux/complications/code-size.md b/src/rust-for-linux/complications/code-size.md index f330a38fa783..f02b526ef18d 100644 --- a/src/rust-for-linux/complications/code-size.md +++ b/src/rust-for-linux/complications/code-size.md @@ -4,32 +4,37 @@ minutes: 10 # Code Size -One pitfall when writing Rust code can be the multiplicative increase in generated machine code when using generics. +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. +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]. +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). +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 preferred 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). +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 preferred 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 preferred to allow reusing definitions -without machine-code duplication, which may closer mirror patterns that would be most natural in C. +In other situations, trait objects should be preferred 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]: +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 { @@ -45,4 +50,5 @@ pub fn read_to_string>(path: P) -> io::Result { ``` [^1]: + [^2]: diff --git a/src/rust-for-linux/complications/fallible-allocation.md b/src/rust-for-linux/complications/fallible-allocation.md index e227d0eb6193..15adb26897a0 100644 --- a/src/rust-for-linux/complications/fallible-allocation.md +++ b/src/rust-for-linux/complications/fallible-allocation.md @@ -18,10 +18,11 @@ 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. +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: +In Rust for Linux, rather than using the infallible allocation APIs provided by +`liballoc`, the kernel library has its own allocation interfaces: ## `KBox` @@ -31,14 +32,15 @@ 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. +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: +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(); @@ -48,10 +50,13 @@ 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. +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 index 8463f08f5df7..644a021c3803 100644 --- a/src/rust-for-linux/complications/kernel-doc.md +++ b/src/rust-for-linux/complications/kernel-doc.md @@ -4,7 +4,8 @@ minutes: 3 # Documentation -Documentation in Rust for Linux is built with the `rustdoc` tool just like for regular Rust code. +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: @@ -12,7 +13,8 @@ Running rustdoc on the kernel is done with the `rustdoc` Make target: $ make LLVM=1 rustdoc ``` -after which generated docs can be viewed by opening `Documentation/output/rust/rustdoc/kernel/index.html`. +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: diff --git a/src/rust-for-linux/complications/memory-models.md b/src/rust-for-linux/complications/memory-models.md index 99cae267d35f..aba1cc37935e 100644 --- a/src/rust-for-linux/complications/memory-models.md +++ b/src/rust-for-linux/complications/memory-models.md @@ -4,41 +4,39 @@ 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. +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 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. + (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. - + - 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. + 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. +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]. +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. +- 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.
diff --git a/src/rust-for-linux/complications/mitigations.md b/src/rust-for-linux/complications/mitigations.md index 6145db5dffcc..a4b0150e85af 100644 --- a/src/rust-for-linux/complications/mitigations.md +++ b/src/rust-for-linux/complications/mitigations.md @@ -4,19 +4,20 @@ 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. +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. +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]. +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 index f63ed0a24d98..8b30f03d2ce2 100644 --- a/src/rust-for-linux/complications/pin.md +++ b/src/rust-for-linux/complications/pin.md @@ -4,55 +4,63 @@ 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. +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. +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. +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. +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. +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. +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). +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`. +`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. +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. +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. +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: +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}; diff --git a/src/rust-for-linux/complications/safety.md b/src/rust-for-linux/complications/safety.md index a81c136721f6..4849986587d2 100644 --- a/src/rust-for-linux/complications/safety.md +++ b/src/rust-for-linux/complications/safety.md @@ -6,44 +6,50 @@ minutes: 15 ## 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 +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. +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. +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. +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. +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. +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. +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. +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 index f9a2356518b8..2003f2d93fca 100644 --- a/src/rust-for-linux/complications/separate-compilation.md +++ b/src/rust-for-linux/complications/separate-compilation.md @@ -5,39 +5,42 @@ 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. +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. +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.
diff --git a/src/rust-for-linux/complications/sleeping.md b/src/rust-for-linux/complications/sleeping.md index 28d26d478d50..1e49959b04ea 100644 --- a/src/rust-for-linux/complications/sleeping.md +++ b/src/rust-for-linux/complications/sleeping.md @@ -4,40 +4,45 @@ 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. +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, +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. +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 +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. +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. +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. +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 index 5f772fa3146c..51f5d717d879 100644 --- a/src/rust-for-linux/hands-on.md +++ b/src/rust-for-linux/hands-on.md @@ -4,4 +4,5 @@ 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. +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 index 8bef28883f3a..f263b3ca4dc3 100644 --- a/src/rust-for-linux/kernel-module.md +++ b/src/rust-for-linux/kernel-module.md @@ -1,7 +1,8 @@ # 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): +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::*; @@ -44,6 +45,7 @@ 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). +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 index 3a544db363ae..81a32c5277a3 100644 --- a/src/rust-for-linux/macros.md +++ b/src/rust-for-linux/macros.md @@ -4,15 +4,16 @@ minutes: 10 # Macros -The `kernel` crate exposes some kernel functionality through macros, -and provides other macros to facilitate definitions that follow kernel patterns. +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!`. +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"); @@ -20,12 +21,15 @@ pr_info!("hello {}\n", "there"); ## Conditional Compilation -In C, conditional compilation is done with the preprocessor using `#if`/`#ifdef`. +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. +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]: +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`) @@ -36,18 +40,20 @@ The kernel build system exports these as `cfg`s, so they can be used as shown be ## 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. +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. +[`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. +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. +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 index 5f61a41cd05c..b0184215a313 100644 --- a/src/rust-for-linux/modules.md +++ b/src/rust-for-linux/modules.md @@ -4,20 +4,20 @@ 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. +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. +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? +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. +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 index 037201c02ed2..e4b2a513a73b 100644 --- a/src/rust-for-linux/modules/module-macro.md +++ b/src/rust-for-linux/modules/module-macro.md @@ -4,10 +4,12 @@ minutes: 2 # The `module!` Macro -A kernel module itself is declared with the [`module!`](https://rust.docs.kernel.org/macros/macro.module.html) 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. +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! { diff --git a/src/rust-for-linux/modules/parameters.md b/src/rust-for-linux/modules/parameters.md index fcca4e233261..23908f1a433a 100644 --- a/src/rust-for-linux/modules/parameters.md +++ b/src/rust-for-linux/modules/parameters.md @@ -4,7 +4,8 @@ minutes: 2 # Module Parameters -Support for defining and accessing module parameters from Rust has not yet landed in mainline Linux. +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]. diff --git a/src/rust-for-linux/modules/setup-and-teardown.md b/src/rust-for-linux/modules/setup-and-teardown.md index f2496b03da33..467f9c8e27bc 100644 --- a/src/rust-for-linux/modules/setup-and-teardown.md +++ b/src/rust-for-linux/modules/setup-and-teardown.md @@ -4,7 +4,8 @@ minutes: 4 # Module Setup and Teardown -Our module implements the [`kernel::Module`](https://rust.docs.kernel.org/kernel/trait.Module.html) trait +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 @@ -13,12 +14,13 @@ pub trait Module: Sized + Sync { } ``` -If some setup fails (e.g. finding device tree nodes or acquiring needed resources), -the `init` method can return `Err`. +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. +By implementing `Drop` on our module struct, we can perform any necessary +cleanup and teardown. ```rust impl Drop for MyModule { diff --git a/src/rust-for-linux/next-steps.md b/src/rust-for-linux/next-steps.md index b8c8f96d40a1..5219db4e6296 100644 --- a/src/rust-for-linux/next-steps.md +++ b/src/rust-for-linux/next-steps.md @@ -5,8 +5,11 @@ 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. +[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 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. +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 index cc358b56c3ed..700c7c38966e 100644 --- a/src/rust-for-linux/rust-analyzer.md +++ b/src/rust-for-linux/rust-analyzer.md @@ -19,7 +19,7 @@ To use it with Rust for Linux, we need to generate a configuration file for $ 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. +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 index 6608418f4f68..e827bc57b18e 100644 --- a/src/rust-for-linux/rust-for-linux.md +++ b/src/rust-for-linux/rust-for-linux.md @@ -4,8 +4,8 @@ minutes: 4 # Getting Rust for Linux -First, we want a checkout of Linux with Rust support. -The basics have been upstream since +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): @@ -17,8 +17,9 @@ $ 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. +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: diff --git a/src/rust-for-linux/types.md b/src/rust-for-linux/types.md index d24af85b6161..dd94d3d8bf97 100644 --- a/src/rust-for-linux/types.md +++ b/src/rust-for-linux/types.md @@ -5,12 +5,13 @@ 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. +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. +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]: diff --git a/src/rust-for-linux/using-abstractions.md b/src/rust-for-linux/using-abstractions.md index ab5d67a07e0a..135beaa4cec9 100644 --- a/src/rust-for-linux/using-abstractions.md +++ b/src/rust-for-linux/using-abstractions.md @@ -7,5 +7,6 @@ minutes: 12 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. +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 index 589a0455c02e..a9f623884003 100644 --- a/src/rust-for-linux/welcome.md +++ b/src/rust-for-linux/welcome.md @@ -13,8 +13,8 @@ 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. +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