diff --git a/src/debug.rs b/src/debug.rs index 9ba51389..34062f6c 100644 --- a/src/debug.rs +++ b/src/debug.rs @@ -2,14 +2,30 @@ use core::fmt::{self, Arguments}; use abi::error::Error; -use kernel_util::util::StaticVector; +use alloc::sync::Arc; +use futures_util::Future; +use kernel_util::util::{OneTimeInit, StaticVector}; -use crate::{sync::IrqSafeSpinlock, task::process::Process}; +use crate::{ + sync::IrqSafeSpinlock, + task::{process::Process, runtime::QueueWaker}, + util::ring::RingBuffer, +}; const MAX_DEBUG_SINKS: usize = 4; +const RING_LOGGER_CAPACITY: usize = 65536; struct SimpleLogger; +struct RingLoggerInner { + data: RingBuffer, +} + +pub struct RingLoggerSink { + inner: IrqSafeSpinlock, + waker: QueueWaker, +} + /// Defines the severity of the message #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub enum LogLevel { @@ -151,11 +167,44 @@ impl fmt::Write for DebugSinkWrapper { } } +impl RingLoggerSink { + pub const fn new() -> Self { + Self { + inner: IrqSafeSpinlock::new(RingLoggerInner { + data: RingBuffer::new(0), + }), + waker: QueueWaker::new(), + } + } + + pub fn read(&self, pos: usize, buffer: &mut [u8]) -> usize { + unsafe { self.inner.lock().data.read_all_static(pos, buffer) } + } + + fn write_fmt(&self, args: fmt::Arguments<'_>) -> fmt::Result { + use fmt::Write; + self.inner.lock().write_fmt(args) + } +} + +impl fmt::Write for RingLoggerInner { + fn write_str(&mut self, s: &str) -> fmt::Result { + for ch in s.bytes() { + unsafe { + self.data.write_unchecked(ch); + } + } + Ok(()) + } +} + static LOGGER: SimpleLogger = SimpleLogger; static DEBUG_SINKS: IrqSafeSpinlock> = IrqSafeSpinlock::new(StaticVector::new()); +pub static RING_LOGGER_SINK: RingLoggerSink = RingLoggerSink::new(); + /// Prints a hex-dump of a slice, appending a virtual address offset to the output pub fn hex_dump(level: LogLevel, addr_offset: usize, data: &[u8]) { for (i, b) in data.iter().enumerate() { @@ -208,6 +257,8 @@ pub fn init() { pub fn debug_internal(args: Arguments, level: LogLevel) { use fmt::Write; + RING_LOGGER_SINK.write_fmt(args).ok(); + for sink in DEBUG_SINKS.lock().iter_mut() { if level < sink.level { continue; diff --git a/src/device/serial/pl011.rs b/src/device/serial/pl011.rs index 22136890..8fe55aac 100644 --- a/src/device/serial/pl011.rs +++ b/src/device/serial/pl011.rs @@ -192,7 +192,7 @@ impl Device for Pl011 { self.inner.init(IrqSafeSpinlock::new(inner)); - debug::add_sink(self, LogLevel::Debug); + // debug::add_sink(self, LogLevel::Debug); devfs::add_char_device(self, CharDeviceType::TtySerial)?; Ok(()) diff --git a/src/fs/sysfs.rs b/src/fs/sysfs.rs index 94b7194e..994574fe 100644 --- a/src/fs/sysfs.rs +++ b/src/fs/sysfs.rs @@ -12,7 +12,7 @@ use git_version::git_version; use kernel_util::util::OneTimeInit; use vfs::{Vnode, VnodeImpl, VnodeKind, VnodeRef, DIR_POSITION_FROM_CACHE}; -use crate::util; +use crate::{debug, util}; trait GetterFn = Fn() -> Result; trait ReaderFn = Fn(u64, &mut [u8]) -> Result; @@ -169,8 +169,7 @@ pub fn root() -> &'static VnodeRef { } fn read_kernel_log(pos: u64, buffer: &mut [u8]) -> Result { - // TODO actual kernel log buffer - todo!() + Ok(debug::RING_LOGGER_SINK.read(pos as usize, buffer)) } pub fn init() { diff --git a/src/util/ring.rs b/src/util/ring.rs index 9f903b04..41205e47 100644 --- a/src/util/ring.rs +++ b/src/util/ring.rs @@ -9,24 +9,36 @@ use futures_util::Future; use crate::{sync::IrqSafeSpinlock, task::runtime::QueueWaker}; -struct Inner { +pub struct RingBuffer { rd: usize, wr: usize, data: [T; N], } pub struct AsyncRing { - inner: Arc>>, + inner: Arc>>, read_waker: Arc, } -impl Inner { +impl RingBuffer { + pub const fn new(value: T) -> Self { + Self { + rd: 0, + wr: 0, + data: [value; N], + } + } + #[inline] const fn is_readable(&self) -> bool { - if self.rd <= self.wr { - (self.wr - self.rd) > 0 + self.is_readable_at(self.rd) + } + + const fn is_readable_at(&self, at: usize) -> bool { + if at <= self.wr { + (self.wr - at) > 0 } else { - (self.wr + (N - self.rd)) > 0 + (self.wr + (N - at)) > 0 } } @@ -37,8 +49,19 @@ impl Inner { res } + pub unsafe fn read_all_static(&mut self, pos: usize, buffer: &mut [T]) -> usize { + let mut pos = (self.rd + pos) % N; + let mut off = 0; + while off < buffer.len() && self.is_readable_at(pos) { + buffer[off] = self.data[pos]; + pos += 1; + off += 1; + } + off + } + #[inline] - unsafe fn write_unchecked(&mut self, ch: T) { + pub unsafe fn write_unchecked(&mut self, ch: T) { self.data[self.wr] = ch; self.wr = (self.wr + 1) % N; } @@ -47,11 +70,7 @@ impl Inner { impl AsyncRing { pub fn new(value: T) -> Self { Self { - inner: Arc::new(IrqSafeSpinlock::new(Inner { - rd: 0, - wr: 0, - data: [value; N], - })), + inner: Arc::new(IrqSafeSpinlock::new(RingBuffer::new(value))), read_waker: Arc::new(QueueWaker::new()), } } @@ -69,7 +88,7 @@ impl AsyncRing { pub fn read(&self) -> impl Future { struct ReadFuture { - inner: Arc>>, + inner: Arc>>, read_waker: Arc, }