1.6.1 司机
01-司机 — Comprehensive Rust
译文 · 基于 Comprehensive Rust
原文链接: https://google.github.io/comprehensive-rust/bare-metal/aps/safemmio/driver.html
1.6.1 司机
现在让我们使用新的Registers我们的驱动程序中的结构体。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
| // Copyright 2025 Google LLC
// SPDX-License-Identifier: Apache-2.0
use safe_mmio::{UniqueMmioPointer, field, field_shared};
/// PL011 UART 的驱动程序。
#[derive(Debug)]
pub struct Uart<'a> {
registers: UniqueMmioPointer<'a, Registers>,
}
impl<'a> Uart<'a> {
/// 为 PL011 设备构建 UART 驱动程序的新实例
/// 给定的一组寄存器。
pub fn new(registers: UniqueMmioPointer<'a, Registers>) -> Self {
Self { registers }
}
/// 将单个字节写入 UART。
pub fn write_byte(&mut self, byte: u8) {
// 等待,直到 TX 缓冲区中有空间。
while self.read_flag_register().contains(Flags::TXFF) {}
// 写入 TX 缓冲区。
field!(self.registers, dr).write(byte.into());
// 等待 UART 不再繁忙。
while self.read_flag_register().contains(Flags::BUSY) {}
}
/// 读取并返回一个待处理字节,或者`None`如果什么都没有
/// 已收到。
pub fn read_byte(&mut self) -> Option<u8> {
if self.read_flag_register().contains(Flags::RXFE) {
None
} else {
let data = field!(self.registers, dr).read();
// TODO:检查位 8-11 中的错误情况。
Some(data as u8)
}
}
fn read_flag_register(&self) -> Flags {
field_shared!(self.registers, fr).read()
}
}
|
- 驱动程序不再需要任何不安全的代码!
UniqueMmioPointer是指向 MMIO 设备的原始指针的包装器,或者
登记。来电者为UniqueMmioPointer::new承诺其有效并且
对于给定的生命周期是唯一的,因此它可以提供安全的方法来读取和
写入字段。- 注意
Uart::new现在安全了;UniqueMmioPointer::new反而不安全。 - 这些 MMIO 访问通常是一个包装器
read_volatile和
write_volatile,尽管在 aarch64 上它们是在汇编中实现的
解决编译器可以发出阻止的指令的错误
MMIO 虚拟化。 - 这
field!和field_shared!内部使用宏&raw mut和
&raw const获取指向各个字段的指针而不创建
中间参考,这是不合理的。 field!需要一个可变引用UniqueMmioPointer,并返回一个
UniqueMmioPointer允许有副作用的读取和写入。field_shared!使用对任一的共享引用UniqueMmioPointer
或一个SharedMmioPointer。它返回一个SharedMmioPointer只允许
纯读。