Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

بیایید یک درایور UART بنویسیم

این ماشین QEMU ‘virt’ یک PL011 به‌عنوان UART دارد، پس بیایید یک درایور برای آن بنویسیم.

const FLAG_REGISTER_OFFSET: usize = 0x18;
const FR_BUSY: u8 = 1 << 3;
const FR_TXFF: u8 = 1 << 5;

/// Minimal driver for a PL011 UART.
#[derive(Debug)]
pub struct Uart {
    base_address: *mut u8,
}

impl Uart {
    /// Constructs a new instance of the UART driver for a PL011 device at the
    /// given base address.
    ///
    /// # Safety
    ///
    /// The given base address 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(base_address: *mut u8) -> Self {
        Self { base_address }
    }

    /// Writes a single byte to the UART.
    pub fn write_byte(&self, byte: u8) {
        // Wait until there is room in the TX buffer.
        while self.read_flag_register() & FR_TXFF != 0 {}

        // SAFETY: We know that the base address points to the control
        // registers of a PL011 device which is appropriately mapped.
        unsafe {
            // Write to the TX buffer.
            self.base_address.write_volatile(byte);
        }

        // Wait until the UART is no longer busy.
        while self.read_flag_register() & FR_BUSY != 0 {}
    }

    fn read_flag_register(&self) -> u8 {
        // SAFETY: We know that the base address points to the control
        // registers of a PL011 device which is appropriately mapped.
        unsafe { self.base_address.add(FLAG_REGISTER_OFFSET).read_volatile() }
    }
}
  • توجه داشته باشید که Uart::new ناامن یا unsafe است در حالی که متد‌های دیگر ایمن هستند. این به‌خاطر این است که تا زمانی که تماس گیرنده Uart::new تضمین کند که الزامات ایمنی آن برآورده شده است (یعنی فقط یک نمونه از درایور برای یک UART مشخص وجود دارد و هیچ چیز دیگری نام مستعار فضای آدرس آن را ندارد)، پس همیشه می‌توان write_byte را بعداً فراخوانی کرد زیرا می‌توانیم پیش‌شرط‌های لازم را فرض کنیم.
  • ما می‌توانستیم این کار را به صورت دیگری انجام دهیم ( ساخت new را ایمن کنیم، اما write_byte را ناامن کنیم)، اما استفاده از آن بسیار راحت‌تر خواهد بود، زیرا هر مکانی که write_byte را صدا می‌زند باید در مورد ایمنی یا safety استدلال کند.
  • This is a common pattern for writing safe wrappers of unsafe code: moving the burden of proof for soundness from a large number of places to a smaller number of places.