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只允许 纯读。
最后修改 August 11, 2026: 更新 (70a5af133)