Skip to content

Commit b51bb90

Browse files
committed
format Rust for Linux material
1 parent 4680a8b commit b51bb90

27 files changed

+396
-323
lines changed

src/rust-for-linux/basic-requirements.md

+13-18
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,9 @@ interop in userspace.
66
## Building
77

88
In userspace, the most common setup is to use Cargo to compile our Rust and
9-
later integrate into a C build system if needed.
10-
Meanwhile, the Linux Kernel compiles its C code with its custom Kbuild build
11-
system.
12-
In Rust for Linux, the kernel build system invokes the Rust compiler directly,
13-
without Cargo.
9+
later integrate into a C build system if needed. Meanwhile, the Linux Kernel
10+
compiles its C code with its custom Kbuild build system. In Rust for Linux, the
11+
kernel build system invokes the Rust compiler directly, without Cargo.
1412

1513
## No `libstd`
1614

@@ -21,32 +19,29 @@ operating system, so kernel Rust will have to eschew the standard library.
2119
## Module Support
2220

2321
Much code in the kernel is compiled into kernel modules rather than as part of
24-
the core kernel.
25-
To write kernel modules in Rust we'll need to be able to match the ABI of kernel
26-
modules.
22+
the core kernel. To write kernel modules in Rust we'll need to be able to match
23+
the ABI of kernel modules.
2724

2825
## Safe Wrappers
2926

3027
To reap the benefits of Rust, we want to be able to write as much code as
31-
possible in safe Rust.
32-
This means that we want safe wrappers for as much kernel functionality as
33-
possible.
28+
possible in safe Rust. This means that we want safe wrappers for as much kernel
29+
functionality as possible.
3430

3531
## Mapping Types
3632

3733
When writing these wrappers, we'll need to refer to the data types of values
38-
passed to and from existing kernel functions in C.
39-
Unlike userspace C, the kernel uses its own set of primitive types rather than
40-
those provided by the C standard.
41-
We'll have to map back and forth between those kernel types and compatible Rust
42-
ones when doing foreign calls.
34+
passed to and from existing kernel functions in C. Unlike userspace C, the
35+
kernel uses its own set of primitive types rather than those provided by the C
36+
standard. We'll have to map back and forth between those kernel types and
37+
compatible Rust ones when doing foreign calls.
4338

4439
## Keeping the Kernel Lean
4540

4641
Finally, even the core Rust library assumes a basic level of functionality that
4742
includes some costly operations (e.g. unicode processing) for which the kernel
48-
does not want to pay implementation costs.
49-
To use Rust in the kernel we'll need a way to disable this functionality.
43+
does not want to pay implementation costs. To use Rust in the kernel we'll need
44+
a way to disable this functionality.
5045

5146
# Outline
5247

src/rust-for-linux/bindings-interfaces.md

+56-37
Original file line numberDiff line numberDiff line change
@@ -6,66 +6,85 @@ minutes: 18
66

77
`bindgen` is used to generate low-level, unsafe bindings for C interfaces.
88

9-
But to reap the benefits of Rust, we want to use safe, foolproof interfaces to unsafe functionality.
9+
But to reap the benefits of Rust, we want to use safe, foolproof interfaces to
10+
unsafe functionality.
1011

11-
Subsystems are expected to implement safe interfaces on top of the low-level generated bindings.
12-
These safe interfaces are exposed as top-level modules within the [`kernel` crate](https://rust.docs.kernel.org/kernel/).
13-
The top-level `bindings` module holds the unsafe `bindgen`-generated bindings,
14-
which are generated from the C headers included by `rust/bindings/bindings_helper.h`.
12+
Subsystems are expected to implement safe interfaces on top of the low-level
13+
generated bindings. These safe interfaces are exposed as top-level modules
14+
within the [`kernel` crate](https://rust.docs.kernel.org/kernel/). The top-level
15+
`bindings` module holds the unsafe `bindgen`-generated bindings, which are
16+
generated from the C headers included by `rust/bindings/bindings_helper.h`.
1517

16-
In Rust for Linux, unsafe `bindgen`-generated bindings should not be used outside the `kernel` crate.
17-
Drivers and other subsystems will make use of the safe abstractions from this crate.
18+
In Rust for Linux, unsafe `bindgen`-generated bindings should not be used
19+
outside the `kernel` crate. Drivers and other subsystems will make use of the
20+
safe abstractions from this crate.
1821

1922
Only a subset of Linux subsystems currently have such abstractions.
2023

21-
It's worth browsing the [list of modules](https://rust.docs.kernel.org/kernel/#modules)
22-
exposed by the `kernel` crate to see what exists currently.
23-
Many of these subsystems have only partial bindings based on the needs of consumers so far.
24+
It's worth browsing the
25+
[list of modules](https://rust.docs.kernel.org/kernel/#modules) exposed by the
26+
`kernel` crate to see what exists currently. Many of these subsystems have only
27+
partial bindings based on the needs of consumers so far.
2428

2529
## Adding a Module
2630

27-
To add a module for some subsystem, first its header must be added to `bindings_helper.h`.
28-
It may be necessary to write some custom code to wrap macros or `inline` functions
29-
that are not automatically handled by `bindgen`; this code lives in the `rust/helpers/` directory.
31+
To add a module for some subsystem, first its header must be added to
32+
`bindings_helper.h`. It may be necessary to write some custom code to wrap
33+
macros or `inline` functions that are not automatically handled by `bindgen`;
34+
this code lives in the `rust/helpers/` directory.
3035

31-
Then we need to write a safe abstraction using these bindings and exposing them to the rest of kernel Rust.
36+
Then we need to write a safe abstraction using these bindings and exposing them
37+
to the rest of kernel Rust.
3238

33-
Some commits from work-in-progress bindings and abstractions
34-
can provide an idea of what it looks like to expose new kernel functionality:
39+
Some commits from work-in-progress bindings and abstractions can provide an idea
40+
of what it looks like to expose new kernel functionality:
3541

36-
- GPIO Consumer: [fecb4bd73f06bb2cac8e16aca7ef0e2f1b6acb50](https://github.com/Fabo/linux/commit/fecb4bd73f06bb2cac8e16aca7ef0e2f1b6acb50)
37-
- Regmap: [ec0b740ac5ab299e4c86011a0002919e5bbe5c2d](https://github.com/Fabo/linux/commit/ec0b740ac5ab299e4c86011a0002919e5bbe5c2d)
38-
- I2C: [70ed30fcdf8ec62fa91485c3c0a161a9d0194668](https://github.com/Fabo/linux/commit/70ed30fcdf8ec62fa91485c3c0a161a9d0194668)
42+
- GPIO Consumer:
43+
[fecb4bd73f06bb2cac8e16aca7ef0e2f1b6acb50](https://github.com/Fabo/linux/commit/fecb4bd73f06bb2cac8e16aca7ef0e2f1b6acb50)
44+
- Regmap:
45+
[ec0b740ac5ab299e4c86011a0002919e5bbe5c2d](https://github.com/Fabo/linux/commit/ec0b740ac5ab299e4c86011a0002919e5bbe5c2d)
46+
- I2C:
47+
[70ed30fcdf8ec62fa91485c3c0a161a9d0194668](https://github.com/Fabo/linux/commit/70ed30fcdf8ec62fa91485c3c0a161a9d0194668)
3948

4049
## Guidelines for Abstractions
4150

42-
Abstractions may not be perfectly safe, but should try to be as safe as possible.
43-
Unsafe functionality exposed should have its safety conditions documented
44-
so that users have guidance on how to use the functionality and justify such use.
51+
Abstractions may not be perfectly safe, but should try to be as safe as
52+
possible. Unsafe functionality exposed should have its safety conditions
53+
documented so that users have guidance on how to use the functionality and
54+
justify such use.
4555

46-
Abstractions should also attempt to present relatively idiomatic Rust in their interfaces:
47-
- Follow Rust naming/capitalization conventions while remaining unsurprising to kernel developers.
56+
Abstractions should also attempt to present relatively idiomatic Rust in their
57+
interfaces:
58+
59+
- Follow Rust naming/capitalization conventions while remaining unsurprising to
60+
kernel developers.
4861
- Use RAII instead of manual resource management where possible.
49-
- Avoid raw pointers to bound kernel objects in favor of safer, more limited interfaces.
50-
62+
- Avoid raw pointers to bound kernel objects in favor of safer, more limited
63+
interfaces.
64+
5165
When exposing types from generated bindings, code should make use of the
52-
[`Opaque<T>`](https://rust.docs.kernel.org/kernel/types/struct.Opaque.html) type
53-
along with native Rust references and the
54-
[`ARef<T>`](https://rust.docs.kernel.org/kernel/types/struct.ARef.html) type for types that are inherently reference-counted.
55-
This type links types' built-in reference count operations to the `Clone` and `Drop` traits.
66+
[`Opaque<T>`](https://rust.docs.kernel.org/kernel/types/struct.Opaque.html)
67+
type along with native Rust references and the
68+
[`ARef<T>`](https://rust.docs.kernel.org/kernel/types/struct.ARef.html) type
69+
for types that are inherently reference-counted. This type links types'
70+
built-in reference count operations to the `Clone` and `Drop` traits.
5671

5772
## Submitting the cyclic dependency
5873

59-
We already know that drivers should not use unsafe bindings directly.
60-
But subsystem maintainers may balk if they see patches submitted that add Rust abstractions without motivation or consumers.
61-
But drivers and subsystem abstractions may have to be submitted separately to different maintainers
62-
due to the distributed nature of Linux development.
74+
We already know that drivers should not use unsafe bindings directly. But
75+
subsystem maintainers may balk if they see patches submitted that add Rust
76+
abstractions without motivation or consumers. But drivers and subsystem
77+
abstractions may have to be submitted separately to different maintainers due to
78+
the distributed nature of Linux development.
6379

64-
So how should a developer submit a driver that requires bindings/abstractions for a subsystem not yet exposed to Rust?
80+
So how should a developer submit a driver that requires bindings/abstractions
81+
for a subsystem not yet exposed to Rust?
6582

6683
There are two main approaches[^1]:
6784

68-
1. Submit the driver as an RFC before submitting the abstractions it relies upon while referencing the RFC as a potential consumer.
69-
2. Submit a stub driver and fill out non-stub functionality as subsystem abstractions land.
85+
1. Submit the driver as an RFC before submitting the abstractions it relies upon
86+
while referencing the RFC as a potential consumer.
87+
2. Submit a stub driver and fill out non-stub functionality as subsystem
88+
abstractions land.
7089

7190
[^1]: <https://rust-for-linux.zulipchat.com/#narrow/channel/288089-General/topic/Upstreaming.20a.20driver.20with.20unsave.20C.20API.20calls.3F/near/471677707>

src/rust-for-linux/bloat.md

+6-5
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,18 @@ minutes: 5
44

55
# Avoiding Bloat
66

7-
Rust for Linux makes use of `libcore` to avoid reimplementing all functionality of the Rust standard library.
8-
But even `libcore` has some functionality built-in that is not portable to all targets the kernel
9-
would like to support or that is not necessary for the kernel while occupying valuable code space.
7+
Rust for Linux makes use of `libcore` to avoid reimplementing all functionality
8+
of the Rust standard library. But even `libcore` has some functionality built-in
9+
that is not portable to all targets the kernel would like to support or that is
10+
not necessary for the kernel while occupying valuable code space.
1011

1112
This includes[^1]:
1213

1314
- Support for math with 128-bit integers
1415
- String formatting for floating-point numbers
1516
- Unicode support for strings
1617

17-
Work is ongoing to make these features optional.
18-
In the meantime, the `libcore` used by Rust for Linux is larger and less portable than it could be.
18+
Work is ongoing to make these features optional. In the meantime, the `libcore`
19+
used by Rust for Linux is larger and less portable than it could be.
1920

2021
[^1]: <https://github.com/Rust-for-Linux/linux/issues/514>

src/rust-for-linux/complications.md

+15-14
Original file line numberDiff line numberDiff line change
@@ -6,34 +6,35 @@ minutes: 5
66

77
{{%segment outline}}
88

9-
There are a number of subtleties and unresolved conflicts between the Rust paradigm and the kernel one.
10-
These must be resolved to ship Rust code in the kernel.
9+
There are a number of subtleties and unresolved conflicts between the Rust
10+
paradigm and the kernel one. These must be resolved to ship Rust code in the
11+
kernel.
1112

1213
Some issues are deeper problems that require additional research and development
13-
before Rust for Linux is ready for the prime-time;
14-
others merely require some additional learning and attention
15-
on behalf of aspiring Rust for Linux developers.
14+
before Rust for Linux is ready for the prime-time; others merely require some
15+
additional learning and attention on behalf of aspiring Rust for Linux
16+
developers.
1617

17-
##
18+
##
1819

1920
Resolving these conflicts involves changes on both sides of the collaboration.
2021
On the Rust side, new features land first in the Nightly edition of the compiler
2122
before being stabilized.
2223

2324
To avoid waiting for stabilization, the kernel uses an
2425
[escape hatch](https://rustc-dev-guide.rust-lang.org/building/bootstrapping/what-bootstrapping-does.html#complications-of-bootstrapping)
25-
to access unstable features even in stable releases of the compiler.
26-
This assists in the goal of eventually deploying Rust for Linux in Linux
26+
to access unstable features even in stable releases of the compiler. This
27+
assists in the goal of eventually deploying Rust for Linux in Linux
2728
distributions that ship only a stable version of the Rust toolchain.
2829

2930
Nonetheless, being able to build Rust for Linux using only stable Rust features
30-
is a significant goal;
31-
the issues blocking this are tracked specifically by both the Rust for Linux
32-
project[^1] and the Rust developers themselves[^2].
31+
is a significant goal; the issues blocking this are tracked specifically by both
32+
the Rust for Linux project[^1] and the Rust developers themselves[^2].
3333

34-
In the next slides we'll explore the most significant sources of friction between
35-
Rust and Linux kernel development to be aware of challenges we are likely to encounter
36-
when trying to implement kernel functionality in Rust.
34+
In the next slides we'll explore the most significant sources of friction
35+
between Rust and Linux kernel development to be aware of challenges we are
36+
likely to encounter when trying to implement kernel functionality in Rust.
3737

3838
[^1]: <https://github.com/Rust-for-Linux/linux/issues/2>
39+
3940
[^2]: <https://github.com/rust-lang/rust-project-goals/issues/116>

src/rust-for-linux/complications/async.md

+18-15
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,29 @@ minutes: 8
44

55
# Async
66

7-
The kernel performs many operations concurrently and involves significant amounts of interaction
8-
between CPU cores and other devices.
9-
For this reason, it would be no surprise to see that async Rust would be a fundamental requirement
10-
for using Rust in the kernel.
11-
But the kernel is central arbiter of most synchronization and is currently written in regular, synchronous C.
7+
The kernel performs many operations concurrently and involves significant
8+
amounts of interaction between CPU cores and other devices. For this reason, it
9+
would be no surprise to see that async Rust would be a fundamental requirement
10+
for using Rust in the kernel. But the kernel is central arbiter of most
11+
synchronization and is currently written in regular, synchronous C.
1212

13-
Rust code making use of `async` mostly exists to write composable code that will run atop event loops,
14-
but the Linux kernel is not really organized as an event loop:
15-
user tasks call directly into the kernel; control flow for interrupts is handled by hardware.
13+
Rust code making use of `async` mostly exists to write composable code that will
14+
run atop event loops, but the Linux kernel is not really organized as an event
15+
loop: user tasks call directly into the kernel; control flow for interrupts is
16+
handled by hardware.
1617

1718
As such, `async` support is not critical for most kernel programming tasks.
18-
However, it is possible to view some components of the kernel as async executors,
19-
and some work has been done in this direction.
20-
Wedson Almeida Filho implemented both workqueue-based[^1] and single-threaded async executors as proofs of concept.
19+
However, it is possible to view some components of the kernel as async
20+
executors, and some work has been done in this direction. Wedson Almeida Filho
21+
implemented both workqueue-based[^1] and single-threaded async executors as
22+
proofs of concept.
2123

22-
There is not a fundamental incompatibility between Rust-for-Linux and Rust `async`,
23-
which is a similar situation to the amenability of `async` to use in embedded Rust programming
24-
(e.g. the Embassy project).
24+
There is not a fundamental incompatibility between Rust-for-Linux and Rust
25+
`async`, which is a similar situation to the amenability of `async` to use in
26+
embedded Rust programming (e.g. the Embassy project).
2527

26-
Nonetheless, no killer application of `async` in Rust for Linux has made it a priority.
28+
Nonetheless, no killer application of `async` in Rust for Linux has made it a
29+
priority.
2730

2831
<details>
2932

src/rust-for-linux/complications/code-size.md

+22-16
Original file line numberDiff line numberDiff line change
@@ -4,32 +4,37 @@ minutes: 10
44

55
# Code Size
66

7-
One pitfall when writing Rust code can be the multiplicative increase in generated machine code when using generics.
7+
One pitfall when writing Rust code can be the multiplicative increase in
8+
generated machine code when using generics.
89

9-
For the Linux kernel, which must be suitable for space-limited embedded environments,
10-
keeping code size low is a significant concern.
10+
For the Linux kernel, which must be suitable for space-limited embedded
11+
environments, keeping code size low is a significant concern.
1112

12-
Experiments with Rust in the kernel so far have shown that Rust code can be of similar code size to C,
13-
but may also be larger in some cases[^1].
13+
Experiments with Rust in the kernel so far have shown that Rust code can be of
14+
similar code size to C, but may also be larger in some cases[^1].
1415

1516
## Assessing Bloat
1617

17-
Tools exist to help analyze different source code's contribution to the size of compiled code,
18-
such as [`cargo-bloat`](https://github.com/RazrFalcon/cargo-bloat).
18+
Tools exist to help analyze different source code's contribution to the size of
19+
compiled code, such as
20+
[`cargo-bloat`](https://github.com/RazrFalcon/cargo-bloat).
1921

2022
## Shrinking Code Size
2123

22-
The reasons for code bloat vary and are not generally specific to Linux kernel usage of Rust.
23-
The most common causes for code bloat are excessive use of generics and forced inlining.
24-
In general, generics should be preferred over trait objects when writing abstractions
25-
that are expected to "compile out" or where generating separate code for different types is critical
26-
for performance (e.g. inner loops or arithmetic on values of a generic type).
24+
The reasons for code bloat vary and are not generally specific to Linux kernel
25+
usage of Rust. The most common causes for code bloat are excessive use of
26+
generics and forced inlining. In general, generics should be preferred over
27+
trait objects when writing abstractions that are expected to "compile out" or
28+
where generating separate code for different types is critical for performance
29+
(e.g. inner loops or arithmetic on values of a generic type).
2730

28-
In other situations, trait objects should be preferred to allow reusing definitions
29-
without machine-code duplication, which may closer mirror patterns that would be most natural in C.
31+
In other situations, trait objects should be preferred to allow reusing
32+
definitions without machine-code duplication, which may closer mirror patterns
33+
that would be most natural in C.
3034

31-
When accepting generic parameters that get converted to a concrete type before use,
32-
follow the pattern of defining an inner monomorphic function that can be shared[^2]:
35+
When accepting generic parameters that get converted to a concrete type before
36+
use, follow the pattern of defining an inner monomorphic function that can be
37+
shared[^2]:
3338

3439
```rust
3540
pub fn read_to_string<P: AsRef<Path>>(path: P) -> io::Result<String> {
@@ -45,4 +50,5 @@ pub fn read_to_string<P: AsRef<Path>>(path: P) -> io::Result<String> {
4550
```
4651

4752
[^1]: <https://www.usenix.org/system/files/atc24-li-hongyu.pdf>
53+
4854
[^2]: <https://github.com/rust-lang/rust/blob/ae612bedcbfc7098d1711eb35bc7ca994eb17a4c/library/std/src/fs.rs#L295-L304>

0 commit comments

Comments
 (0)