diff --git a/build.rs b/build.rs index ac5756b5..c783fb16 100644 --- a/build.rs +++ b/build.rs @@ -1,8 +1,16 @@ #[cfg(not(feature = "binary"))] -fn main() {} +#[allow(unreachable_code)] +fn main() { + #[cfg(target_arch = "x86")] + panic!("This crate currently does not support 32-bit protected mode. \ + See https://github.com/rust-osdev/bootloader/issues/70 for more information."); + + #[cfg(not(target_arch = "x86_64"))] + panic!("This crate only supports the x86_64 architecture."); +} #[cfg(feature = "binary")] -fn address_from_env(env: &'static str) -> Option { +fn num_from_env(env: &'static str, aligned: bool) -> Option { use std::env; match env::var(env) { Err(env::VarError::NotPresent) => None, @@ -10,26 +18,26 @@ fn address_from_env(env: &'static str) -> Option { panic!("The `{}` environment variable must be valid unicode", env,) } Ok(s) => { - let addr = if s.starts_with("0x") { + let num = if s.starts_with("0x") { u64::from_str_radix(&s[2..], 16) } else { u64::from_str_radix(&s, 10) }; - let addr = addr.expect(&format!( + let num = num.expect(&format!( "The `{}` environment variable must be an integer\ (is `{}`).", env, s )); - if addr % 0x1000 != 0 { + if aligned && num % 0x1000 != 0 { panic!( "The `{}` environment variable must be aligned to 0x1000 (is `{:#x}`).", - env, addr + env, num ); } - Some(addr) + Some(num) } } } @@ -176,31 +184,26 @@ fn main() { process::exit(1); } - // create a file with the `PHYSICAL_MEMORY_OFFSET` constant - let file_path = out_dir.join("physical_memory_offset.rs"); - let mut file = File::create(file_path).expect("failed to create physical_memory_offset.rs"); - let physical_memory_offset = address_from_env("BOOTLOADER_PHYSICAL_MEMORY_OFFSET"); - file.write_all( - format!( - "const PHYSICAL_MEMORY_OFFSET: Option = {:?};", - physical_memory_offset - ) - .as_bytes(), - ) - .expect("write to physical_memory_offset.rs failed"); - - // create a file with the `KERNEL_STACK_ADDRESS` constant - let file_path = out_dir.join("kernel_stack_address.rs"); - let mut file = File::create(file_path).expect("failed to create kernel_stack_address.rs"); - let kernel_stack_address = address_from_env("BOOTLOADER_KERNEL_STACK_ADDRESS"); + // Configure constants for the bootloader + // We leave some variables as Option rather than hardcoding their defaults so that they + // can be calculated dynamically by the bootloader. + let file_path = out_dir.join("bootloader_config.rs"); + let mut file = File::create(file_path).expect("failed to create bootloader_config.rs"); + let physical_memory_offset = num_from_env("BOOTLOADER_PHYSICAL_MEMORY_OFFSET", true); + let kernel_stack_address = num_from_env("BOOTLOADER_KERNEL_STACK_ADDRESS", true); + let kernel_stack_size = num_from_env("BOOTLOADER_KERNEL_STACK_SIZE", false); file.write_all( format!( - "const KERNEL_STACK_ADDRESS: Option = {:?};", + "const PHYSICAL_MEMORY_OFFSET: Option = {:?}; + const KERNEL_STACK_ADDRESS: Option = {:?}; + const KERNEL_STACK_SIZE: u64 = {};", + physical_memory_offset, kernel_stack_address, + kernel_stack_size.unwrap_or(512), // size is in number of pages ) .as_bytes(), ) - .expect("write to kernel_stack_address.rs failed"); + .expect("write to bootloader_config.rs failed"); // pass link arguments to rustc println!("cargo:rustc-link-search=native={}", out_dir.display()); @@ -212,6 +215,7 @@ fn main() { println!("cargo:rerun-if-env-changed=KERNEL"); println!("cargo:rerun-if-env-changed=BOOTLOADER_PHYSICAL_MEMORY_OFFSET"); println!("cargo:rerun-if-env-changed=BOOTLOADER_KERNEL_STACK_ADDRESS"); + println!("cargo:rerun-if-env-changed=BOOTLOADER_KERNEL_STACK_SIZE"); println!("cargo:rerun-if-changed={}", kernel.display()); println!("cargo:rerun-if-changed=build.rs"); } diff --git a/src/main.rs b/src/main.rs index 381eed0f..6f4a4492 100644 --- a/src/main.rs +++ b/src/main.rs @@ -24,12 +24,14 @@ use x86_64::structures::paging::{ use x86_64::ux::u9; use x86_64::{PhysAddr, VirtAddr}; -// The offset into the virtual address space where the physical memory is mapped if -// the `map_physical_memory` is activated. Set by the build script. -include!(concat!(env!("OUT_DIR"), "/physical_memory_offset.rs")); - -// The virtual address of the kernel stack. Set by the build script. -include!(concat!(env!("OUT_DIR"), "/kernel_stack_address.rs")); +// The bootloader_config.rs file contains some configuration constants set by the build script: +// PHYSICAL_MEMORY_OFFSET: The offset into the virtual address space where the physical memory +// is mapped if the `map_physical_memory` feature is activated. +// +// KERNEL_STACK_ADDRESS: The virtual address of the kernel stack. +// +// KERNEL_STACK_SIZE: The number of pages in the kernel stack. +include!(concat!(env!("OUT_DIR"), "/bootloader_config.rs")); global_asm!(include_str!("stage_1.s")); global_asm!(include_str!("stage_2.s")); @@ -271,6 +273,7 @@ fn load_elf( let stack_end = page_table::map_kernel( kernel_start.phys(), kernel_stack_address, + KERNEL_STACK_SIZE, &segments, &mut rec_page_table, &mut frame_allocator, diff --git a/src/page_table.rs b/src/page_table.rs index 45f1aee3..6d7ef5a7 100644 --- a/src/page_table.rs +++ b/src/page_table.rs @@ -11,6 +11,7 @@ use xmas_elf::program::{self, ProgramHeader64}; pub(crate) fn map_kernel( kernel_start: PhysAddr, stack_start: Page, + stack_size: u64, segments: &FixedVec, page_table: &mut RecursivePageTable, frame_allocator: &mut FrameAllocator, @@ -20,9 +21,8 @@ pub(crate) fn map_kernel( } // Create a stack - let stack_size: u64 = 512; // in pages let stack_start = stack_start + 1; // Leave the first page unmapped as a 'guard page' - let stack_end = stack_start + stack_size; + let stack_end = stack_start + stack_size; // stack_size is in pages let flags = PageTableFlags::PRESENT | PageTableFlags::WRITABLE; let region_type = MemoryRegionType::KernelStack;