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 Jul 4, 2023
1 parent 01ac11a commit cf66d38
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 4 deletions.
7 changes: 7 additions & 0 deletions src/cpu/percpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use crate::address::{Address, PhysAddr, VirtAddr};
use crate::cpu::tss::TSS_LIMIT;
use crate::cpu::vmsa::init_guest_vmsa;
use crate::error::SvsmError;
use crate::line_buffer::LineBuffer;
use crate::locking::{LockGuard, RWLock, SpinLock};
use crate::mm::alloc::{allocate_page, allocate_zeroed_page};
use crate::mm::pagetable::{get_init_pgtable_locked, PageTable, PageTableRef};
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
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ pub mod fw_cfg;
pub mod fw_meta;
pub mod io;
pub mod kernel_launch;
pub mod line_buffer;
pub mod locking;
pub mod log_buffer;
pub mod migrate;
Expand Down
115 changes: 115 additions & 0 deletions src/line_buffer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
use crate::cpu::percpu::this_cpu_mut;
use crate::log_buffer::LB;
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: [u8; LINE_BUFFER_SIZE],
head: usize,
tail: usize,
}

impl LineBuffer {
pub const fn new() -> Self {
LineBuffer {
buf: [0; LINE_BUFFER_SIZE],
head: 0,
tail: 0,
}
}

pub fn write_buffer(&mut self, s: &str) {
for b in s.bytes() {
self.buf[self.head] = b;
self.head = (self.head + 1) % LINE_BUFFER_SIZE;
if b == 0xa {
// write to global log buffer when '\n' character is encountered
if self.tail <= self.head {
let st = core::str::from_utf8(&self.buf[self.tail..self.head]).unwrap();
unsafe { LB.write_log(st) };
} else {
let st1 = core::str::from_utf8(&self.buf[self.tail..]).unwrap();
let st2 = core::str::from_utf8(&self.buf[..self.head]).unwrap();
let st = &[st1, st2].concat();
unsafe { LB.write_log(st) };
}
self.tail = self.head;
}
}
}
}

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 component: &'static str = &self.component;
let line_buf: &mut LineBuffer = this_cpu_mut().get_line_buffer();
// Log format/detail depends on the level.
match record.metadata().level() {
log::Level::Error | log::Level::Warn => write!(
line_buf,
"[{}] {}: {}\n",
component,
record.metadata().level().as_str(),
record.args()
)
.expect("write error"),

log::Level::Info => {
write!(line_buf, "[{}] {}\n", component, record.args()).expect("write error")
}

log::Level::Debug | log::Level::Trace => write!(
line_buf,
"[{}/{}] {} {}\n",
component,
record.metadata().target(),
record.metadata().level().as_str(),
record.args()
)
.expect("write error"),
}
}

fn flush(&self) {}
}

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

pub fn install_buffer_logger(component: &'static str) -> Result<(), ()> {
BUFFER_LOGGER
.init(&BufferLogger::new(component))
.expect("already initialized the logger");
if let Err(_) = log::set_logger(&*BUFFER_LOGGER) {
return Err(());
}

// Log levels are to be configured via the log's library feature configuration.
log::set_max_level(log::LevelFilter::Trace);
Ok(())
}
7 changes: 5 additions & 2 deletions src/stage2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@ use core::arch::asm;
use core::panic::PanicInfo;
use core::slice;
use svsm::address::{Address, PhysAddr, VirtAddr};
use svsm::console::{init_console, install_console_logger, WRITER};
use svsm::console::{init_console, WRITER};
use svsm::cpu::cpuid::{dump_cpuid_table, register_cpuid_table, SnpCpuidTable};
use svsm::cpu::percpu::{this_cpu_mut, PerCpu};
use svsm::elf;
use svsm::fw_cfg::FwCfg;
use svsm::kernel_launch::KernelLaunchInfo;
use svsm::line_buffer::install_buffer_logger;
use svsm::log_buffer::{init_log_buffer, LB};
use svsm::migrate::MigrateInfo;
use svsm::mm::alloc::{memory_info, print_memory_info, root_mem_init};
Expand Down Expand Up @@ -85,7 +86,6 @@ static mut CONSOLE_SERIAL: SerialPort = SerialPort {
};

fn setup_env() {
install_console_logger("Stage2");
init_kernel_mapping_info(
VirtAddr::null(),
VirtAddr::from(640 * 1024usize),
Expand All @@ -106,6 +106,9 @@ fn setup_env() {
}
init_console();
init_log_buffer();
if let Err(_) = install_buffer_logger("Stage2") {
panic!("log buffer installation error")
}

// Console is fully working now and any unsupported configuration can be
// properly reported.
Expand Down
7 changes: 5 additions & 2 deletions src/svsm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use core::panic::PanicInfo;
use core::slice;
use svsm::acpi::tables::load_acpi_cpu_info;
use svsm::address::{Address, PhysAddr, VirtAddr};
use svsm::console::{init_console, install_console_logger, WRITER};
use svsm::console::{init_console, WRITER};
use svsm::cpu::control_regs::{cr0_init, cr4_init};
use svsm::cpu::cpuid::{dump_cpuid_table, register_cpuid_table, SnpCpuidTable};
use svsm::cpu::efer::efer_init;
Expand All @@ -34,6 +34,7 @@ use svsm::error::SvsmError;
use svsm::fs::{initialize_fs, populate_ram_fs};
use svsm::fw_cfg::FwCfg;
use svsm::kernel_launch::KernelLaunchInfo;
use svsm::line_buffer::install_buffer_logger;
use svsm::log_buffer::migrate_log_buffer;
use svsm::migrate::MigrateInfo;
use svsm::mm::alloc::{memory_info, print_memory_info, root_mem_init};
Expand Down Expand Up @@ -386,8 +387,10 @@ pub extern "C" fn svsm_start(li: &KernelLaunchInfo, mi: &MigrateInfo) {
unsafe {
WRITER.lock().set(&mut CONSOLE_SERIAL);
}
if let Err(_) = install_buffer_logger("SVSM") {
panic!("log buffer installation error")
}
init_console();
install_console_logger("SVSM");

log::info!("COCONUT Secure Virtual Machine Service Module (SVSM)");

Expand Down

0 comments on commit cf66d38

Please sign in to comment.