1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
//! A library for OS developers to save a kernel crash log happened in your
//! own kernel into a file on disk reboot the computer.
//!
//! # Prerequisites
//!
//! You kernel needs to satisfy the following prerequisites to use this crate:
//!
//! - The CPU is x86_64 and is in the 64-bit mode.
//! - The file system is ext4 and its on a virtio-blk device.
//! - A **sufficiently large** file for the crash log (e.g. in the following example, `kerla.dump`)
//!   already exists in the **root directory**.
//! - Virtual addresses starting `0xffff_8000_0000_0000` are straight mapped into
//!   from the physical addresses 0 (i.e. `0xffff_8000_0001_0000` points to `0x1_0000`).
//!   It should cover the memory pages where boot2dump image exist.
//!
//! # How to Use
//!
//! The usage is pretty simple: at the end of your panic handler, call
//! [`save_to_file_and_reboot`]. It will save the given buffer into a file
//! and then reboot the computer.
//!
//! # Example
//!
//! ```ignore
//! use boot2dump::save_to_file_and_reboot;
//!
//! #[panic_handler]
//! fn panic(info: &core::panic::PanicInfo) -> ! {
//!     // Save the panic message into a file. Let's hope `format!` won't panic...
//!     let message = format!("{}", info).as_bytes();
//!     save_to_file_and_reboot("kerla.dump",  message.as_bytes());
//! }
//! ```
#![no_std]

#[repr(align(4096))]
struct PageAligned;

// A quick workaround for aligning the image location to a page boundary.
// https://users.rust-lang.org/t/can-i-conveniently-compile-bytes-into-a-rust-program-with-a-specific-alignment/24049/2
#[repr(C)]
struct Image<T: ?Sized> {
    _align: [PageAligned; 0],
    data: T,
}

static BOOT2DUMP: &'static Image<[u8]> = &Image {
    _align: [],
    data: *include_bytes!("../boot2dump.bin"),
};

/// Saves `data` into `filename` on the disk and then reboots the computer.
///
/// Currently, it only supports saving to a file in the root directory. Thus,
/// `filename` should be a filename without slashes (`/`), for example,
/// `kerla.dump`.
///
/// # Safety
///
/// This function will boot another operating system (boot2dump) and it may cause
/// a problem.
pub unsafe fn save_to_file_and_reboot(filename: &str, data: &[u8]) -> ! {
    type EntryPoint = extern "C" fn(*const u8, u64, *const u8, u64);
    let entrypoint = core::mem::transmute::<_, EntryPoint>(BOOT2DUMP.data.as_ptr());
    entrypoint(
        filename.as_ptr(),
        filename.len() as u64,
        data.as_ptr(),
        data.len() as u64,
    );
    core::hint::unreachable_unchecked();
}