fs: simple kernel log buffer

This commit is contained in:
Mark Poliakov 2023-11-26 13:28:50 +02:00
parent dbbddaa4f5
commit 0dc2cfa159
4 changed files with 88 additions and 19 deletions

View File

@ -2,14 +2,30 @@
use core::fmt::{self, Arguments}; use core::fmt::{self, Arguments};
use abi::error::Error; 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 MAX_DEBUG_SINKS: usize = 4;
const RING_LOGGER_CAPACITY: usize = 65536;
struct SimpleLogger; struct SimpleLogger;
struct RingLoggerInner {
data: RingBuffer<u8, RING_LOGGER_CAPACITY>,
}
pub struct RingLoggerSink {
inner: IrqSafeSpinlock<RingLoggerInner>,
waker: QueueWaker,
}
/// Defines the severity of the message /// Defines the severity of the message
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum LogLevel { 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 LOGGER: SimpleLogger = SimpleLogger;
static DEBUG_SINKS: IrqSafeSpinlock<StaticVector<DebugSinkWrapper, MAX_DEBUG_SINKS>> = static DEBUG_SINKS: IrqSafeSpinlock<StaticVector<DebugSinkWrapper, MAX_DEBUG_SINKS>> =
IrqSafeSpinlock::new(StaticVector::new()); 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 /// 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]) { pub fn hex_dump(level: LogLevel, addr_offset: usize, data: &[u8]) {
for (i, b) in data.iter().enumerate() { for (i, b) in data.iter().enumerate() {
@ -208,6 +257,8 @@ pub fn init() {
pub fn debug_internal(args: Arguments, level: LogLevel) { pub fn debug_internal(args: Arguments, level: LogLevel) {
use fmt::Write; use fmt::Write;
RING_LOGGER_SINK.write_fmt(args).ok();
for sink in DEBUG_SINKS.lock().iter_mut() { for sink in DEBUG_SINKS.lock().iter_mut() {
if level < sink.level { if level < sink.level {
continue; continue;

View File

@ -192,7 +192,7 @@ impl Device for Pl011 {
self.inner.init(IrqSafeSpinlock::new(inner)); 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)?; devfs::add_char_device(self, CharDeviceType::TtySerial)?;
Ok(()) Ok(())

View File

@ -12,7 +12,7 @@ use git_version::git_version;
use kernel_util::util::OneTimeInit; use kernel_util::util::OneTimeInit;
use vfs::{Vnode, VnodeImpl, VnodeKind, VnodeRef, DIR_POSITION_FROM_CACHE}; use vfs::{Vnode, VnodeImpl, VnodeKind, VnodeRef, DIR_POSITION_FROM_CACHE};
use crate::util; use crate::{debug, util};
trait GetterFn<T: ToString> = Fn() -> Result<T, Error>; trait GetterFn<T: ToString> = Fn() -> Result<T, Error>;
trait ReaderFn = Fn(u64, &mut [u8]) -> Result<usize, Error>; trait ReaderFn = Fn(u64, &mut [u8]) -> Result<usize, Error>;
@ -169,8 +169,7 @@ pub fn root() -> &'static VnodeRef {
} }
fn read_kernel_log(pos: u64, buffer: &mut [u8]) -> Result<usize, Error> { fn read_kernel_log(pos: u64, buffer: &mut [u8]) -> Result<usize, Error> {
// TODO actual kernel log buffer Ok(debug::RING_LOGGER_SINK.read(pos as usize, buffer))
todo!()
} }
pub fn init() { pub fn init() {

View File

@ -9,24 +9,36 @@ use futures_util::Future;
use crate::{sync::IrqSafeSpinlock, task::runtime::QueueWaker}; use crate::{sync::IrqSafeSpinlock, task::runtime::QueueWaker};
struct Inner<T, const N: usize> { pub struct RingBuffer<T, const N: usize> {
rd: usize, rd: usize,
wr: usize, wr: usize,
data: [T; N], data: [T; N],
} }
pub struct AsyncRing<T, const N: usize> { pub struct AsyncRing<T, const N: usize> {
inner: Arc<IrqSafeSpinlock<Inner<T, N>>>, inner: Arc<IrqSafeSpinlock<RingBuffer<T, N>>>,
read_waker: Arc<QueueWaker>, read_waker: Arc<QueueWaker>,
} }
impl<T: Copy, const N: usize> Inner<T, N> { impl<T: Copy, const N: usize> RingBuffer<T, N> {
pub const fn new(value: T) -> Self {
Self {
rd: 0,
wr: 0,
data: [value; N],
}
}
#[inline] #[inline]
const fn is_readable(&self) -> bool { const fn is_readable(&self) -> bool {
if self.rd <= self.wr { self.is_readable_at(self.rd)
(self.wr - self.rd) > 0 }
const fn is_readable_at(&self, at: usize) -> bool {
if at <= self.wr {
(self.wr - at) > 0
} else { } else {
(self.wr + (N - self.rd)) > 0 (self.wr + (N - at)) > 0
} }
} }
@ -37,8 +49,19 @@ impl<T: Copy, const N: usize> Inner<T, N> {
res 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] #[inline]
unsafe fn write_unchecked(&mut self, ch: T) { pub unsafe fn write_unchecked(&mut self, ch: T) {
self.data[self.wr] = ch; self.data[self.wr] = ch;
self.wr = (self.wr + 1) % N; self.wr = (self.wr + 1) % N;
} }
@ -47,11 +70,7 @@ impl<T: Copy, const N: usize> Inner<T, N> {
impl<T: Copy, const N: usize> AsyncRing<T, N> { impl<T: Copy, const N: usize> AsyncRing<T, N> {
pub fn new(value: T) -> Self { pub fn new(value: T) -> Self {
Self { Self {
inner: Arc::new(IrqSafeSpinlock::new(Inner { inner: Arc::new(IrqSafeSpinlock::new(RingBuffer::new(value))),
rd: 0,
wr: 0,
data: [value; N],
})),
read_waker: Arc::new(QueueWaker::new()), read_waker: Arc::new(QueueWaker::new()),
} }
} }
@ -69,7 +88,7 @@ impl<T: Copy, const N: usize> AsyncRing<T, N> {
pub fn read(&self) -> impl Future<Output = T> { pub fn read(&self) -> impl Future<Output = T> {
struct ReadFuture<T: Copy, const N: usize> { struct ReadFuture<T: Copy, const N: usize> {
inner: Arc<IrqSafeSpinlock<Inner<T, N>>>, inner: Arc<IrqSafeSpinlock<RingBuffer<T, N>>>,
read_waker: Arc<QueueWaker>, read_waker: Arc<QueueWaker>,
} }