ドライバ

では、ドライバで新しい Registers 構造体を使ってみましょう。

// 著作権 2025 Google LLC
// SPDX-License-Identifier: Apache-2.0

use safe_mmio::{UniqueMmioPointer, field, field_shared};

/// Driver for a PL011 UART.
#[derive(Debug)]
pub struct Uart<'a> {
    registers: UniqueMmioPointer<'a, Registers>,
}

impl<'a> Uart<'a> {
    /// Constructs a new instance of the UART driver for a PL011 device with the
    /// given set of registers.
    pub fn new(registers: UniqueMmioPointer<'a, Registers>) -> Self {
        Self { registers }
    }

    /// Writes a single byte to the UART.
    pub fn write_byte(&mut self, byte: u8) {
        // Wait until there is room in the TX buffer.
        while self.read_flag_register().contains(Flags::TXFF) {}

        // Write to the TX buffer.
        field!(self.registers, dr).write(byte.into());

        // Wait until the UART is no longer busy.
        while self.read_flag_register().contains(Flags::BUSY) {}
    }

    /// Reads and returns a pending byte, or `None` if nothing has been
    /// received.
    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: Check for error conditions in bits 8-11.
            Some(data as u8)
        }
    }

    fn read_flag_register(&self) -> Flags {
        field_shared!(self.registers, fr).read()
    }
}
  • このドライバでは、もはや unsafe コードは必要ありません!
  • UniqueMmioPointer は、MMIO デバイスまたはレジスタへの生ポインタをラップするものです。UniqueMmioPointer::new の呼び出し元は、それが指定されたライフタイムの間に有効で一意であることを保証するため、フィールドを安全に読み書きするメソッドを提供できます。
  • Uart::new は現在では safe であり、代わりに UniqueMmioPointer::new が unsafe であることに注意してください。
  • これらの MMIO アクセスは一般に read_volatilewrite_volatile のラッパーですが、aarch64 では代わりにアセンブリで実装されています。これは、コンパイラが MMIO 仮想化を妨げる命令を出力してしまうバグを回避するためです。
  • field! および field_shared! マクロは内部で &raw mut&raw const を使用して、中間参照を作成せずに個々のフィールドへのポインタを取得します。中間参照を作成すると不健全になるためです。
  • field!UniqueMmioPointer への可変参照を必要とし、副作用を伴う読み取りと書き込みを許可する UniqueMmioPointer を返します。
  • field_shared! は、UniqueMmioPointer または SharedMmioPointer のいずれかへの共有参照で動作します。これは、純粋な読み取りのみを許可する SharedMmioPointer を返します。