Skip to content

Commit

Permalink
Implement a percpu line buffer to store the individual log messages.
Browse files Browse the repository at this point in the history
Each individual log message gets written into the global log buffer
from the percpu line buffer.

Signed-off-by: Vasant Karasulli <[email protected]>
  • Loading branch information
vsntk18 committed Aug 9, 2023
1 parent 74ba88e commit dbc26eb
Show file tree
Hide file tree
Showing 4 changed files with 150 additions and 1 deletion.
119 changes: 119 additions & 0 deletions src/cpu/line_buffer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2022-2023 SUSE LLC
//
// Author: Vasant Karasulli <[email protected]>

use crate::cpu::percpu::this_cpu_mut;
use crate::log_buffer::LB;
use crate::string::FixedString;
use crate::utils::immut_after_init::ImmutAfterInitCell;
use core::fmt;
use core::fmt::Write;

const LINE_BUFFER_SIZE: usize = 256;

#[derive(Debug)]
pub struct LineBuffer {
buf: FixedString<LINE_BUFFER_SIZE>,
}

impl LineBuffer {
pub const fn new() -> Self {
LineBuffer {
buf: FixedString::new(),
}
}

pub fn write_buffer(&mut self, s: &str) {
for c in s.chars() {
self.buf.push(c);
if c == '\n' || self.buf.length() == LINE_BUFFER_SIZE {
// when buffer is full or '\n' character is encountered
let mut buf_str: [u8; LINE_BUFFER_SIZE * 4] = [0; LINE_BUFFER_SIZE * 4];
let mut count: usize = 0;
let mut tmp: [u8; 4] = [0; 4];
for ch in self.buf {
ch.encode_utf8(&mut tmp);
buf_str[count] = tmp[0];
count += 1;
for item in tmp.iter().skip(1) {
/* ignore the trailing zeros in the utf8 array */
if *item != 0 {
buf_str[count] = *item;
count += 1;
}
}
}
unsafe { LB.lock().write_log(&buf_str[..count]) };
self.buf.reset();
}
}
}
}

impl fmt::Write for LineBuffer {
fn write_str(&mut self, s: &str) -> fmt::Result {
self.write_buffer(s);
Ok(())
}
}

#[derive(Clone, Copy)]
struct BufferLogger {
component: &'static str,
}

impl BufferLogger {
fn new(component: &'static str) -> BufferLogger {
BufferLogger { component }
}
}

impl log::Log for BufferLogger {
fn enabled(&self, _metadata: &log::Metadata) -> bool {
true
}

fn log(&self, record: &log::Record) {
let comp: &'static str = self.component;
let line_buf: &mut LineBuffer = this_cpu_mut().get_line_buffer();
// Log format/detail depends on the level.
let rec_args = record.args();
let lvl = record.metadata().level().as_str();
let target = record.metadata().target();
match record.metadata().level() {
log::Level::Error | log::Level::Warn => {
line_buf
.write_fmt(format_args!("[{}] {}: {}\n", comp, lvl, rec_args))
.unwrap();
}

log::Level::Info => {
line_buf
.write_fmt(format_args!("[{}] {}\n", comp, rec_args))
.unwrap();
}

log::Level::Debug | log::Level::Trace => {
line_buf
.write_fmt(format_args!("[{}/{}] {} {}\n", comp, target, lvl, rec_args))
.unwrap();
}
}
}

fn flush(&self) {}
}

static BUFFER_LOGGER: ImmutAfterInitCell<BufferLogger> = ImmutAfterInitCell::uninit();

pub fn install_buffer_logger(component: &'static str) {
BUFFER_LOGGER
.init(&BufferLogger::new(component))
.expect("already initialized the logger");
let _ = log::set_logger(&*BUFFER_LOGGER);

// Log levels are to be configured via the log's library feature configuration.
log::set_max_level(log::LevelFilter::Trace);
}
1 change: 1 addition & 0 deletions src/cpu/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ pub mod extable;
pub mod features;
pub mod gdt;
pub mod idt;
pub mod line_buffer;
pub mod msr;
pub mod percpu;
pub mod registers;
Expand Down
7 changes: 7 additions & 0 deletions src/cpu/percpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ extern crate alloc;
use super::gdt::load_tss;
use super::tss::{X86Tss, IST_DF};
use crate::address::{Address, PhysAddr, VirtAddr};
use crate::cpu::line_buffer::LineBuffer;
use crate::cpu::tss::TSS_LIMIT;
use crate::cpu::vmsa::init_guest_vmsa;
use crate::error::SvsmError;
Expand Down Expand Up @@ -182,6 +183,7 @@ pub struct PerCpu {
svsm_vmsa: Option<VmsaRef>,
guest_vmsa: SpinLock<GuestVmsaRef>,
reset_ip: u64,
ln_buf: LineBuffer,

/// Address allocator for per-cpu 4k temporary mappings
pub vrange_4k: VirtualRange,
Expand All @@ -202,6 +204,7 @@ impl PerCpu {
svsm_vmsa: None,
guest_vmsa: SpinLock::new(GuestVmsaRef::new()),
reset_ip: 0xffff_fff0u64,
ln_buf: LineBuffer::new(),
vrange_4k: VirtualRange::new(),
vrange_2m: VirtualRange::new(),
}
Expand Down Expand Up @@ -502,6 +505,10 @@ impl PerCpu {
PAGE_SHIFT_2M,
);
}

pub fn get_line_buffer(&mut self) -> &mut LineBuffer {
&mut self.ln_buf
}
}

unsafe impl Sync for PerCpu {}
Expand Down
24 changes: 23 additions & 1 deletion src/string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,15 @@ use core::mem::MaybeUninit;
pub struct FixedString<const T: usize> {
len: usize,
data: [char; T],
current: usize,
}

impl<const T: usize> FixedString<T> {
pub const fn new() -> Self {
FixedString {
len: 0,
data: ['\0'; T],
current: 0,
}
}

Expand All @@ -36,12 +38,18 @@ impl<const T: usize> FixedString<T> {
pub fn length(&self) -> usize {
self.len
}

pub fn reset(&mut self) {
self.len = 0;
self.current = 0;
}
}

impl<const N: usize> From<[u8; N]> for FixedString<N> {
fn from(arr: [u8; N]) -> FixedString<N> {
let mut data: [MaybeUninit<char>; N] = array::from_fn(|_| MaybeUninit::uninit());
let mut len = N;
let current = 0;

for (i, (d, val)) in data.iter_mut().zip(&arr).enumerate() {
let val = *val;
Expand All @@ -52,7 +60,7 @@ impl<const N: usize> From<[u8; N]> for FixedString<N> {
}

let data = unsafe { *(data.as_ptr().cast::<[char; N]>()) };
FixedString { data, len }
FixedString { data, len, current }
}
}

Expand Down Expand Up @@ -104,6 +112,20 @@ impl<const T: usize> fmt::Display for FixedString<T> {
}
}

impl<const T: usize> Iterator for FixedString<T> {
type Item = char;

fn next(&mut self) -> Option<Self::Item> {
let ret = if self.current == self.len {
None
} else {
Some(self.data[self.current])
};
self.current += 1;
ret
}
}

#[cfg(test)]
mod tests {
extern crate alloc;
Expand Down

0 comments on commit dbc26eb

Please sign in to comment.