Skip to content

Commit 7c74627

Browse files
committed
Add a test to verify that ramdisk is marked as used in memory map
1 parent 6b23732 commit 7c74627

File tree

2 files changed

+96
-0
lines changed

2 files changed

+96
-0
lines changed

tests/ramdisk.rs

+8
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,11 @@ fn check_ramdisk() {
1818
Some(Path::new(RAMDISK_PATH)),
1919
);
2020
}
21+
22+
#[test]
23+
fn memory_map() {
24+
run_test_kernel_with_ramdisk(
25+
env!("CARGO_BIN_FILE_TEST_KERNEL_RAMDISK_memory_map"),
26+
Some(Path::new(RAMDISK_PATH)),
27+
);
28+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
#![no_std] // don't link the Rust standard library
2+
#![no_main] // disable all Rust-level entry points
3+
4+
use bootloader_api::{
5+
config::Mapping, entry_point, info::MemoryRegionKind, BootInfo, BootloaderConfig,
6+
};
7+
use core::{fmt::Write, ptr::slice_from_raw_parts};
8+
use test_kernel_ramdisk::{exit_qemu, serial, QemuExitCode, RAMDISK_CONTENTS};
9+
use x86_64::{
10+
structures::paging::{OffsetPageTable, PageTable, PageTableFlags, Translate},
11+
VirtAddr,
12+
};
13+
14+
pub const BOOTLOADER_CONFIG: BootloaderConfig = {
15+
let mut config = BootloaderConfig::new_default();
16+
config.mappings.physical_memory = Some(Mapping::FixedAddress(0x0000_6000_0000_0000));
17+
config
18+
};
19+
20+
entry_point!(kernel_main, config = &BOOTLOADER_CONFIG);
21+
22+
fn kernel_main(boot_info: &'static mut BootInfo) -> ! {
23+
writeln!(serial(), "Boot info: {boot_info:?}").unwrap();
24+
25+
let phys_mem_offset = VirtAddr::new(boot_info.physical_memory_offset.into_option().unwrap());
26+
let level_4_table = unsafe { active_level_4_table(phys_mem_offset) };
27+
let page_table = unsafe { OffsetPageTable::new(level_4_table, phys_mem_offset) };
28+
29+
let ramdisk_start_addr = VirtAddr::new(boot_info.ramdisk_addr.into_option().unwrap());
30+
assert_eq!(boot_info.ramdisk_len as usize, RAMDISK_CONTENTS.len());
31+
let ramdisk_end_addr = ramdisk_start_addr + boot_info.ramdisk_len;
32+
33+
let mut next_addr = ramdisk_start_addr;
34+
while next_addr < ramdisk_end_addr {
35+
let phys_addr = match page_table.translate(next_addr) {
36+
x86_64::structures::paging::mapper::TranslateResult::Mapped {
37+
frame,
38+
offset: _,
39+
flags,
40+
} => {
41+
assert!(flags.contains(PageTableFlags::PRESENT));
42+
assert!(flags.contains(PageTableFlags::WRITABLE));
43+
44+
next_addr += frame.size();
45+
46+
frame.start_address()
47+
}
48+
other => panic!("invalid result: {other:?}"),
49+
};
50+
let region = boot_info
51+
.memory_regions
52+
.iter()
53+
.find(|r| r.start <= phys_addr.as_u64() && r.end > phys_addr.as_u64())
54+
.unwrap();
55+
assert_eq!(region.kind, MemoryRegionKind::Bootloader);
56+
}
57+
58+
let actual_ramdisk = unsafe {
59+
&*slice_from_raw_parts(
60+
boot_info.ramdisk_addr.into_option().unwrap() as *const u8,
61+
boot_info.ramdisk_len as usize,
62+
)
63+
};
64+
writeln!(serial(), "Actual contents: {actual_ramdisk:?}").unwrap();
65+
assert_eq!(RAMDISK_CONTENTS, actual_ramdisk);
66+
67+
exit_qemu(QemuExitCode::Success);
68+
}
69+
70+
/// This function is called on panic.
71+
#[cfg(not(test))]
72+
#[panic_handler]
73+
fn panic(info: &core::panic::PanicInfo) -> ! {
74+
let _ = writeln!(test_kernel_ramdisk::serial(), "PANIC: {info}");
75+
exit_qemu(QemuExitCode::Failed);
76+
}
77+
78+
pub unsafe fn active_level_4_table(physical_memory_offset: VirtAddr) -> &'static mut PageTable {
79+
use x86_64::registers::control::Cr3;
80+
81+
let (level_4_table_frame, _) = Cr3::read();
82+
83+
let phys = level_4_table_frame.start_address();
84+
let virt = physical_memory_offset + phys.as_u64();
85+
let page_table_ptr: *mut PageTable = virt.as_mut_ptr();
86+
87+
&mut *page_table_ptr // unsafe
88+
}

0 commit comments

Comments
 (0)