ドライバ
それでは、ドライバで新しい Registers 構造体を使いましょう。
// Copyright 2023 Google LLC // SPDX-License-Identifier: Apache-2.0 /// Driver for a PL011 UART. #[derive(Debug)] pub struct Uart { registers: *mut Registers, } impl Uart { /// Constructs a new instance of the UART driver for a PL011 device with the /// given set of registers. /// /// # Safety /// /// The given pointer must point to the 8 MMIO control registers of a PL011 /// device, which must be mapped into the address space of the process as /// device memory and not have any other aliases. pub unsafe fn new(registers: *mut 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) {} // SAFETY: We know that self.registers points to the control registers // of a PL011 device which is appropriately mapped. unsafe { // Write to the TX buffer. (&raw mut (*self.registers).dr).write_volatile(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 { // SAFETY: We know that self.registers points to the control // registers of a PL011 device which is appropriately mapped. let data = unsafe { (&raw const (*self.registers).dr).read_volatile() }; // TODO: Check for error conditions in bits 8-11. Some(data as u8) } } fn read_flag_register(&self) -> Flags { // SAFETY: We know that self.registers points to the control registers // of a PL011 device which is appropriately mapped. unsafe { (&raw const (*self.registers).fr).read_volatile() } } }
- 個々のフィールドへのポインタを取得するために、中間の参照を作成せずに
&raw const/&raw mutを使っている点に注目してください。中間の参照を作成すると、不健全になります。 - この例は、次に出てくる
safe-mmioの例と非常によく似ているため、スライドには含まれていません。必要であれば、src/bare-metal/aps/examples配下でmake qemuを実行して QEMU 上で動かせます。