Skip to content

Commit bf39aab

Browse files
committed
Record memory slices used by bios
1 parent 0d10761 commit bf39aab

File tree

5 files changed

+64
-13
lines changed

5 files changed

+64
-13
lines changed

Diff for: bios/common/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ pub mod racy_cell;
55
#[cfg_attr(feature = "debug", derive(Debug))]
66
#[repr(C)]
77
pub struct BiosInfo {
8+
pub stage_3: Region,
89
pub stage_4: Region,
910
pub kernel: Region,
1011
pub ramdisk: Region,

Diff for: bios/stage-2/src/main.rs

+4
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,10 @@ fn start(disk_number: u16, partition_table_start: *const u8) -> ! {
145145
vesa_mode.enable().unwrap();
146146

147147
let mut info = BiosInfo {
148+
stage_3: Region {
149+
start: STAGE_3_DST as u64,
150+
len: stage_3_len,
151+
},
148152
stage_4: Region {
149153
start: stage_4_dst as u64,
150154
len: stage_4_len,

Diff for: bios/stage-4/src/main.rs

+15-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
use crate::memory_descriptor::MemoryRegion;
55
use bootloader_api::info::{FrameBufferInfo, PixelFormat};
66
use bootloader_boot_config::{BootConfig, LevelFilter};
7-
use bootloader_x86_64_bios_common::{BiosFramebufferInfo, BiosInfo, E820MemoryRegion};
7+
use bootloader_x86_64_bios_common::{BiosFramebufferInfo, BiosInfo, E820MemoryRegion, Region};
8+
use bootloader_x86_64_common::legacy_memory_region::UsedMemorySlice;
89
use bootloader_x86_64_common::RawFrameBufferInfo;
910
use bootloader_x86_64_common::{
1011
legacy_memory_region::LegacyFrameAllocator, load_and_switch_to_kernel, Kernel, PageTables,
@@ -55,9 +56,10 @@ pub extern "C" fn _start(info: &mut BiosInfo) -> ! {
5556
};
5657
let kernel_size = info.kernel.len;
5758
let next_free_frame = PhysFrame::containing_address(PhysAddr::new(info.last_used_addr)) + 1;
58-
let mut frame_allocator = LegacyFrameAllocator::new_starting_at(
59+
let mut frame_allocator = LegacyFrameAllocator::new_with_used_slices(
5960
next_free_frame,
6061
memory_map.iter().copied().map(MemoryRegion),
62+
used_memory_slices(info),
6163
);
6264

6365
// We identity-mapped all memory, so the offset between physical and virtual addresses is 0
@@ -216,6 +218,17 @@ fn init_logger(
216218
framebuffer_info
217219
}
218220

221+
fn used_memory_slices(info: &BiosInfo) -> impl Iterator<Item = UsedMemorySlice> {
222+
// skip kernel and ramdisk because they are handled individually by the
223+
// uefi/bios common code
224+
[info.stage_3, info.stage_4, info.config_file]
225+
.into_iter()
226+
.map(|region| UsedMemorySlice {
227+
start: PhysAddr::new(region.start),
228+
len: region.len,
229+
})
230+
}
231+
219232
/// Creates page table abstraction types for both the bootloader and kernel page tables.
220233
fn create_page_tables(frame_allocator: &mut impl FrameAllocator<Size4KiB>) -> PageTables {
221234
// We identity-mapped all memory, so the offset between physical and virtual addresses is 0

Diff for: common/src/legacy_memory_region.rs

+34-5
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,23 @@
11
use bootloader_api::info::{MemoryRegion, MemoryRegionKind};
2-
use core::mem::MaybeUninit;
2+
use core::{
3+
iter::{empty, Empty},
4+
mem::MaybeUninit,
5+
};
36
use x86_64::{
47
structures::paging::{FrameAllocator, PhysFrame, Size4KiB},
58
PhysAddr,
69
};
710

11+
/// A slice of memory that is used by the bootloader and needs to be reserved
12+
/// in the kernel
13+
#[derive(Clone, Copy, Debug)]
14+
pub struct UsedMemorySlice {
15+
/// the physical start of the slice
16+
pub start: PhysAddr,
17+
/// the length of the slice
18+
pub len: u64,
19+
}
20+
821
/// Abstraction trait for a memory region returned by the UEFI or BIOS firmware.
922
pub trait LegacyMemoryRegion: Copy + core::fmt::Debug {
1023
/// Returns the physical start address of the region.
@@ -23,18 +36,19 @@ pub trait LegacyMemoryRegion: Copy + core::fmt::Debug {
2336
}
2437

2538
/// A physical frame allocator based on a BIOS or UEFI provided memory map.
26-
pub struct LegacyFrameAllocator<I, D> {
39+
pub struct LegacyFrameAllocator<I, D, S> {
2740
original: I,
2841
memory_map: I,
2942
current_descriptor: Option<D>,
3043
next_frame: PhysFrame,
3144
min_frame: PhysFrame,
45+
used_slices: S,
3246
}
3347

3448
/// Start address of the first frame that is not part of the lower 1MB of frames
3549
const LOWER_MEMORY_END_PAGE: u64 = 0x100_000;
3650

37-
impl<I, D> LegacyFrameAllocator<I, D>
51+
impl<I, D> LegacyFrameAllocator<I, D, Empty<UsedMemorySlice>>
3852
where
3953
I: ExactSizeIterator<Item = D> + Clone,
4054
I::Item: LegacyMemoryRegion,
@@ -56,14 +70,28 @@ where
5670
/// before the given `frame` or `0x10000`(1MB) whichever is higher, there are use cases that require
5771
/// lower conventional memory access (Such as SMP SIPI).
5872
pub fn new_starting_at(frame: PhysFrame, memory_map: I) -> Self {
73+
Self::new_with_used_slices(frame, memory_map, empty())
74+
}
75+
}
76+
77+
impl<I, D, S> LegacyFrameAllocator<I, D, S>
78+
where
79+
I: ExactSizeIterator<Item = D> + Clone,
80+
I::Item: LegacyMemoryRegion,
81+
S: Iterator<Item = UsedMemorySlice>,
82+
{
83+
pub fn new_with_used_slices(start_frame: PhysFrame, memory_map: I, used_slices: S) -> Self {
84+
// skip frame 0 because the rust core library does not see 0 as a valid address
85+
// Also skip at least the lower 1MB of frames, there are use cases that require lower conventional memory access (Such as SMP SIPI).
5986
let lower_mem_end = PhysFrame::containing_address(PhysAddr::new(LOWER_MEMORY_END_PAGE));
60-
let frame = core::cmp::max(frame, lower_mem_end);
87+
let frame = core::cmp::max(start_frame, lower_mem_end);
6188
Self {
6289
original: memory_map.clone(),
6390
memory_map,
6491
current_descriptor: None,
6592
next_frame: frame,
6693
min_frame: frame,
94+
used_slices,
6795
}
6896
}
6997

@@ -318,10 +346,11 @@ where
318346
}
319347
}
320348

321-
unsafe impl<I, D> FrameAllocator<Size4KiB> for LegacyFrameAllocator<I, D>
349+
unsafe impl<I, D, S> FrameAllocator<Size4KiB> for LegacyFrameAllocator<I, D, S>
322350
where
323351
I: ExactSizeIterator<Item = D> + Clone,
324352
I::Item: LegacyMemoryRegion,
353+
S: Iterator<Item = UsedMemorySlice>,
325354
{
326355
fn allocate_frame(&mut self) -> Option<PhysFrame<Size4KiB>> {
327356
if let Some(current_descriptor) = self.current_descriptor {

Diff for: common/src/lib.rs

+10-6
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use bootloader_api::{
1010
};
1111
use bootloader_boot_config::{BootConfig, LevelFilter};
1212
use core::{alloc::Layout, arch::asm, mem::MaybeUninit, slice};
13+
use legacy_memory_region::UsedMemorySlice;
1314
use level_4_entries::UsedLevel4Entries;
1415
use usize_conversions::FromUsize;
1516
use x86_64::{
@@ -123,16 +124,17 @@ impl<'a> Kernel<'a> {
123124
/// This function is a convenience function that first calls [`set_up_mappings`], then
124125
/// [`create_boot_info`], and finally [`switch_to_kernel`]. The given arguments are passed
125126
/// directly to these functions, so see their docs for more info.
126-
pub fn load_and_switch_to_kernel<I, D>(
127+
pub fn load_and_switch_to_kernel<I, D, S>(
127128
kernel: Kernel,
128129
boot_config: BootConfig,
129-
mut frame_allocator: LegacyFrameAllocator<I, D>,
130+
mut frame_allocator: LegacyFrameAllocator<I, D, S>,
130131
mut page_tables: PageTables,
131132
system_info: SystemInfo,
132133
) -> !
133134
where
134135
I: ExactSizeIterator<Item = D> + Clone,
135136
D: LegacyMemoryRegion,
137+
S: Iterator<Item = UsedMemorySlice>,
136138
{
137139
let config = kernel.config;
138140
let mut mappings = set_up_mappings(
@@ -168,9 +170,9 @@ where
168170
///
169171
/// This function reacts to unexpected situations (e.g. invalid kernel ELF file) with a panic, so
170172
/// errors are not recoverable.
171-
pub fn set_up_mappings<I, D>(
173+
pub fn set_up_mappings<I, D, S>(
172174
kernel: Kernel,
173-
frame_allocator: &mut LegacyFrameAllocator<I, D>,
175+
frame_allocator: &mut LegacyFrameAllocator<I, D, S>,
174176
page_tables: &mut PageTables,
175177
framebuffer: Option<&RawFrameBufferInfo>,
176178
config: &BootloaderConfig,
@@ -179,6 +181,7 @@ pub fn set_up_mappings<I, D>(
179181
where
180182
I: ExactSizeIterator<Item = D> + Clone,
181183
D: LegacyMemoryRegion,
184+
S: Iterator<Item = UsedMemorySlice>,
182185
{
183186
let kernel_page_table = &mut page_tables.kernel;
184187

@@ -466,17 +469,18 @@ pub struct Mappings {
466469
/// address space at the same address. This makes it possible to return a Rust
467470
/// reference that is valid in both address spaces. The necessary physical frames
468471
/// are taken from the given `frame_allocator`.
469-
pub fn create_boot_info<I, D>(
472+
pub fn create_boot_info<I, D, S>(
470473
config: &BootloaderConfig,
471474
boot_config: &BootConfig,
472-
mut frame_allocator: LegacyFrameAllocator<I, D>,
475+
mut frame_allocator: LegacyFrameAllocator<I, D, S>,
473476
page_tables: &mut PageTables,
474477
mappings: &mut Mappings,
475478
system_info: SystemInfo,
476479
) -> &'static mut BootInfo
477480
where
478481
I: ExactSizeIterator<Item = D> + Clone,
479482
D: LegacyMemoryRegion,
483+
S: Iterator<Item = UsedMemorySlice>,
480484
{
481485
log::info!("Allocate bootinfo");
482486

0 commit comments

Comments
 (0)