//! K403 guest observation: real PL011 UARTDR reads enter a bounded buffer. use super::*; use turkos_kernel::serial_rx::{CAPACITY, PushResult, RxBuffer}; const RXFE: u32 = 1 << 4; const DATA_ERROR: u32 = 0x0f00; fn fail(reason: &str) -> ! { write_str("TURKOS/SERIAL-RX-ERROR: "); write_line(reason); park() } fn ticks() -> u64 { let value: u64; unsafe { asm!("mrs {value}, CNTPCT_EL0", value = out(reg) value, options(nomem, nostack, preserves_flags)) }; value } pub(super) fn smoke_test() -> ! { let base = UART_BASE.load(Ordering::Relaxed); let frequency: u64; unsafe { asm!("mrs {value}, CNTFRQ_EL0", value = out(reg) frequency, options(nomem, nostack, preserves_flags)) }; if frequency == 0 { fail("zero counter frequency"); } let mut receive = RxBuffer::new(); write_line("TURKOS/SERIAL-RX: READY CAPACITY=0x10 EXPECTED=0x14"); for index in 0..20usize { let deadline = ticks() .checked_add(frequency.saturating_mul(5)) .unwrap_or(u64::MAX); while unsafe { read_volatile((base + 0x18) as *const u32) } & RXFE != 0 { if ticks() >= deadline { fail("input timeout"); } core::hint::spin_loop(); } let data = unsafe { read_volatile(base as *const u32) }; if data & DATA_ERROR != 0 { fail("PL011 data error"); } let byte = data as u8; let stored = receive.push(byte) == PushResult::Stored; write_str("TURKOS/SERIAL-RX-BYTE: INDEX=0x"); write_hex(index); write_str(" VALUE=0x"); write_hex(byte as usize); write_str(" STORED=0x"); write_hex(stored as usize); write_str(" LEN=0x"); write_hex(receive.len()); write_str(" DROPPED=0x"); write_hex(receive.dropped() as usize); write_str("\r\n"); } if receive.len() != CAPACITY || receive.dropped() != 4 { fail("buffer accounting"); } write_str("TURKOS/SERIAL-RX-TEXT: "); for expected in b"ABCDEFGHIJKLMNOP" { let byte = receive .pop() .unwrap_or_else(|| fail("missing buffered byte")); if byte != *expected { fail("buffered byte order/content"); } write_byte(byte); } write_str("\r\n"); if receive.pop().is_some() || receive.len() != 0 || receive.dropped() != 4 { fail("post-drain accounting"); } write_line("TURKOS/SERIAL-RX: PASS STORED=0x10 DROPPED=0x4 EMPTY=0x1"); park() }