Skip to content

Commit

Permalink
Merge #72
Browse files Browse the repository at this point in the history
72: Configurable kernel stack size, better non-x86_64 errors r=phil-opp a=64

Allows the configuration of the kernel stack size through an environment variable.

Also makes the errors a bit nicer if you try to use this crate from a non-x86_64 architecture (only works if you build it as a library), as discussed in #70.

Co-authored-by: Matt Taylor <mstaveleytaylor@gmail.com>
  • Loading branch information
bors[bot] and 64 committed Aug 5, 2019
2 parents 12242da + 2fdd1f2 commit 24a4cae
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 34 deletions.
56 changes: 30 additions & 26 deletions build.rs
Original file line number Diff line number Diff line change
@@ -1,35 +1,43 @@
#[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<u64> {
fn num_from_env(env: &'static str, aligned: bool) -> Option<u64> {
use std::env;
match env::var(env) {
Err(env::VarError::NotPresent) => None,
Err(env::VarError::NotUnicode(_)) => {
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)
}
}
}
Expand Down Expand Up @@ -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<u64> = {:?};",
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<T> 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<u64> = {:?};",
"const PHYSICAL_MEMORY_OFFSET: Option<u64> = {:?};
const KERNEL_STACK_ADDRESS: Option<u64> = {:?};
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());
Expand All @@ -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");
}
15 changes: 9 additions & 6 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"));
Expand Down Expand Up @@ -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,
Expand Down
4 changes: 2 additions & 2 deletions src/page_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<ProgramHeader64>,
page_table: &mut RecursivePageTable,
frame_allocator: &mut FrameAllocator,
Expand All @@ -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;
Expand Down

0 comments on commit 24a4cae

Please sign in to comment.