diff --git a/Cargo.lock b/Cargo.lock index 2ce48ac2..031c38a4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -350,6 +350,12 @@ dependencies = [ "locate-cargo-manifest", ] +[[package]] +name = "rustversion" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f" + [[package]] name = "scopeguard" version = "1.1.0" @@ -576,12 +582,13 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "x86_64" -version = "0.14.7" +version = "0.14.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb611915c917c6296d11e23f71ff1ecfe49c5766daba92cd3df52df6b58285b6" +checksum = "958cd5cb28e720db2f59ee9dc4235b5f82a183d079fb0e6caf43ad074cfdc66a" dependencies = [ "bit_field", "bitflags", + "rustversion", "volatile", ] diff --git a/Cargo.toml b/Cargo.toml index 2b39e8af..61c2b95d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,7 +35,7 @@ required-features = ["uefi_bin"] [dependencies] xmas-elf = { version = "0.8.0", optional = true } -x86_64 = { version = "0.14.7", optional = true, default-features = false, features = ["instructions", "inline_asm"] } +x86_64 = { version = "0.14.9", optional = true, default-features = false, features = ["instructions", "inline_asm", "step_trait"] } usize_conversions = { version = "0.2.0", optional = true } bit_field = { version = "0.10.0", optional = true } log = { version = "0.4.8", optional = true } diff --git a/build.rs b/build.rs index 2c4c46e7..c1d25f52 100644 --- a/build.rs +++ b/build.rs @@ -366,6 +366,8 @@ mod binary { pub framebuffer_address: Option, pub minimum_framebuffer_height: Option, pub minimum_framebuffer_width: Option, + pub dynamic_range_start: Option, + pub dynamic_range_end: Option, } /// Convert to tokens suitable for initializing the `Config` struct. @@ -387,6 +389,8 @@ mod binary { let framebuffer_address = optional(self.framebuffer_address); let minimum_framebuffer_height = optional(self.minimum_framebuffer_height); let minimum_framebuffer_width = optional(self.minimum_framebuffer_width); + let dynamic_range_start = optional(self.dynamic_range_start); + let dynamic_range_end = optional(self.dynamic_range_end); tokens.extend(quote! { Config { map_physical_memory: #map_physical_memory, @@ -400,7 +404,9 @@ mod binary { boot_info_address: #boot_info_address, framebuffer_address: #framebuffer_address, minimum_framebuffer_height: #minimum_framebuffer_height, - minimum_framebuffer_width: #minimum_framebuffer_width + minimum_framebuffer_width: #minimum_framebuffer_width, + dynamic_range_start: #dynamic_range_start, + dynamic_range_end: #dynamic_range_end, }}); } } diff --git a/src/binary/level_4_entries.rs b/src/binary/level_4_entries.rs index b62f2872..04afbe43 100644 --- a/src/binary/level_4_entries.rs +++ b/src/binary/level_4_entries.rs @@ -1,4 +1,4 @@ -use core::{alloc::Layout, convert::TryInto}; +use core::{alloc::Layout, convert::TryInto, iter::Step}; use rand::{ distributions::{Distribution, Uniform}, seq::IteratorRandom, @@ -70,6 +70,28 @@ impl UsedLevel4Entries { } } + // Mark everything before the dynamic range as unusable. + if let Some(dynamic_range_start) = CONFIG.dynamic_range_start { + let dynamic_range_start = VirtAddr::new(dynamic_range_start); + let start_page: Page = Page::containing_address(dynamic_range_start); + if let Some(unusable_page) = Step::backward_checked(start_page, 1) { + for i in 0..=u16::from(unusable_page.p4_index()) { + used.mark_p4_index_as_used(PageTableIndex::new(i)); + } + } + } + + // Mark everything after the dynamic range as unusable. + if let Some(dynamic_range_end) = CONFIG.dynamic_range_end { + let dynamic_range_end = VirtAddr::new(dynamic_range_end); + let end_page: Page = Page::containing_address(dynamic_range_end); + if let Some(unusable_page) = Step::forward_checked(end_page, 1) { + for i in u16::from(unusable_page.p4_index())..512 { + used.mark_p4_index_as_used(PageTableIndex::new(i)); + } + } + } + used } diff --git a/src/config.rs b/src/config.rs index de5b7cd2..8e0b31e8 100644 --- a/src/config.rs +++ b/src/config.rs @@ -33,7 +33,7 @@ const PAGE_SIZE: u64 = 4096; /// /// All memory addresses are optional, even if their corresponding switch is enabled. If no /// address is specified, the bootloader will choose an unused entry of the level 4 page table -/// at runtime. +/// at runtime. The addresses can be restricted by setting the `dynamic-range` configuration key. #[derive(Debug)] pub struct Config { /// Whether to create a virtual mapping of the complete physical memory. @@ -96,6 +96,14 @@ pub struct Config { /// `minimum_framebuffer_width` is supplied, and using the last available mode that /// fits them if 1 or more is set. pub minimum_framebuffer_width: Option, + /// The lowest virtual address for dynamic addresses. + /// + /// Defaults to `0`. + pub dynamic_range_start: Option, + /// The highest virtual address for dynamic addresses. + /// + /// Defaults to `0xffff_ffff_ffff_f000`. + pub dynamic_range_end: Option, } #[cfg(feature = "binary")] diff --git a/src/lib.rs b/src/lib.rs index be178dee..0155098d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -67,6 +67,7 @@ for all possible configuration options. #![cfg_attr(not(feature = "builder"), no_std)] #![feature(maybe_uninit_slice)] +#![feature(step_trait)] #![deny(unsafe_op_in_unsafe_fn)] #![warn(missing_docs)] diff --git a/tests/test_kernels/higher_half/Cargo.toml b/tests/test_kernels/higher_half/Cargo.toml index ba9ce580..99a7107d 100644 --- a/tests/test_kernels/higher_half/Cargo.toml +++ b/tests/test_kernels/higher_half/Cargo.toml @@ -8,3 +8,6 @@ edition = "2018" bootloader = { path = "../../.." } x86_64 = { version = "0.14.7", default-features = false, features = ["instructions", "inline_asm"] } uart_16550 = "0.2.10" + +[package.metadata.bootloader] +dynamic-range-start = "0xffff_8000_0000_0000" diff --git a/tests/test_kernels/higher_half/src/bin/verify_higher_half.rs b/tests/test_kernels/higher_half/src/bin/verify_higher_half.rs index f081b99a..8e982919 100644 --- a/tests/test_kernels/higher_half/src/bin/verify_higher_half.rs +++ b/tests/test_kernels/higher_half/src/bin/verify_higher_half.rs @@ -7,11 +7,25 @@ use test_kernel_higher_half::{exit_qemu, QemuExitCode}; entry_point!(kernel_main); -fn kernel_main(_boot_info: &'static mut BootInfo) -> ! { +fn kernel_main(boot_info: &'static mut BootInfo) -> ! { // verify that kernel is really running in the higher half of the address space // (set in `x86_64-higher_half.json` custom target) let rip = x86_64::registers::read_rip().as_u64(); assert_eq!(rip & 0xffffffffffff0000, 0xffff800000000000); + + // verify that the boot info is located in the higher half of the address space + assert_eq!( + (boot_info as *const _ as usize) & 0xffff800000000000, + 0xffff800000000000 + ); + + // verify that the stack is located in the higher half of the address space. + let stack_addr = &rip; + assert_eq!( + (boot_info as *const _ as usize) & 0xffff800000000000, + 0xffff800000000000 + ); + exit_qemu(QemuExitCode::Success); }