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 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<u8, RING_LOGGER_CAPACITY>,
}
pub struct RingLoggerSink {
inner: IrqSafeSpinlock<RingLoggerInner>,
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<StaticVector<DebugSinkWrapper, MAX_DEBUG_SINKS>> =
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;

View File

@ -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(())

View File

@ -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<T: ToString> = Fn() -> Result<T, 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> {
// TODO actual kernel log buffer
todo!()
Ok(debug::RING_LOGGER_SINK.read(pos as usize, buffer))
}
pub fn init() {

View File

@ -9,24 +9,36 @@ use futures_util::Future;
use crate::{sync::IrqSafeSpinlock, task::runtime::QueueWaker};
struct Inner<T, const N: usize> {
pub struct RingBuffer<T, const N: usize> {
rd: usize,
wr: usize,
data: [T; N],
}
pub struct AsyncRing<T, const N: usize> {
inner: Arc<IrqSafeSpinlock<Inner<T, N>>>,
inner: Arc<IrqSafeSpinlock<RingBuffer<T, N>>>,
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]
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<T: Copy, const N: usize> Inner<T, N> {
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<T: Copy, const N: usize> Inner<T, N> {
impl<T: Copy, const N: usize> AsyncRing<T, N> {
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<T: Copy, const N: usize> AsyncRing<T, N> {
pub fn read(&self) -> impl Future<Output = T> {
struct ReadFuture<T: Copy, const N: usize> {
inner: Arc<IrqSafeSpinlock<Inner<T, N>>>,
inner: Arc<IrqSafeSpinlock<RingBuffer<T, N>>>,
read_waker: Arc<QueueWaker>,
}