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.