Skip to content

Commit a9e3987

Browse files
authored
Merge pull request #1996 from hermit-os/reserve-memory
feat(physicalmem): respect memory reservations
2 parents 4b7e46e + d0f13fb commit a9e3987

2 files changed

Lines changed: 84 additions & 40 deletions

File tree

src/arch/x86_64/mm/paging.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -367,12 +367,12 @@ pub unsafe fn log_page_tables() {
367367

368368
use self::mapped_page_range_display::OffsetPageTableExt;
369369

370-
if !log_enabled!(Level::Debug) {
370+
if !log_enabled!(Level::Trace) {
371371
return;
372372
}
373373

374374
let page_table = unsafe { identity_mapped_page_table() };
375-
debug!("Page tables:\n{}", page_table.display());
375+
trace!("Page tables:\n{}", page_table.display());
376376
}
377377

378378
pub mod mapped_page_range_display {

src/mm/physicalmem.rs

Lines changed: 82 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use core::sync::atomic::{AtomicUsize, Ordering};
22

33
use align_address::Align;
4-
use free_list::{FreeList, PageRange};
4+
use free_list::{FreeList, PageRange, PageRangeError};
55
use hermit_sync::InterruptTicketMutex;
66
use memory_addresses::{PhysAddr, VirtAddr};
77

@@ -19,7 +19,7 @@ pub fn total_memory_size() -> usize {
1919
TOTAL_MEMORY.load(Ordering::Relaxed)
2020
}
2121

22-
pub unsafe fn init_frame_range(frame_range: PageRange) {
22+
pub unsafe fn map_frame_range(frame_range: PageRange) {
2323
cfg_if::cfg_if! {
2424
if #[cfg(target_arch = "aarch64")] {
2525
type IdentityPageSize = crate::arch::mm::paging::BasePageSize;
@@ -37,10 +37,6 @@ pub unsafe fn init_frame_range(frame_range: PageRange) {
3737
.end()
3838
.align_up(IdentityPageSize::SIZE.try_into().unwrap());
3939

40-
unsafe {
41-
PHYSICAL_FREE_LIST.lock().deallocate(frame_range).unwrap();
42-
}
43-
4440
(start..end)
4541
.step_by(IdentityPageSize::SIZE.try_into().unwrap())
4642
.map(|addr| PhysAddr::new(addr.try_into().unwrap()))
@@ -61,58 +57,104 @@ pub unsafe fn init_frame_range(frame_range: PageRange) {
6157
paging::map::<IdentityPageSize>(virt_addr, phys_addr, 1, flags);
6258
});
6359
}
64-
65-
TOTAL_MEMORY.fetch_add(frame_range.len().get(), Ordering::Relaxed);
6660
}
6761

6862
fn detect_from_fdt() -> Result<(), ()> {
6963
let fdt = env::fdt().ok_or(())?;
7064

65+
let all_regions = fdt
66+
.find_all_nodes("/memory")
67+
.map(|m| m.reg().unwrap().next().unwrap());
68+
if all_regions.count() == 0 {
69+
return Err(());
70+
}
7171
let all_regions = fdt
7272
.find_all_nodes("/memory")
7373
.map(|m| m.reg().unwrap().next().unwrap());
7474

75-
let mut found_ram = false;
75+
for m in all_regions {
76+
let start_address = m.starting_address as u64;
77+
let size = m.size.unwrap() as u64;
78+
let end_address = start_address + size;
7679

77-
if env::is_uefi() {
78-
let biggest_region = all_regions.max_by_key(|m| m.size.unwrap()).unwrap();
79-
found_ram = true;
80+
if end_address <= super::kernel_end_address().as_u64() && !env::is_uefi() {
81+
continue;
82+
}
8083

81-
let range = PageRange::from_start_len(
82-
biggest_region.starting_address.addr(),
83-
biggest_region.size.unwrap(),
84-
)
85-
.unwrap();
84+
let start_address =
85+
if start_address <= super::kernel_start_address().as_u64() && !env::is_uefi() {
86+
super::kernel_end_address()
87+
} else {
88+
VirtAddr::new(start_address)
89+
};
8690

91+
let range = PageRange::new(start_address.as_usize(), end_address as usize).unwrap();
8792
unsafe {
88-
init_frame_range(range);
93+
PHYSICAL_FREE_LIST.lock().deallocate(range).unwrap();
94+
map_frame_range(range);
8995
}
96+
TOTAL_MEMORY.fetch_add(range.len().get(), Ordering::Relaxed);
97+
debug!("Claimed physical memory: {range:#x?}");
98+
}
99+
100+
let reserve = |reservation: PageRange| {
101+
debug!("Memory reservation: {reservation:#x?}");
102+
// While there are still overlaps between this reservation and any available ranges,
103+
// allocate that overlap to mark it as not available.
104+
while let Ok(reserved) = PHYSICAL_FREE_LIST
105+
.lock()
106+
.allocate_with(|range| reservation.and(range))
107+
{
108+
debug!("Reserved {reserved:#x?}");
109+
}
110+
};
111+
112+
for reservation in fdt.memory_reservations() {
113+
let start = reservation.address().addr();
114+
let end = start + reservation.size();
115+
let reservation = PageRange::new(start, end).unwrap();
116+
reserve(reservation);
117+
}
118+
119+
let kernel_start = if env::is_uefi() {
120+
super::kernel_start_address().as_usize()
90121
} else {
91-
for m in all_regions {
92-
let start_address = m.starting_address as u64;
93-
let size = m.size.unwrap() as u64;
94-
let end_address = start_address + size;
122+
// FIXME: Memory before the kernel causes trouble on non-uefi systems.
123+
// It is unclear, which exact regions cause problems.
124+
0
125+
};
126+
let kernel_end = super::kernel_end_address().as_usize();
127+
let kernel_region = PageRange::new(kernel_start, kernel_end).unwrap();
128+
reserve(kernel_region);
129+
130+
let fdt_start = env::boot_info().hardware_info.device_tree.unwrap().get();
131+
let fdt_start = usize::try_from(fdt_start).unwrap();
132+
let fdt_end = fdt_start + fdt.total_size();
133+
let fdt_region = PageRange::containing(fdt_start, fdt_end).unwrap();
134+
reserve(fdt_region);
95135

96-
if end_address <= super::kernel_end_address().as_u64() {
97-
continue;
98-
}
136+
Ok(())
137+
}
99138

100-
found_ram = true;
139+
// FIXME: upstream these
140+
trait PageRangeExt: Sized {
141+
fn containing(start: usize, end: usize) -> Result<Self, PageRangeError>;
101142

102-
let start_address = if start_address <= super::kernel_start_address().as_u64() {
103-
super::kernel_end_address()
104-
} else {
105-
VirtAddr::new(start_address)
106-
};
143+
fn and(self, rhs: Self) -> Option<Self>;
144+
}
107145

108-
let range = PageRange::new(start_address.as_usize(), end_address as usize).unwrap();
109-
unsafe {
110-
init_frame_range(range);
111-
}
112-
}
146+
impl PageRangeExt for PageRange {
147+
fn containing(start: usize, end: usize) -> Result<Self, PageRangeError> {
148+
let start = start.align_down(free_list::PAGE_SIZE);
149+
let end = end.align_up(free_list::PAGE_SIZE);
150+
Self::new(start, end)
113151
}
114152

115-
if found_ram { Ok(()) } else { Err(()) }
153+
fn and(self, rhs: Self) -> Option<Self> {
154+
let start = self.start().max(rhs.start());
155+
let end = self.end().min(rhs.end());
156+
Self::new(start, end).ok()
157+
}
116158
}
117159

118160
#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
@@ -130,8 +172,10 @@ fn detect_from_limits() -> Result<(), ()> {
130172
let range =
131173
PageRange::new(super::kernel_end_address().as_usize(), ram_address + limit).unwrap();
132174
unsafe {
133-
init_frame_range(range);
175+
PHYSICAL_FREE_LIST.lock().deallocate(range).unwrap();
176+
map_frame_range(range);
134177
}
178+
TOTAL_MEMORY.fetch_add(range.len().get(), Ordering::Relaxed);
135179

136180
Ok(())
137181
}

0 commit comments

Comments
 (0)