Skip to main content

kernel/kprint/
ringbuffer.rs

1// SPDX-License-Identifier: GPL-3.0-only
2//! Kernel Log Ringbuffer
3//!
4//! Authors: MarioS271
5
6use crate::kprint::log_entry::{LogEntryHeader, LogFlags, LogLevel};
7use crate::lib::types::packed_u8::PackedU8;
8
9/// The kernel ringbuffer
10pub struct Ringbuffer {
11    seq: u64,
12    buffer: [u8; Self::SIZE],
13    head: usize,
14    tail: usize
15}
16
17impl Ringbuffer {
18    /// Capacity of the in-memory log ring buffer (1 MiB)
19    pub const SIZE: usize = 1 << 20;
20
21    /// Constructor; create a new empty [`Ringbuffer`]
22    pub const fn new() -> Self {
23        Self {
24            seq: 0,
25            buffer: [0u8; Self::SIZE],
26            head: 0,
27            tail: 0
28        }
29    }
30
31    /// Constructs and writes a [`LogEntryHeader`] followed by the given `text` to the ringbuffer
32    pub fn write_entry(
33        &mut self,
34        log_level: LogLevel,
35        log_flags: LogFlags,
36        text: &[u8]
37    ) -> LogEntryHeader {
38        use super::log_entry::LogEntryHeader;
39
40        let seq = self.seq;
41        self.seq += 1;
42
43        // TODO: get proper timestamp
44        let ts_nsec = 0;
45
46        let mut flags_and_level = PackedU8::default();
47        flags_and_level.set(
48            LogEntryHeader::FLAGS_START_BIT,
49            LogEntryHeader::FLAGS_NUM_BITS,
50            log_flags.as_u8()
51        );
52        flags_and_level.set(
53            LogEntryHeader::LEVEL_START_BIT,
54            LogEntryHeader::LEVEL_NUM_BITS,
55            log_level as u8
56        );
57
58        let header = LogEntryHeader {
59            seq,
60            ts_nsec,
61            text_len: text.len() as u16,
62            flags_and_level
63        };
64        let header_bytes = unsafe {
65            core::slice::from_raw_parts(
66                &raw const header as *const u8,
67                size_of::<LogEntryHeader>()
68            )
69        };
70
71        self.write_bytes(header_bytes);
72        self.write_bytes(text);
73
74        header
75    }
76
77    /// Write raw bytes into the ring buffer
78    fn write_bytes(&mut self, bytes: &[u8]) {
79        for byte in bytes {
80            self.buffer[self.head % Self::SIZE] = *byte;
81            self.head = self.head.wrapping_add(1);
82
83            if self.head.wrapping_sub(self.tail) > Self::SIZE {
84                self.advance_tail();
85            }
86        }
87    }
88
89    /// Advance `Ringbuffer::tail` to the next entry
90    fn advance_tail(&mut self) {
91        let header_size = size_of::<LogEntryHeader>();
92
93        let lo = self.buffer[(self.tail + 16) % Self::SIZE];
94        let hi = self.buffer[(self.tail + 17) % Self::SIZE];
95        let text_len = u16::from_ne_bytes([lo, hi]) as usize;
96
97        self.tail = self.tail.wrapping_add(header_size + text_len);
98    }
99}