Driver
Agora vamos usar o novo struct Registers em nosso driver.
/// Driver para um UART PL011.
#[derive(Debug)]
pub struct Uart {
registers: *mut Registers,
}
impl Uart {
/// Constrói uma nova instância do driver UART para um dispositivo PL011 no endereço
/// base fornecido.
///
/// # Segurança
///
/// O endereço base fornecido deve apontar para os 8 registradores de controle MMIO de um
/// dispositivo PL011, que deve ser mapeado no espaço de endereços do processo
/// como memória de dispositivo e não ter nenhum outro alias.
pub unsafe fn new(base_address: *mut u32) -> Self {
Self { registers: base_address as *mut Registers }
}
/// Grava um único byte no UART.
pub fn write_byte(&self, byte: u8) {
// Aguarde até que haja espaço no buffer TX.
while self.read_flag_register().contains(Flags::TXFF) {}
// SEGURANÇA: Sabemos que self.registers aponta para os registradores
// de controle de um dispositivo PL011 que está mapeado adequadamente.
unsafe {
// Escreva no buffer TX.
addr_of_mut!((*self.registers).dr).write_volatile(byte.into());
}
// Aguarde até que o UART não esteja mais ocupado.
while self.read_flag_register().contains(Flags::BUSY) {}
}
/// Lê e retorna um byte pendente ou `None` se nada foi
/// recebido.
pub fn read_byte(&self) -> Option<u8> {
if self.read_flag_register().contains(Flags::RXFE) {
None
} else {
// SEGURANÇA: Sabemos que self.registers aponta para os registradores
// de controle de um dispositivo PL011 que está mapeado adequadamente.
let data = unsafe { addr_of!((*self.registers).dr).read_volatile() };
// TODO: Verifique as condições de erro nos bits 8-11.
Some(data as u8)
}
}
fn read_flag_register(&self) -> Flags {
// SEGURANÇA: Sabemos que self.registers aponta para os registradores
// de controle de um dispositivo PL011 que está mapeado adequadamente.
unsafe { addr_of!((*self.registers).fr).read_volatile() }
}
}
- Observe o uso de
addr_of!/addr_of_mut!para obter ponteiros para campos individuais sem criar uma referência intermediária, o que seria incorreto.