Skip to content

Commit

Permalink
Support saving kernel crash logs using boot2dump (#139)
Browse files Browse the repository at this point in the history
  • Loading branch information
nuta committed Dec 22, 2021
1 parent 2852abd commit 264a961
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 5 deletions.
7 changes: 7 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions kernel/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ log = "0.4"
spin = "0.9.2"
goblin = { version = "0.4", default-features = false, features = ["elf64"] }
smoltcp = { version = "0.7.5", default-features = false, features = ["alloc", "proto-ipv4", "socket", "socket-raw", "socket-udp", "socket-tcp", "proto-dhcpv4", "ethernet"] }
boot2dump = { version = "0" }

# Data structues.
bitflags = "1.3.2"
Expand Down
46 changes: 45 additions & 1 deletion kernel/lang_items.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,27 @@
use core::sync::atomic::AtomicBool;

pub static PANICKED: AtomicBool = AtomicBool::new(false);
static mut KERNEL_DUMP_BUF: KernelDump = KernelDump::empty();

#[repr(C, packed)]
struct KernelDump {
/// `0xdeadbeee`
magic: u32,
/// The length of the kernel log.
len: u32,
/// The kernel log (including the panic message).
log: [u8; 4096],
}

impl KernelDump {
const fn empty() -> KernelDump {
KernelDump {
magic: 0,
len: 0,
log: [0; 4096],
}
}
}

#[alloc_error_handler]
fn alloc_error_handler(layout: core::alloc::Layout) -> ! {
Expand All @@ -11,6 +32,7 @@ fn alloc_error_handler(layout: core::alloc::Layout) -> ! {
#[panic_handler]
#[cfg(not(test))]
fn panic(info: &core::panic::PanicInfo) -> ! {
use crate::logger::KERNEL_LOG_BUF;
use core::sync::atomic::Ordering;

if PANICKED.load(Ordering::SeqCst) {
Expand All @@ -21,5 +43,27 @@ fn panic(info: &core::panic::PanicInfo) -> ! {
PANICKED.store(true, Ordering::SeqCst);
error!("{}", info);
kerla_runtime::backtrace::backtrace();
kerla_runtime::arch::halt();

unsafe {
warn!("preparing a crash dump...");
KERNEL_LOG_BUF.force_unlock();
let mut off = 0;
let mut log_buffer = KERNEL_LOG_BUF.lock();
while let Some(slice) = log_buffer.pop_slice(KERNEL_DUMP_BUF.log.len().saturating_sub(off))
{
KERNEL_DUMP_BUF.log[off..(off + slice.len())].copy_from_slice(slice);
off += slice.len();
}

KERNEL_DUMP_BUF.magic = 0xdeadbeee;
KERNEL_DUMP_BUF.len = off as u32;

warn!("prepared crash dump: log_len={}", off);
warn!("booting boot2dump...");
let dump_as_bytes = core::slice::from_raw_parts(
&KERNEL_DUMP_BUF as *const _ as *const u8,
core::mem::size_of::<KernelDump>(),
);
boot2dump::save_to_file_and_reboot("kerla.dump", dump_as_bytes);
}
}
15 changes: 11 additions & 4 deletions kernel/logger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,18 @@ impl Printer for LoggedPrinter {
fn print_bytes(&self, s: &[u8]) {
self.inner.print_bytes(s);

// Don't write into the kernel log buffer as it may call a printk function
// due to an assertion.
if !PANICKED.load(Ordering::SeqCst) {
KERNEL_LOG_BUF.lock().push_slice(s);
if PANICKED.load(Ordering::SeqCst) {
// If kernel panics, it's uncertain whether KERNEL_LOG_BUF is in
// a dead lock.
//
// Since only single CPU can continue handling a panic, we can
// ensure it's safe to unlock it.
unsafe {
KERNEL_LOG_BUF.force_unlock();
}
}

KERNEL_LOG_BUF.lock().push_slice(s);
}
}

Expand Down

0 comments on commit 264a961

Please sign in to comment.