Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 22d116f

Browse files
Merge pull request #408 from rust-osdev/fix-ramdisk
Fix: Mark `ramdisk` as used in memory map
2 parents 1b84c46 + 7c74627 commit 22d116f

File tree

4 files changed

+148
-3
lines changed

4 files changed

+148
-3
lines changed

‎common/src/legacy_memory_region.rs

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,9 +112,12 @@ where
112112
regions: &mut [MaybeUninit<MemoryRegion>],
113113
kernel_slice_start: PhysAddr,
114114
kernel_slice_len: u64,
115+
ramdisk_slice_start: Option<PhysAddr>,
116+
ramdisk_slice_len: u64,
115117
) -> &mut [MemoryRegion] {
116118
let mut next_index = 0;
117119
let kernel_slice_start = kernel_slice_start.as_u64();
120+
let ramdisk_slice_start = ramdisk_slice_start.map(|a| a.as_u64());
118121

119122
for descriptor in self.original {
120123
let mut start = descriptor.start();
@@ -157,8 +160,9 @@ where
157160
kind,
158161
};
159162

160-
// check if region overlaps with kernel
163+
// check if region overlaps with kernel or ramdisk
161164
let kernel_slice_end = kernel_slice_start + kernel_slice_len;
165+
let ramdisk_slice_end = ramdisk_slice_start.map(|s| s + ramdisk_slice_len);
162166
if region.kind == MemoryRegionKind::Usable
163167
&& kernel_slice_start < region.end
164168
&& kernel_slice_end > region.start
@@ -198,6 +202,47 @@ where
198202
Self::add_region(before_kernel, regions, &mut next_index);
199203
Self::add_region(kernel, regions, &mut next_index);
200204
Self::add_region(after_kernel, regions, &mut next_index);
205+
} else if region.kind == MemoryRegionKind::Usable
206+
&& ramdisk_slice_start.map(|s| s < region.end).unwrap_or(false)
207+
&& ramdisk_slice_end.map(|e| e > region.start).unwrap_or(false)
208+
{
209+
// region overlaps with ramdisk -> we might need to split it
210+
let ramdisk_slice_start = ramdisk_slice_start.unwrap();
211+
let ramdisk_slice_end = ramdisk_slice_end.unwrap();
212+
213+
// ensure that the ramdisk allocation does not span multiple regions
214+
assert!(
215+
ramdisk_slice_start >= region.start,
216+
"region overlaps with ramdisk, but ramdisk begins before region \
217+
(ramdisk_start: {ramdisk_slice_start:#x}, region_start: {:#x})",
218+
region.start
219+
);
220+
assert!(
221+
ramdisk_slice_end <= region.end,
222+
"region overlaps with ramdisk, but region ends before ramdisk \
223+
(ramdisk_end: {ramdisk_slice_end:#x}, region_end: {:#x})",
224+
region.end,
225+
);
226+
227+
// split the region into three parts
228+
let before_ramdisk = MemoryRegion {
229+
end: ramdisk_slice_start,
230+
..region
231+
};
232+
let ramdisk = MemoryRegion {
233+
start: ramdisk_slice_start,
234+
end: ramdisk_slice_end,
235+
kind: MemoryRegionKind::Bootloader,
236+
};
237+
let after_ramdisk = MemoryRegion {
238+
start: ramdisk_slice_end,
239+
..region
240+
};
241+
242+
// add the three regions (empty regions are ignored in `add_region`)
243+
Self::add_region(before_ramdisk, regions, &mut next_index);
244+
Self::add_region(ramdisk, regions, &mut next_index);
245+
Self::add_region(after_ramdisk, regions, &mut next_index);
201246
} else {
202247
// add the region normally
203248
Self::add_region(region, regions, &mut next_index);

‎common/src/lib.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -293,14 +293,14 @@ where
293293
None
294294
};
295295
let ramdisk_slice_len = system_info.ramdisk_len;
296-
let ramdisk_slice_start = if let Some(ramdisk_address) = system_info.ramdisk_addr {
296+
let ramdisk_slice_phys_start = system_info.ramdisk_addr.map(PhysAddr::new);
297+
let ramdisk_slice_start = if let Some(physical_address) = ramdisk_slice_phys_start {
297298
let start_page = mapping_addr_page_aligned(
298299
config.mappings.ramdisk_memory,
299300
system_info.ramdisk_len,
300301
&mut used_entries,
301302
"ramdisk start",
302303
);
303-
let physical_address = PhysAddr::new(ramdisk_address);
304304
let ramdisk_physical_start_page: PhysFrame<Size4KiB> =
305305
PhysFrame::containing_address(physical_address);
306306
let ramdisk_page_count = (system_info.ramdisk_len - 1) / Size4KiB::SIZE;
@@ -404,6 +404,7 @@ where
404404
kernel_slice_len,
405405
kernel_image_offset,
406406

407+
ramdisk_slice_phys_start,
407408
ramdisk_slice_start,
408409
ramdisk_slice_len,
409410
}
@@ -433,6 +434,7 @@ pub struct Mappings {
433434
pub kernel_slice_len: u64,
434435
/// Relocation offset of the kernel image in virtual memory.
435436
pub kernel_image_offset: VirtAddr,
437+
pub ramdisk_slice_phys_start: Option<PhysAddr>,
436438
pub ramdisk_slice_start: Option<VirtAddr>,
437439
pub ramdisk_slice_len: u64,
438440
}
@@ -516,6 +518,8 @@ where
516518
memory_regions,
517519
mappings.kernel_slice_start,
518520
mappings.kernel_slice_len,
521+
mappings.ramdisk_slice_phys_start,
522+
mappings.ramdisk_slice_len,
519523
);
520524

521525
log::info!("Create bootinfo");

‎tests/ramdisk.rs

Lines changed: 8 additions & 0 deletions
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+
}
Lines changed: 88 additions & 0 deletions
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)

AltStyle によって変換されたページ (->オリジナル) /