You've already forked comprehensive-rust
mirror of
https://github.com/google/comprehensive-rust.git
synced 2025-09-16 09:36:41 +02:00
docs: improve language in bare-metal section (#2891)
I asked Gemini to review the English for inconsistencies and grammar mistakes. This is the result and I hope it's useful! As a non-native speaker, it is hard for me to evaluate the finer details, so let me know if you would like to see changes (or even better: make them directly in the PR with the suggestion function). --------- Co-authored-by: Dmitri Gribenko <gribozavr@gmail.com>
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
# A better UART driver
|
||||
|
||||
The PL011 actually has [a bunch more registers][1], and adding offsets to
|
||||
construct pointers to access them is error-prone and hard to read. Plus, some of
|
||||
them are bit fields which would be nice to access in a structured way.
|
||||
The PL011 actually has [more registers][1], and adding offsets to construct
|
||||
pointers to access them is error-prone and hard to read. Additionally, some of
|
||||
them are bit fields, which would be nice to access in a structured way.
|
||||
|
||||
| Offset | Register name | Width |
|
||||
| ------ | ------------- | ----- |
|
||||
@@ -23,7 +23,7 @@ them are bit fields which would be nice to access in a structured way.
|
||||
|
||||
<details>
|
||||
|
||||
- There are also some ID registers which have been omitted for brevity.
|
||||
- There are also some ID registers that have been omitted for brevity.
|
||||
|
||||
</details>
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
# Getting Ready to Rust
|
||||
|
||||
Before we can start running Rust code, we need to do some initialisation.
|
||||
Before we can start running Rust code, we need to do some initialization.
|
||||
|
||||
```armasm
|
||||
{{#include examples/src/entry.S:entry}}
|
||||
@@ -12,21 +12,21 @@ This code is in `src/bare-metal/aps/examples/src/entry.S`. It's not necessary to
|
||||
understand this in detail -- the takeaway is that typically some low-level setup
|
||||
is needed to meet Rust's expectations of the system.
|
||||
|
||||
- This is the same as it would be for C: initialising the processor state,
|
||||
- This is the same as it would be for C: initializing the processor state,
|
||||
zeroing the BSS, and setting up the stack pointer.
|
||||
- The BSS (block starting symbol, for historical reasons) is the part of the
|
||||
object file which containing statically allocated variables which are
|
||||
initialised to zero. They are omitted from the image, to avoid wasting space
|
||||
object file that contains statically allocated variables that are
|
||||
initialized to zero. They are omitted from the image, to avoid wasting space
|
||||
on zeroes. The compiler assumes that the loader will take care of zeroing
|
||||
them.
|
||||
- The BSS may already be zeroed, depending on how memory is initialised and the
|
||||
- The BSS may already be zeroed, depending on how memory is initialized and the
|
||||
image is loaded, but we zero it to be sure.
|
||||
- We need to enable the MMU and cache before reading or writing any memory. If
|
||||
we don't:
|
||||
- Unaligned accesses will fault. We build the Rust code for the
|
||||
`aarch64-unknown-none` target which sets `+strict-align` to prevent the
|
||||
compiler generating unaligned accesses, so it should be fine in this case,
|
||||
but this is not necessarily the case in general.
|
||||
`aarch64-unknown-none` target that sets `+strict-align` to prevent the
|
||||
compiler from generating unaligned accesses, so it should be fine in this
|
||||
case, but this is not necessarily the case in general.
|
||||
- If it were running in a VM, this can lead to cache coherency issues. The
|
||||
problem is that the VM is accessing memory directly with the cache disabled,
|
||||
while the host has cacheable aliases to the same memory. Even if the host
|
||||
@@ -34,14 +34,14 @@ is needed to meet Rust's expectations of the system.
|
||||
fills, and then changes from one or the other will get lost when the cache
|
||||
is cleaned or the VM enables the cache. (Cache is keyed by physical address,
|
||||
not VA or IPA.)
|
||||
- For simplicity, we just use a hardcoded pagetable (see `idmap.S`) which
|
||||
- For simplicity, we just use a hardcoded pagetable (see `idmap.S`) that
|
||||
identity maps the first 1 GiB of address space for devices, the next 1 GiB for
|
||||
DRAM, and another 1 GiB higher up for more devices. This matches the memory
|
||||
layout that QEMU uses.
|
||||
- We also set up the exception vector (`vbar_el1`), which we'll see more about
|
||||
later.
|
||||
- All examples this afternoon assume we will be running at exception level 1
|
||||
(EL1). If you need to run at a different exception level you'll need to modify
|
||||
`entry.S` accordingly.
|
||||
(EL1). If you need to run at a different exception level, you'll need to
|
||||
modify `entry.S` accordingly.
|
||||
|
||||
</details>
|
||||
|
@@ -16,7 +16,7 @@ for all these functions.)
|
||||
- PSCI is the Arm Power State Coordination Interface, a standard set of
|
||||
functions to manage system and CPU power states, among other things. It is
|
||||
implemented by EL3 firmware and hypervisors on many systems.
|
||||
- The `0 => _` syntax means initialise the register to 0 before running the
|
||||
- The `0 => _` syntax means initialize the register to 0 before running the
|
||||
inline assembly code, and ignore its contents afterwards. We need to use
|
||||
`inout` rather than `in` because the call could potentially clobber the
|
||||
contents of the registers.
|
||||
@@ -24,7 +24,7 @@ for all these functions.)
|
||||
because it is called from our entry point in `entry.S`.
|
||||
- Just `#[no_mangle]` would be sufficient but
|
||||
[RFC3325](https://rust-lang.github.io/rfcs/3325-unsafe-attributes.html) uses
|
||||
this notation to draw reviewer attention to attributes which might cause
|
||||
this notation to draw reviewer attention to attributes that might cause
|
||||
undefined behavior if used incorrectly.
|
||||
- `_x0`–`_x3` are the values of registers `x0`–`x3`, which are conventionally
|
||||
used by the bootloader to pass things like a pointer to the device tree.
|
||||
|
@@ -9,7 +9,7 @@ We can do this by implementing the `Log` trait.
|
||||
|
||||
<details>
|
||||
|
||||
- The first unwrap in `log` will succeed because we initialise `LOGGER` before
|
||||
- The first unwrap in `log` will succeed because we initialize `LOGGER` before
|
||||
calling `set_logger`. The second will succeed because `Uart::write_str` always
|
||||
returns `Ok`.
|
||||
|
||||
|
@@ -28,7 +28,7 @@ unsafe {
|
||||
compiler may assume that the value read is the same as the value just
|
||||
written, and not bother actually reading memory.
|
||||
- Some existing crates for volatile access to hardware do hold references, but
|
||||
this is unsound. Whenever a reference exist, the compiler may choose to
|
||||
this is unsound. Whenever a reference exists, the compiler may choose to
|
||||
dereference it.
|
||||
- Use `&raw` to get struct field pointers from a pointer to the struct.
|
||||
- For compatibility with old versions of Rust you can use the [`addr_of!`] macro
|
||||
|
@@ -5,9 +5,9 @@
|
||||
- Supports x86, aarch64 and RISC-V.
|
||||
- Relies on LinuxBoot rather than having many drivers itself.
|
||||
- [Rust RaspberryPi OS tutorial](https://github.com/rust-embedded/rust-raspberrypi-OS-tutorials)
|
||||
- Initialisation, UART driver, simple bootloader, JTAG, exception levels,
|
||||
- Initialization, UART driver, simple bootloader, JTAG, exception levels,
|
||||
exception handling, page tables.
|
||||
- Some dodginess around cache maintenance and initialisation in Rust, not
|
||||
- Some caveats around cache maintenance and initialization in Rust, not
|
||||
necessarily a good example to copy for production code.
|
||||
- [`cargo-call-stack`](https://crates.io/crates/cargo-call-stack)
|
||||
- Static analysis to determine maximum stack usage.
|
||||
|
@@ -17,14 +17,14 @@ Now let's use the new `Registers` struct in our driver.
|
||||
- These MMIO accesses are generally a wrapper around `read_volatile` and
|
||||
`write_volatile`, though on aarch64 they are instead implemented in assembly
|
||||
to work around a bug where the compiler can emit instructions that prevent
|
||||
MMIO virtualisation.
|
||||
MMIO virtualization.
|
||||
- The `field!` and `field_shared!` macros internally use `&raw mut` and
|
||||
`&raw const` to get pointers to individual fields without creating an
|
||||
intermediate reference, which would be unsound.
|
||||
- `field!` needs a mutable reference to a `UniqueMmioPointer`, and returns a
|
||||
`UniqueMmioPointer` which allows reads with side effects and writes.
|
||||
`UniqueMmioPointer` that allows reads with side effects and writes.
|
||||
- `field_shared!` works with a shared reference to either a `UniqueMmioPointer`
|
||||
or a `SharedMmioPointer`. It returns a `SharedMmioPointer` which only allows
|
||||
or a `SharedMmioPointer`. It returns a `SharedMmioPointer` that only allows
|
||||
pure reads.
|
||||
|
||||
</details>
|
||||
|
@@ -1,6 +1,6 @@
|
||||
# safe-mmio
|
||||
|
||||
The [`safe-mmio`] crate provides types to wrap registers which can be read or
|
||||
The [`safe-mmio`] crate provides types to wrap registers that can be read or
|
||||
written safely.
|
||||
|
||||
| | Can't read | Read has no side-effects | Read has side-effects |
|
||||
@@ -23,7 +23,7 @@ written safely.
|
||||
operations; we recommend the `safe-mmio` crate.
|
||||
- The difference between `ReadPure` or `ReadOnly` (and likewise between
|
||||
`ReadPureWrite` and `ReadWrite`) is whether reading a register can have
|
||||
side-effects which change the state of the device. E.g. reading the data
|
||||
side-effects that change the state of the device, e.g., reading the data
|
||||
register pops a byte from the receive FIFO. `ReadPure` means that reads have
|
||||
no side-effects, they are purely reading data.
|
||||
|
||||
|
@@ -12,7 +12,7 @@ for convenience.
|
||||
<details>
|
||||
|
||||
- In this case the board support crate is just providing more useful names, and
|
||||
a bit of initialisation.
|
||||
a bit of initialization.
|
||||
- The crate may also include drivers for some on-board devices outside of the
|
||||
microcontroller itself.
|
||||
- `microbit-v2` includes a simple driver for the LED matrix.
|
||||
|
@@ -16,8 +16,8 @@ accelerometer driver might need an I2C or SPI device instance.
|
||||
|
||||
<details>
|
||||
|
||||
- The traits cover using the peripherals but not initialising or configuring
|
||||
them, as initialisation and configuration is usually highly platform-specific.
|
||||
- The traits cover using the peripherals but not initializing or configuring
|
||||
them, as initialization and configuration is usually highly platform-specific.
|
||||
- There are implementations for many microcontrollers, as well as other
|
||||
platforms such as Linux on Raspberry Pi.
|
||||
- [`embedded-hal-async`] provides async versions of the traits.
|
||||
|
@@ -11,12 +11,11 @@ wrappers for memory-mapped peripherals from
|
||||
<details>
|
||||
|
||||
- SVD (System View Description) files are XML files typically provided by
|
||||
silicon vendors which describe the memory map of the device.
|
||||
- They are organised by peripheral, register, field and value, with names,
|
||||
silicon vendors that describe the memory map of the device.
|
||||
- They are organized by peripheral, register, field and value, with names,
|
||||
descriptions, addresses and so on.
|
||||
- SVD files are often buggy and incomplete, so there are various projects
|
||||
which patch the mistakes, add missing details, and publish the generated
|
||||
crates.
|
||||
- SVD files are often buggy and incomplete, so there are various projects that
|
||||
patch the mistakes, add missing details, and publish the generated crates.
|
||||
- `cortex-m-rt` provides the vector table, among other things.
|
||||
- If you `cargo install cargo-binutils` then you can run
|
||||
`cargo objdump --bin pac -- -d --no-show-raw-insn` to see the resulting
|
||||
|
@@ -21,7 +21,7 @@ in your project directory.
|
||||
a range from SEGGER.
|
||||
- The Debug Access Port is usually either a 5-pin JTAG interface or 2-pin Serial
|
||||
Wire Debug.
|
||||
- probe-rs is a library which you can integrate into your own tools if you want
|
||||
- probe-rs is a library that you can integrate into your own tools if you want
|
||||
to.
|
||||
- The
|
||||
[Microsoft Debug Adapter Protocol](https://microsoft.github.io/debug-adapter-protocol/)
|
||||
@@ -29,6 +29,6 @@ in your project directory.
|
||||
microcontroller.
|
||||
- cargo-embed is a binary built using the probe-rs library.
|
||||
- RTT (Real Time Transfers) is a mechanism to transfer data between the debug
|
||||
host and the target through a number of ringbuffers.
|
||||
host and the target through a number of ring buffers.
|
||||
|
||||
</details>
|
||||
|
@@ -7,12 +7,12 @@
|
||||
<details>
|
||||
|
||||
- Pins don't implement `Copy` or `Clone`, so only one instance of each can
|
||||
exist. Once a pin is moved out of the port struct nobody else can take it.
|
||||
exist. Once a pin is moved out of the port struct, nobody else can take it.
|
||||
- Changing the configuration of a pin consumes the old pin instance, so you
|
||||
can’t keep use the old instance afterwards.
|
||||
- The type of a value indicates the state that it is in: e.g. in this case, the
|
||||
can't use the old instance afterwards.
|
||||
- The type of a value indicates the state it is in: e.g., in this case, the
|
||||
configuration state of a GPIO pin. This encodes the state machine into the
|
||||
type system, and ensures that you don't try to use a pin in a certain way
|
||||
type system and ensures that you don't try to use a pin in a certain way
|
||||
without properly configuring it first. Illegal state transitions are caught at
|
||||
compile time.
|
||||
- You can call `is_high` on an input pin and `set_high` on an output pin, but
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# Useful crates
|
||||
|
||||
We'll look at a few crates which solve some common problems in bare-metal
|
||||
We'll look at a few crates that solve some common problems in bare-metal
|
||||
programming.
|
||||
|
@@ -1,6 +1,6 @@
|
||||
# `buddy_system_allocator`
|
||||
|
||||
[`buddy_system_allocator`][1] is a crate implementing a basic buddy system
|
||||
[`buddy_system_allocator`][1] is a crate that implements a basic buddy system
|
||||
allocator. It can be used both to implement [`GlobalAlloc`][3] (using
|
||||
[`LockedHeap`][2]) so you can use the standard `alloc` crate (as we saw
|
||||
[before][4]), or for allocating other address space (using
|
||||
|
@@ -25,8 +25,8 @@ fn main() {
|
||||
|
||||
- Be careful to avoid deadlock if you take locks in interrupt handlers.
|
||||
- `spin` also has a ticket lock mutex implementation; equivalents of `RwLock`,
|
||||
`Barrier` and `Once` from `std::sync`; and `Lazy` for lazy initialisation.
|
||||
- The [`once_cell`][2] crate also has some useful types for late initialisation
|
||||
`Barrier` and `Once` from `std::sync`; and `Lazy` for lazy initialization.
|
||||
- The [`once_cell`][2] crate also has some useful types for late initialization
|
||||
with a slightly different approach to `spin::once::Once`.
|
||||
- The Rust Playground includes `spin`, so this example will run fine inline.
|
||||
|
||||
|
@@ -1,8 +1,8 @@
|
||||
# `tinyvec`
|
||||
|
||||
Sometimes you want something which can be resized like a `Vec`, but without heap
|
||||
Sometimes you want something that can be resized like a `Vec`, but without heap
|
||||
allocation. [`tinyvec`][1] provides this: a vector backed by an array or slice,
|
||||
which could be statically allocated or on the stack, which keeps track of how
|
||||
which could be statically allocated or on the stack, that keeps track of how
|
||||
many elements are used and panics if you try to use more than are allocated.
|
||||
|
||||
<!-- mdbook-xgettext: skip -->
|
||||
@@ -23,7 +23,7 @@ fn main() {
|
||||
<details>
|
||||
|
||||
- `tinyvec` requires that the element type implement `Default` for
|
||||
initialisation.
|
||||
initialization.
|
||||
- The Rust Playground includes `tinyvec`, so this example will run fine inline.
|
||||
|
||||
</details>
|
||||
|
Reference in New Issue
Block a user