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

Драйвер

Теперь используем новую структуру Registers в нашем драйвере.

// Copyright 2023 Google LLC
// SPDX-License-Identifier: Apache-2.0

/// Драйвер для UART PL011.
#[derive(Debug)]
pub struct Uart {
    registers: *mut Registers,
}

impl Uart {
    /// Создаёт новый экземпляр драйвера UART для устройства PL011 с
    /// заданным набором регистров.
    ///
    /// # Safety
    ///
    /// Заданный указатель должен указывать на 8 управляющих регистров MMIO
    /// устройства PL011, которые должны быть отображены в адресное пространство процесса как
    /// память устройства и не иметь других алиасов.
    pub unsafe fn new(registers: *mut Registers) -> Self {
        Self { registers }
    }

    /// Записывает один байт в UART.
    pub fn write_byte(&mut self, byte: u8) {
        // Ждём, пока в буфере передачи (TX) не появится место.
        while self.read_flag_register().contains(Flags::TXFF) {}

        // SAFETY: Мы знаем, что self.registers указывает на управляющие регистры
        // устройства PL011, которое корректно отображено.
        unsafe {
            // Записываем в буфер передачи (TX).
            (&raw mut (*self.registers).dr).write_volatile(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 {
            // SAFETY: Мы знаем, что self.registers указывает на управляющие
            // регистры устройства PL011, которое корректно отображено.
            let data = unsafe { (&raw const (*self.registers).dr).read_volatile() };
            // TODO: Проверить условия ошибок в битах 8–11.
            Some(data as u8)
        }
    }

    fn read_flag_register(&self) -> Flags {
        // SAFETY: Мы знаем, что self.registers указывает на управляющие регистры
        // устройства PL011, которое корректно отображено.
        unsafe { (&raw const (*self.registers).fr).read_volatile() }
    }
}
  • Обратите внимание на использование &raw const / &raw mut, чтобы получить указатели на отдельные поля без создания промежуточной ссылки, что было бы некорректно.
  • Пример не включён в слайды, потому что он очень похож на пример safe-mmio, который идёт следующим. При необходимости его можно запустить в QEMU командой make qemu в каталоге src/bare-metal/aps/examples.