Skip to content

Commit fa9d037

Browse files
authored
Merge pull request #92 from noncombatant/master
A variety of minor cleanups
2 parents 052fd35 + e0d90ca commit fa9d037

File tree

9 files changed

+65
-59
lines changed

9 files changed

+65
-59
lines changed

ci/dma/src/lib.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ pub struct Dma1Channel1 {
1313
impl Dma1Channel1 {
1414
/// Data will be written to this `address`
1515
///
16-
/// `inc` indicates whether the address will be incremented after every byte transfer
16+
/// `inc` indicates whether the address will be incremented after every byte
17+
/// transfer
1718
///
1819
/// NOTE this performs a volatile write
1920
pub fn set_destination_address(&mut self, address: usize, inc: bool) {
@@ -22,7 +23,8 @@ impl Dma1Channel1 {
2223

2324
/// Data will be read from this `address`
2425
///
25-
/// `inc` indicates whether the address will be incremented after every byte transfer
26+
/// `inc` indicates whether the address will be incremented after every byte
27+
/// transfer
2628
///
2729
/// NOTE this performs a volatile write
2830
pub fn set_source_address(&mut self, address: usize, inc: bool) {

ci/singleton/app/src/main.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ fn main() -> ! {
2929
impl GlobalLog for Logger {
3030
fn log(&self, address: u8) {
3131
// we use a critical section (`interrupt::free`) to make the access to the
32-
// `static mut` variable interrupt safe which is required for memory safety
32+
// `static mut` variable interrupt-safe which is required for memory safety
3333
interrupt::free(|_| unsafe {
3434
static mut HSTDOUT: Option<HStdout> = None;
3535

@@ -41,6 +41,7 @@ impl GlobalLog for Logger {
4141
let hstdout = HSTDOUT.as_mut().unwrap();
4242

4343
hstdout.write_all(&[address])
44-
}).ok(); // `.ok()` = ignore errors
44+
})
45+
.ok(); // `.ok()` = ignore errors
4546
}
4647
}

src/asm.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
So far we have managed to boot the device and handle interrupts without a single
1010
line of assembly. That's quite a feat! But depending on the architecture you are
1111
targeting you may need some assembly to get to this point. There are also some
12-
operations like context switching that require assembly, etc.
12+
operations, for example context switching, that require assembly.
1313

1414
The problem is that both *inline* assembly (`asm!`) and *free form* assembly
1515
(`global_asm!`) are unstable, and there's no estimate for when they'll be
@@ -97,7 +97,7 @@ $ cargo objdump --bin app --release -- -d --no-show-raw-insn --print-imm-hex
9797
```
9898

9999
> **NOTE:** To make this disassembly smaller I commented out the initialization
100-
> of RAM
100+
> of RAM.
101101
102102
Now look at the vector table. The 4th entry should be the address of
103103
`HardFaultTrampoline` plus one.

src/compiler-support.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ following command:
2020

2121
``` console
2222
$ # you need to have `cargo-binutils` installed to run this command
23-
$ cargo objdump -- -version
23+
$ cargo objdump -- --version
2424
LLVM (http://llvm.org/):
2525
LLVM version 7.0.0svn
2626
Optimized build.
@@ -68,7 +68,7 @@ to replace the original version of LLVM with the fork before building `rustc`. T
6868
allows this and in principle it should just require changing the `llvm` submodule to point to the
6969
fork.
7070

71-
If your target architecture is only supported by some vendor provided GCC, you have the option of
71+
If your target architecture is only supported by some vendor-provided GCC, you have the option of
7272
using [`mrustc`], an unofficial Rust compiler, to translate your Rust program into C code and then
7373
compile that using GCC.
7474

src/custom-target.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
# Creating a custom target
22

33
If a custom target triple is not available for your platform, you must create a custom target file
4-
that describes your target to rustc.
4+
that describes your target to `rustc`.
55

66
Keep in mind that it is required to use a nightly compiler to build the core library, which must be
7-
done for a target unknown to rustc.
7+
done for a target unknown to `rustc`.
88

99
## Deciding on a target triple
1010

@@ -65,15 +65,15 @@ You can pretty much copy that output into your file. Start with a few modificati
6565
- I have no native atomic operations, but I can emulate them myself: set `max-atomic-width` to the
6666
highest number of bits that you can emulate up to 128, then implement all of the
6767
[atomic][libcalls-atomic] and [sync][libcalls-sync] functions expected by LLVM as
68-
`#[no_mangle] unsafe extern "C"`. These functions have been standardized by gcc, so the [gcc
68+
`#[no_mangle] unsafe extern "C"`. These functions have been standardized by GCC, so the [GCC
6969
documentation][gcc-sync] may have more notes. Missing functions will cause a linker error, while
7070
incorrectly implemented functions will possibly cause UB. For example, if you have a
7171
single-core, single-thread processor with interrupts, you can implement these functions to
7272
disable interrupts, perform the regular operation, and then re-enable them.
7373
- I have no native atomic operations: you'll have to do some unsafe work to manually ensure
7474
synchronization in your code. You must set `"max-atomic-width": 0`.
7575
- Change the linker if integrating with an existing toolchain. For example, if you're using a
76-
toolchain that uses a custom build of gcc, set `"linker-flavor": "gcc"` and `linker` to the
76+
toolchain that uses a custom build of GCC, set `"linker-flavor": "gcc"` and `linker` to the
7777
command name of your linker. If you require additional linker arguments, use `pre-link-args` and
7878
`post-link-args` as so:
7979
``` json
@@ -96,8 +96,8 @@ You can pretty much copy that output into your file. Start with a few modificati
9696
(not including the version in the case of ARM) to list the available features and their
9797
descriptions. **If your target requires strict memory alignment access (e.g. `armv5te`), make sure
9898
that you enable `strict-align`**. To enable a feature, place a plus before it. Likewise, to
99-
disable a feature, place a minus before it. Features should be comma separated like so:
100-
`"features": "+soft-float,+neon`. Note that this may not be necessary if LLVM knows enough about
99+
disable a feature, place a minus before it. Features should be comma-separated like so:
100+
`"features": "+soft-float,+neon"`. Note that this may not be necessary if LLVM knows enough about
101101
your target based on the provided triple and CPU.
102102
- Configure the CPU that LLVM uses if you know it. This will enable CPU-specific optimizations and
103103
features. At the top of the output of the command in the last step, there is a list of known CPUs.
@@ -121,7 +121,7 @@ You can pretty much copy that output into your file. Start with a few modificati
121121
Once you have a target specification file, you may refer to it by its path or by its name (i.e.
122122
excluding `.json`) if it is in the current directory or in `$RUST_TARGET_PATH`.
123123

124-
Verify that it is readable by rustc:
124+
Verify that it is readable by `rustc`:
125125

126126
``` sh
127127
❱ rustc --print cfg --target foo.json # or just foo if in the current directory

src/dma.md

Lines changed: 33 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ DMA transfers.
66
The DMA peripheral is used to perform memory transfers in parallel to the work
77
of the processor (the execution of the main program). A DMA transfer is more or
88
less equivalent to spawning a thread (see [`thread::spawn`]) to do a `memcpy`.
9-
We'll use the fork-join model to illustrate the requirements of a memory safe
9+
We'll use the fork-join model to illustrate the requirements of a memory-safe
1010
API.
1111

1212
[`thread::spawn`]: https://doc.rust-lang.org/std/thread/fn.spawn.html
@@ -28,11 +28,11 @@ Assume that the `Dma1Channel1` is statically configured to work with serial port
2828
{{#include ../ci/dma/src/lib.rs:82:83}}
2929
```
3030

31-
Let's say we want to extend `Serial1` API to (a) asynchronously send out a
31+
Let's say we want to extend the `Serial1` API to (a) asynchronously send out a
3232
buffer and (b) asynchronously fill a buffer.
3333

34-
We'll start with a memory unsafe API and we'll iterate on it until it's
35-
completely memory safe. On each step we'll show you how the API can be broken to
34+
We'll start with a memory-unsafe API and we'll iterate on it until it's
35+
completely memory-safe. At each step we'll show you how the API can be broken to
3636
make you aware of the issues that need to be addressed when dealing with
3737
asynchronous memory operations.
3838

@@ -47,7 +47,7 @@ keep things simple let's ignore all error handling.
4747
{{#include ../ci/dma/examples/one.rs:7:47}}
4848
```
4949

50-
> **NOTE:** `Transfer` could expose a futures or generator based API instead of
50+
> **NOTE:** `Transfer` could expose a futures- or generator-based API instead of
5151
> the API shown above. That's an API design question that has little bearing on
5252
> the memory safety of the overall API so we won't delve into it in this text.
5353
@@ -95,11 +95,13 @@ variables `x` and `y` changing their value at random times. The DMA transfer
9595
could also overwrite the state (e.g. link register) pushed onto the stack by the
9696
prologue of function `bar`.
9797

98-
Note that if we had not use `mem::forget`, but `mem::drop`, it would have been
99-
possible to make `Transfer`'s destructor stop the DMA transfer and then the
100-
program would have been safe. But one can *not* rely on destructors running to
101-
enforce memory safety because `mem::forget` and memory leaks (see RC cycles) are
102-
safe in Rust.
98+
Note that if we had used `mem::drop` instead of `mem::forget`, it would have
99+
been possible to make `Transfer`'s destructor stop the DMA transfer and then the
100+
program would have been safe. But one *cannot* rely on destructors running to
101+
enforce memory safety because `mem::forget` and memory leaks (see `Rc` cycles)
102+
are safe in Rust. (Refer to [`mem::forget` safety].)
103+
104+
[`mem::forget` safety]: https://doc.rust-lang.org/std/mem/fn.forget.html#safety
103105

104106
We can fix this particular problem by changing the lifetime of the buffer from
105107
`'a` to `'static` in both APIs.
@@ -164,7 +166,7 @@ result in a data race: both the processor and the DMA would end up modifying
164166
`buf` at the same time. Similarly the compiler can move the zeroing operation to
165167
after `read_exact`, which would also result in a data race.
166168

167-
To prevent these problematic reorderings we can use a [`compiler_fence`]
169+
To prevent these problematic reorderings we can use a [`compiler_fence`].
168170

169171
[`compiler_fence`]: https://doc.rust-lang.org/core/sync/atomic/fn.compiler_fence.html
170172

@@ -188,29 +190,29 @@ orderings in the comments.
188190
{{#include ../ci/dma/examples/four.rs:68:87}}
189191
```
190192

191-
The zeroing operation can *not* be moved *after* `read_exact` due to the
192-
`Release` fence. Similarly, the `reverse` operation can *not* be moved *before*
193+
The zeroing operation *cannot* be moved *after* `read_exact` due to the
194+
`Release` fence. Similarly, the `reverse` operation *cannot* be moved *before*
193195
`wait` due to the `Acquire` fence. The memory operations *between* both fences
194196
*can* be freely reordered across the fences but none of those operations
195197
involves `buf` so such reorderings do *not* result in undefined behavior.
196198

197199
Note that `compiler_fence` is a bit stronger than what's required. For example,
198200
the fences will prevent the operations on `x` from being merged even though we
199201
know that `buf` doesn't overlap with `x` (due to Rust aliasing rules). However,
200-
there exist no intrinsic that's more fine grained than `compiler_fence`.
202+
there exists no intrinsic that's more fine grained than `compiler_fence`.
201203

202204
### Don't we need a memory barrier?
203205

204206
That depends on the target architecture. In the case of Cortex M0 to M4F cores,
205207
[AN321] says:
206208

207-
[AN321]: https://static.docs.arm.com/dai0321/a/DAI0321A_programming_guide_memory_barriers_for_m_profile.pdf
209+
[AN321]: https://documentation-service.arm.com/static/5efefb97dbdee951c1cd5aaf
208210

209211
> 3.2 Typical usages
210212
>
211213
> (..)
212214
>
213-
> The use of DMB is rarely needed in Cortex-M processors because they do not
215+
> The use of `DMB` is rarely needed in Cortex-M processors because they do not
214216
> reorder memory transactions. However, it is needed if the software is to be
215217
> reused on other ARM processors, especially multi-master systems. For example:
216218
>
@@ -223,25 +225,26 @@ That depends on the target architecture. In the case of Cortex M0 to M4F cores,
223225
>
224226
> (..)
225227
>
226-
> Omitting the DMB or DSB instruction in the examples in Figure 41 on page 47
227-
> and Figure 42 would not cause any error because the Cortex-M processors:
228+
> Omitting the `DMB` or `DSB` instruction in the examples in Figure 41 on page
229+
> 47 and Figure 42 would not cause any error because the Cortex-M processors:
228230
>
229231
> - do not re-order memory transfers
230232
> - do not permit two write transfers to be overlapped.
231233
232-
Where Figure 41 shows a DMB (memory barrier) instruction being used before
234+
Where Figure 41 shows a `DMB` (memory barrier) instruction being used before
233235
starting a DMA transaction.
234236

235-
In the case of Cortex-M7 cores you'll need memory barriers (DMB/DSB) if you are
236-
using the data cache (DCache), unless you manually invalidate the buffer used by
237-
the DMA. Even with the data cache disabled, memory barriers might still be
238-
required to avoid reordering in the store buffer.
237+
In the case of Cortex-M7 cores you'll need memory barriers (`DMB`/`DSB`) if you
238+
are using the data cache (DCache), unless you manually invalidate the buffer
239+
used by the DMA. Even with the data cache disabled, memory barriers might still
240+
be required to avoid reordering in the store buffer.
239241

240242
If your target is a multi-core system then it's very likely that you'll need
241243
memory barriers.
242244

243245
If you do need the memory barrier then you need to use [`atomic::fence`] instead
244-
of `compiler_fence`. That should generate a DMB instruction on Cortex-M devices.
246+
of `compiler_fence`. That should generate a `DMB` instruction on Cortex-M
247+
devices.
245248

246249
[`atomic::fence`]: https://doc.rust-lang.org/core/sync/atomic/fn.fence.html
247250

@@ -282,7 +285,7 @@ pointer used in `read_exact` will become invalidated. You'll end up with a
282285
situation similar to the [`unsound`](#dealing-with-memforget) example.
283286

284287
To avoid this problem we require that the buffer used with our API retains its
285-
memory location even when it's moved. The [`Pin`] newtype provides such
288+
memory location even when it's moved. The [`Pin`] newtype provides such a
286289
guarantee. We can update our API to required that all buffers are "pinned"
287290
first.
288291

@@ -347,7 +350,7 @@ over. For example, dropping a `Transfer<Box<[u8]>>` value will cause the buffer
347350
to be deallocated. This can result in undefined behavior if the transfer is
348351
still in progress as the DMA would end up writing to deallocated memory.
349352

350-
In such scenario one option is to make `Transfer.drop` stop the DMA transfer.
353+
In such a scenario one option is to make `Transfer.drop` stop the DMA transfer.
351354
The other option is to make `Transfer.drop` wait for the transfer to finish.
352355
We'll pick the former option as it's cheaper.
353356

@@ -365,8 +368,8 @@ Now the DMA transfer will be stopped before the buffer is deallocated.
365368

366369
## Summary
367370

368-
To sum it up, we need to consider all the following points to achieve memory
369-
safe DMA transfers:
371+
To sum it up, we need to consider all the following points to achieve
372+
memory-safe DMA transfers:
370373

371374
- Use immovable buffers plus indirection: `Pin<B>`. Alternatively, you can use
372375
the `StableDeref` trait.
@@ -381,8 +384,8 @@ safe DMA transfers:
381384

382385
---
383386

384-
This text leaves out up several details required to build a production grade
385-
DMA abstraction, like configuring the DMA channels (e.g. streams, circular vs
387+
This text leaves out several details required to build a production-grade DMA
388+
abstraction, like configuring the DMA channels (e.g. streams, circular vs
386389
one-shot mode, etc.), alignment of buffers, error handling, how to make the
387390
abstraction device-agnostic, etc. All those aspects are left as an exercise for
388391
the reader / community (`:P`).

src/exceptions.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ matches the name we used in `EXCEPTIONS`.
200200
{{#include ../ci/exceptions/app2/src/main.rs}}
201201
```
202202

203-
You can test it in QEMU
203+
You can test it in QEMU:
204204

205205
``` console
206206
(gdb) target remote :3333

src/logging.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ the `static` variables but their addresses.
5252
As long as the `static` variables are not zero sized each one will have a
5353
different address. What we're doing here is effectively encoding each message
5454
into a unique identifier, which happens to be the variable address. Some part of
55-
the log system will have to decode this id back into the message.
55+
the log system will have to decode this ID back into the message.
5656

5757
Let's write some code to illustrate the idea.
5858

@@ -104,8 +104,8 @@ $ qemu-system-arm \
104104
{{#include ../ci/logging/app/dev.out}}
105105
```
106106

107-
> **NOTE**: These addresses may not be the ones you get locally because
108-
> addresses of `static` variable are not guaranteed to remain the same when the
107+
> **NOTE**: These addresses may not be the ones you get locally because the
108+
> addresses of `static` variables are not guaranteed to remain the same when the
109109
> toolchain is changed (e.g. optimizations may have improved).
110110
111111
Now we have two addresses printed to the console.
@@ -128,11 +128,11 @@ $ # first column is the symbol address; last column is the symbol name
128128
we are only looking for the ones in the `.rodata` section and whose size is one
129129
byte (our variables have type `u8`).
130130

131-
It's important to note that the address of the symbols will likely change when
131+
It's important to note that the addresses of the symbols will likely change when
132132
optimizing the program. Let's check that.
133133

134134
> **PROTIP** You can set `target.thumbv7m-none-eabi.runner` to the long QEMU
135-
> command from before (`qemu-system-arm -cpu (..) -kernel`) in the Cargo
135+
> command from before (`qemu-system-arm -cpu ... -kernel ...`) in the Cargo
136136
> configuration file (`.cargo/config.toml`) to have `cargo run` use that *runner* to
137137
> execute the output binary.
138138
@@ -173,8 +173,9 @@ an exercise for the reader.
173173
Can we do better? Yes, we can!
174174

175175
The current implementation places the `static` variables in `.rodata`, which
176-
means they occupy size in Flash even though we never use their contents. Using a
177-
little bit of linker script magic we can make them occupy *zero* space in Flash.
176+
means they occupy space in flash even though we never use their contents. Using
177+
a little bit of linker script magic we can make them occupy *zero* space in
178+
flash.
178179

179180
``` console
180181
$ cat log.x
@@ -199,8 +200,7 @@ We also specified the start address of this output section: the `0` in `.log 0
199200
(INFO)`.
200201

201202
The other improvement we can do is switch from formatted I/O (`fmt::Write`) to
202-
binary I/O, that is send the addresses to the host as bytes rather than as
203-
strings.
203+
binary I/O, sending the addresses to the host as bytes rather than as strings.
204204

205205
Binary serialization can be hard but we'll keep things super simple by
206206
serializing each address as a single byte. With this approach we don't have to

src/singleton.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ In this section we'll cover how to implement a global, shared singleton. The
44
embedded Rust book covered local, owned singletons which are pretty much unique
55
to Rust. Global singletons are essentially the singleton pattern you see in C
66
and C++; they are not specific to embedded development but since they involve
7-
symbols they seemed a good fit for the embedonomicon.
7+
symbols they seemed a good fit for the Embedonomicon.
88

99
> **TODO**(resources team) link "the embedded Rust book" to the singletons
1010
> section when it's up
@@ -16,7 +16,7 @@ section to support global logging. The result will be very similar to the
1616
> **TODO**(resources team) link `#[global_allocator]` to the collections chapter
1717
> of the book when it's in a more stable location.
1818
19-
Here's the summary of what we want to:
19+
Here's the summary of what we want to do:
2020

2121
In the last section we created a `log!` macro to log messages through a specific
2222
logger, a value that implements the `Log` trait. The syntax of the `log!` macro
@@ -26,9 +26,9 @@ message through a global logger; this is how `std::println!` works. We'll also
2626
need a mechanism to declare what the global logger is; this is the part that's
2727
similar to `#[global_allocator]`.
2828

29-
It could be that the global logger is declared in the top crate and it could
29+
It could be that the global logger is declared in the top crate, and it could
3030
also be that the type of the global logger is defined in the top crate. In this
31-
scenario the dependencies can *not* know the exact type of the global logger. To
31+
scenario the dependencies *cannot* know the exact type of the global logger. To
3232
support this scenario we'll need some indirection.
3333

3434
Instead of hardcoding the type of the global logger in the `log` crate we'll

0 commit comments

Comments
 (0)