From cb875cf54eabe71558ebd95feb2826d36283913f Mon Sep 17 00:00:00 2001 From: bunnie Date: Sun, 9 Apr 2023 22:15:57 +0800 Subject: [PATCH] various fixes to gdb-stub these are from @xobs via issue #361 --- kernel/src/debug/gdb.rs | 77 +++++++++++++++++++++--- kernel/src/platform/precursor/gdbuart.rs | 13 ++-- 2 files changed, 76 insertions(+), 14 deletions(-) diff --git a/kernel/src/debug/gdb.rs b/kernel/src/debug/gdb.rs index c39ec920e..55fd0e2ca 100644 --- a/kernel/src/debug/gdb.rs +++ b/kernel/src/debug/gdb.rs @@ -49,15 +49,78 @@ impl ProcessPid for XousTarget { } } -fn receive_irq(uart: &mut GdbUart) { - while let Some(c) = uart.getc() { - process_character(c); +struct MicroRingBuf { + buffer: [u8; N], + head: usize, + tail: usize, +} + +impl Default for MicroRingBuf { + fn default() -> Self { + MicroRingBuf { + buffer: [0u8; N], + head: 0, + tail: 0, + } + } +} + +impl MicroRingBuf { + // pub fn capacity(&self) -> usize { + // self.buffer.len() + // } + // pub fn len(&self) -> usize { + // self.head.wrapping_sub(self.tail) % N + // } + + pub fn is_full(&self) -> bool { + (self.tail.wrapping_sub(1) % N) == self.head } - // If the GDB server goes away for some reason, reconstitute it - unsafe { - if GDB_STATE.is_none() { - init(); + pub fn try_push(&mut self, val: u8) -> Result<(), ()> { + if self.is_full() { + return Err(()); + } + self.buffer[self.head] = val; + self.head = (self.head + 1) % N; + Ok(()) + } + + pub fn try_pop(&mut self) -> Option { + if self.tail == self.head { + return None; + } + let val = self.buffer[self.tail]; + self.tail = (self.tail + 1) % N; + Some(val) + } +} + +fn receive_irq(uart: &mut GdbUart) { + let mut buffer = MicroRingBuf::<32>::default(); + loop { + // Try to fill up the ring buffer with as many characters + // as can fit. This is to compensate for the fact that we do + // all of this processing in an interrupt context, and the + // hardware UART buffer is only a few characters deep. + while !buffer.is_full() { + if let Some(c) = uart.getc() { + buffer.try_push(c).ok(); + } else { + break; + } + } + + // If there is a character in the buffer, process it. Otherwise, + // we're done. + let Some(c) = buffer.try_pop() else { break }; + process_character(c); + + // If the GDB server goes away for some reason, reconstitute it + unsafe { + if GDB_STATE.is_none() { + init(); + } } } } diff --git a/kernel/src/platform/precursor/gdbuart.rs b/kernel/src/platform/precursor/gdbuart.rs index ef186efcd..b43764ec8 100644 --- a/kernel/src/platform/precursor/gdbuart.rs +++ b/kernel/src/platform/precursor/gdbuart.rs @@ -142,14 +142,13 @@ impl SerialRead for GdbUart { fn getc(&mut self) -> Option { // If EV_PENDING_RX is 1, return the pending character. // Otherwise, return None. - match self.uart_csr.rf(utra::app_uart::EV_PENDING_RX) { - 0 => None, - _ => { - let ret = Some(self.uart_csr.r(utra::app_uart::RXTX) as u8); - self.uart_csr.wfo(utra::app_uart::EV_PENDING_RX, 1); - ret - } + if self.uart_csr.r(utra::app_uart::RXEMPTY) != 0 { + return None; } + + let ret = self.uart_csr.r(utra::app_uart::RXTX) as u8; + self.uart_csr.wfo(utra::app_uart::EV_PENDING_RX, 1); + Some(ret) } }