From 3f225e645adb854533dbfa95150d6d467b8d27d0 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Fri, 22 Mar 2019 01:38:49 +0100 Subject: [PATCH 01/10] Rewrite the build system using a build script --- Cargo.toml | 1 + build.rs | 135 ++++++++++++++++++++++++++++++++++++++++++++ builder/src/main.rs | 1 + linker.ld | 12 ++-- src/main.rs | 6 +- src/stage_1.s | 2 +- src/stage_2.s | 2 +- src/stage_3.s | 2 +- 8 files changed, 149 insertions(+), 12 deletions(-) create mode 100644 build.rs diff --git a/Cargo.toml b/Cargo.toml index 635717a4..97789341 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,7 @@ description = "An experimental pure-Rust x86 bootloader." repository = "https://github.com/rust-osdev/bootloader" publish-lockfile = true edition = "2018" +build = "build.rs" [dependencies] xmas-elf = "0.6.2" diff --git a/build.rs b/build.rs new file mode 100644 index 00000000..f6785e08 --- /dev/null +++ b/build.rs @@ -0,0 +1,135 @@ +use std::{env, path::{Path, PathBuf}, process::{self, Command}}; + +fn main() { + let target = env::var("TARGET").expect("TARGET not set"); + if Path::new(&target) + .file_stem() + .expect("target has no file stem") + != "x86_64-bootloader" + { + return; + } + + let out_dir = PathBuf::from(env::var("OUT_DIR").expect("OUT_DIR not set")); + let kernel = PathBuf::from(match env::var("KERNEL") { + Ok(kernel) => kernel, + Err(_) => { + eprintln!( + "The KERNEL environment variable must be set for building the bootloader." + ); + process::exit(1); + } + }); + let kernel_file_name = kernel.file_name().expect("KERNEL has no valid file name").to_str().expect("kernel file name not valid utf8"); + let kernel_out_path = out_dir.join(format!("kernel_bin-{}.o", kernel_file_name)); + let kernel_archive_path = out_dir.join(format!("libkernel_bin-{}.a", kernel_file_name)); + + + let bin_dir = BinDir::new(); + let objcopy = bin_dir.tool(&LlvmTool::tool_name("objcopy")).expect("llvm-objcopy not found in llvm-tools"); + + let mut cmd = Command::new(objcopy.path()); + cmd.arg("-I").arg("binary"); + cmd.arg("-O").arg("elf64-x86-64"); + cmd.arg("--binary-architecture=i386:x86-64"); + cmd.arg("--rename-section").arg(".data=.kernel"); + cmd.arg("--redefine-sym").arg(format!("_binary_{}_start=_kernel_start_addr", kernel_file_name)); + cmd.arg("--redefine-sym").arg(format!("_binary_{}_end=_kernel_end_addr", kernel_file_name)); + cmd.arg("--redefine-sym").arg(format!("_binary_{}_size=_kernel_size", kernel_file_name)); + cmd.current_dir(kernel.parent().expect("KERNEL has no valid parent dir")); + cmd.arg(&kernel_file_name); + cmd.arg(&kernel_out_path); + let exit_status = cmd.status().expect("failed to run objcopy"); + if !exit_status.success() { + eprintln!("Error: Running objcopy failed"); + process::exit(1); + } + + let ar = bin_dir.tool(&LlvmTool::tool_name("ar")).expect("llvm-ar not found in llvm-tools"); + let mut cmd = Command::new(ar.path()); + cmd.arg("crs"); + cmd.arg(&kernel_archive_path); + cmd.arg(&kernel_out_path); + let exit_status = cmd.status().expect("failed to run ar"); + if !exit_status.success() { + eprintln!("Error: Running ar failed"); + process::exit(1); + } + + println!("cargo:rerun-if-changed={}", kernel.display()); + println!("cargo:rerun-if-changed=build.rs"); + println!("cargo:rustc-link-search=native={}", out_dir.display()); + println!("cargo:rustc-link-lib=static=kernel_bin-{}", kernel_file_name); +} + +#[derive(Debug)] +struct BinDir { + bin_dir: PathBuf, +} + +impl BinDir { + fn new() -> Self { + let example_tool_name = LlvmTool::tool_name("objdump"); + let output = Command::new("rustc") + .arg("--print") + .arg("sysroot") + .output() + .expect("failed to print sysroot"); + if !output.status.success() { + eprintln!("Failed to execute `rustc --print sysroot`"); + eprintln!("Stderr: {}", String::from_utf8(output.stderr).expect("error not valid unicode")); + process::exit(1); + } + + let sysroot = PathBuf::from(String::from_utf8(output.stdout).expect("sysroot not valid unicode").trim()); + + let rustlib = sysroot.join("lib").join("rustlib"); + for entry in rustlib.read_dir().expect("read_dir on sysroot dir failed") { + let bin_dir = entry.expect("failed to read sysroot dir entry").path().join("bin"); + let tool_path = bin_dir.join(&example_tool_name); + if tool_path.exists() { + return Self { bin_dir }; + } + } + + eprintln!("Error: llvm-tools not found"); + eprintln!("Maybe the rustup component `llvm-tools-preview` is missing?"); + eprintln!(" Install it through: `rustup component add llvm-tools-preview`"); + process::exit(1); + } + + fn tool(&self, tool_name: &str) -> Option { + let tool_path = self.bin_dir.join(&tool_name); + + if tool_path.exists() { + Some(LlvmTool { + name: tool_name.to_owned(), + path: tool_path, + }) + } else { + None + } + } +} + +#[derive(Debug)] +struct LlvmTool { + name: String, + path: PathBuf, +} + +impl LlvmTool { + fn path(&self) -> &Path { + &self.path + } + + #[cfg(target_os = "windows")] + fn tool_name(tool: &str) -> String { + format!("llvm-{}.exe", tool) + } + + #[cfg(not(target_os = "windows"))] + fn tool_name(tool: &str) -> String { + format!("llvm-{}", tool) + } +} diff --git a/builder/src/main.rs b/builder/src/main.rs index 8046388a..f5884a10 100644 --- a/builder/src/main.rs +++ b/builder/src/main.rs @@ -152,6 +152,7 @@ fn run_xbuild(args: &[String]) -> io::Result { command.args(args); let exit_status = command.status()?; + if !exit_status.success() { let mut help_command = process::Command::new("cargo"); help_command.arg("xbuild").arg("--help"); diff --git a/linker.ld b/linker.ld index 119e697a..4e58320a 100644 --- a/linker.ld +++ b/linker.ld @@ -40,13 +40,11 @@ SECTIONS { *(.got) . = ALIGN(512); _rest_of_bootloader_end_addr = .; + __bootloader_end = .; } - _kernel_info_block_start = .; - _kib_kernel_size = .; - . += 512; /* kernel info block */ - _kernel_info_block_end = .; - - __bootloader_end = .; - _kernel_start_addr = .; + .kernel : + { + KEEP(*(.kernel)) + } } diff --git a/src/main.rs b/src/main.rs index 742985fe..2dfa79b4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -63,7 +63,9 @@ impl IdentityMappedAddr { extern "C" { static mmap_ent: usize; static _memory_map: usize; - static _kib_kernel_size: usize; + static _kernel_start_addr: usize; + static _kernel_end_addr: usize; + static _kernel_size: usize; static __page_table_start: usize; static __page_table_end: usize; static __bootloader_end: usize; @@ -77,7 +79,7 @@ pub unsafe extern "C" fn stage_4() -> ! { mov ss, bx" ::: "bx" : "intel"); let kernel_start = 0x400000; - let kernel_size = _kib_kernel_size as u64; + let kernel_size = &_kernel_size as *const _ as u64; let memory_map_addr = &_memory_map as *const _ as u64; let memory_map_entry_count = (mmap_ent & 0xff) as u64; // Extract lower 8 bits let page_table_start = &__page_table_start as *const _ as u64; diff --git a/src/stage_1.s b/src/stage_1.s index 74ba5f7a..ebfa1a08 100644 --- a/src/stage_1.s +++ b/src/stage_1.s @@ -84,7 +84,7 @@ load_rest_of_bootloader_from_disk: mov [dap_buffer_addr], ax # number of disk blocks to load - lea ebx, _kernel_info_block_end + lea ebx, _rest_of_bootloader_end_addr sub ebx, eax # end - start shr ebx, 9 # divide by 512 (block size) mov [dap_blocks], bx diff --git a/src/stage_2.s b/src/stage_2.s index 7a39088e..5486439a 100644 --- a/src/stage_2.s +++ b/src/stage_2.s @@ -50,7 +50,7 @@ load_kernel_from_disk: mov edi, 0x400000 # block count - mov ecx, _kib_kernel_size + lea ecx, _kernel_size add ecx, 511 # align up shr ecx, 9 diff --git a/src/stage_3.s b/src/stage_3.s index 71121f96..0e7c03f7 100644 --- a/src/stage_3.s +++ b/src/stage_3.s @@ -52,7 +52,7 @@ set_up_page_tables: mov [_p2], eax mov eax, (0x400000 | 1 | 2 | (1 << 7)) mov ecx, 2 - mov edx, _kib_kernel_size + lea edx, _kernel_size add edx, 0x400000 # start address add edx, 0x200000 - 1 # align up shr edx, 12 + 9 # end huge page number From 3f2c575d7f5a48374f9d4c353024735eed45f66a Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Fri, 22 Mar 2019 19:05:11 +0100 Subject: [PATCH 02/10] Use x86_64-bootloader.json as default target --- .cargo/config | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .cargo/config diff --git a/.cargo/config b/.cargo/config new file mode 100644 index 00000000..70ad1c6a --- /dev/null +++ b/.cargo/config @@ -0,0 +1,2 @@ +[build] +target = "x86_64-bootloader.json" \ No newline at end of file From d69925fe3d4a54e8ea3569ff5d940339b165dec8 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Sat, 23 Mar 2019 16:04:30 +0100 Subject: [PATCH 03/10] Factor out BinDir code into llvm-tools crate --- Cargo.lock | 7 ++++ Cargo.toml | 3 ++ build.rs | 100 ++++++++++++----------------------------------------- 3 files changed, 32 insertions(+), 78 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1a8182d5..97cb59c6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -24,6 +24,7 @@ version = "0.4.0" dependencies = [ "fixedvec 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "font8x8 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "llvm-tools 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "x86_64 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "xmas-elf 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -60,6 +61,11 @@ name = "libc" version = "0.2.48" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "llvm-tools" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "nodrop" version = "0.1.13" @@ -206,6 +212,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" "checksum getopts 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "0a7292d30132fb5424b354f5dc02512a86e4c516fe544bb7a25e7f266951b797" "checksum libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)" = "e962c7641008ac010fa60a7dfdc1712449f29c44ef2d4702394aea943ee75047" +"checksum llvm-tools 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "955be5d0ca0465caf127165acb47964f911e2bc26073e865deb8be7189302faf" "checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" "checksum os_bootinfo 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "66481dbeb5e773e7bd85b63cd6042c30786f834338288c5ec4f3742673db360a" "checksum pulldown-cmark 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8361e81576d2e02643b04950e487ec172b687180da65c731c03cf336784e6c07" diff --git a/Cargo.toml b/Cargo.toml index 97789341..56282710 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,6 +22,9 @@ version = "0.2.4" default-features = false features = ["unicode"] +[build-dependencies] +llvm-tools = "0.1" + [features] default = [] vga_320x200 = [] diff --git a/build.rs b/build.rs index f6785e08..80ac965e 100644 --- a/build.rs +++ b/build.rs @@ -24,11 +24,22 @@ fn main() { let kernel_out_path = out_dir.join(format!("kernel_bin-{}.o", kernel_file_name)); let kernel_archive_path = out_dir.join(format!("libkernel_bin-{}.a", kernel_file_name)); + let llvm_tools = match llvm_tools::LlvmTools::new() { + Ok(tools) => tools, + Err(llvm_tools::Error::NotFound) => { + eprintln!("Error: llvm-tools not found"); + eprintln!("Maybe the rustup component `llvm-tools-preview` is missing?"); + eprintln!(" Install it through: `rustup component add llvm-tools-preview`"); + process::exit(1); + } + Err(err) => { + eprintln!("Failed to retrieve llvm-tools component: {:?}", err); + process::exit(1); + } + }; + let objcopy = llvm_tools.tool(&llvm_tools::exe("llvm-objcopy")).expect("llvm-objcopy not found in llvm-tools"); - let bin_dir = BinDir::new(); - let objcopy = bin_dir.tool(&LlvmTool::tool_name("objcopy")).expect("llvm-objcopy not found in llvm-tools"); - - let mut cmd = Command::new(objcopy.path()); + let mut cmd = Command::new(objcopy); cmd.arg("-I").arg("binary"); cmd.arg("-O").arg("elf64-x86-64"); cmd.arg("--binary-architecture=i386:x86-64"); @@ -45,8 +56,13 @@ fn main() { process::exit(1); } - let ar = bin_dir.tool(&LlvmTool::tool_name("ar")).expect("llvm-ar not found in llvm-tools"); - let mut cmd = Command::new(ar.path()); + let ar = llvm_tools.tool(&llvm_tools::exe("llvm-ar")).unwrap_or_else(|| { + eprintln!("Failed to retrieve llvm-ar component"); + eprint!("This component is available since nightly-XXXX-XX-XX,"); + eprintln!("so try updating your toolchain if you're using an older nightly"); + process::exit(1); + }); + let mut cmd = Command::new(ar); cmd.arg("crs"); cmd.arg(&kernel_archive_path); cmd.arg(&kernel_out_path); @@ -61,75 +77,3 @@ fn main() { println!("cargo:rustc-link-search=native={}", out_dir.display()); println!("cargo:rustc-link-lib=static=kernel_bin-{}", kernel_file_name); } - -#[derive(Debug)] -struct BinDir { - bin_dir: PathBuf, -} - -impl BinDir { - fn new() -> Self { - let example_tool_name = LlvmTool::tool_name("objdump"); - let output = Command::new("rustc") - .arg("--print") - .arg("sysroot") - .output() - .expect("failed to print sysroot"); - if !output.status.success() { - eprintln!("Failed to execute `rustc --print sysroot`"); - eprintln!("Stderr: {}", String::from_utf8(output.stderr).expect("error not valid unicode")); - process::exit(1); - } - - let sysroot = PathBuf::from(String::from_utf8(output.stdout).expect("sysroot not valid unicode").trim()); - - let rustlib = sysroot.join("lib").join("rustlib"); - for entry in rustlib.read_dir().expect("read_dir on sysroot dir failed") { - let bin_dir = entry.expect("failed to read sysroot dir entry").path().join("bin"); - let tool_path = bin_dir.join(&example_tool_name); - if tool_path.exists() { - return Self { bin_dir }; - } - } - - eprintln!("Error: llvm-tools not found"); - eprintln!("Maybe the rustup component `llvm-tools-preview` is missing?"); - eprintln!(" Install it through: `rustup component add llvm-tools-preview`"); - process::exit(1); - } - - fn tool(&self, tool_name: &str) -> Option { - let tool_path = self.bin_dir.join(&tool_name); - - if tool_path.exists() { - Some(LlvmTool { - name: tool_name.to_owned(), - path: tool_path, - }) - } else { - None - } - } -} - -#[derive(Debug)] -struct LlvmTool { - name: String, - path: PathBuf, -} - -impl LlvmTool { - fn path(&self) -> &Path { - &self.path - } - - #[cfg(target_os = "windows")] - fn tool_name(tool: &str) -> String { - format!("llvm-{}.exe", tool) - } - - #[cfg(not(target_os = "windows"))] - fn tool_name(tool: &str) -> String { - format!("llvm-{}", tool) - } -} From dda869e1b99ff40d992df5eb6b3e338b1a5bf506 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Sat, 23 Mar 2019 16:04:58 +0100 Subject: [PATCH 04/10] Remove `builder` sub-crate --- builder/.gitignore | 2 - builder/Cargo.lock | 74 --------------- builder/Cargo.toml | 11 --- builder/src/main.rs | 225 -------------------------------------------- 4 files changed, 312 deletions(-) delete mode 100644 builder/.gitignore delete mode 100644 builder/Cargo.lock delete mode 100644 builder/Cargo.toml delete mode 100644 builder/src/main.rs diff --git a/builder/.gitignore b/builder/.gitignore deleted file mode 100644 index eccd7b4a..00000000 --- a/builder/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/target/ -**/*.rs.bk diff --git a/builder/Cargo.lock b/builder/Cargo.lock deleted file mode 100644 index 2493a19c..00000000 --- a/builder/Cargo.lock +++ /dev/null @@ -1,74 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "args" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "getopts 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "builder" -version = "0.1.0" -dependencies = [ - "args 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "getopts 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", - "xmas-elf 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "byteorder" -version = "1.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "cfg-if" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "getopts" -version = "0.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "log" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "unicode-width" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "xmas-elf" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "zero 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "zero" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[metadata] -"checksum args 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d4b7432c65177b8d5c032d56e020dd8d407e939468479fc8c300e2d93e6d970b" -"checksum byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "94f88df23a25417badc922ab0f5716cc1330e87f71ddd9203b3a3ccd9cedf75d" -"checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4" -"checksum getopts 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "0a7292d30132fb5424b354f5dc02512a86e4c516fe544bb7a25e7f266951b797" -"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6" -"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" -"checksum xmas-elf 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "22678df5df766e8d1e5d609da69f0c3132d794edf6ab5e75e7abcd2270d4cf58" -"checksum zero 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5f1bc8a6b2005884962297587045002d8cfb8dcec9db332f4ca216ddc5de82c5" diff --git a/builder/Cargo.toml b/builder/Cargo.toml deleted file mode 100644 index 30eb8319..00000000 --- a/builder/Cargo.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "builder" -version = "0.1.0" -authors = ["Philipp Oppermann "] -edition = "2018" - -[dependencies] -xmas-elf = "0.6.2" -byteorder = "1.2.7" -args = "2.2.0" -getopts = "0.2.18" diff --git a/builder/src/main.rs b/builder/src/main.rs deleted file mode 100644 index f5884a10..00000000 --- a/builder/src/main.rs +++ /dev/null @@ -1,225 +0,0 @@ -use args::Args; -use byteorder::{ByteOrder, LittleEndian}; -use std::{ - fs::File, - io::{self, Read, Write}, - path::Path, - process, -}; - -const PROGRAM_NAME: &'static str = "builder"; -const PROGRAM_DESC: &'static str = "Builds the bootloader crate."; - -const BLOCK_SIZE: usize = 512; -type KernelInfoBlock = [u8; BLOCK_SIZE]; - -fn main() { - let mut args = args(); - - if help_arg_present() { - println!("{}", args.full_usage()); - process::exit(0); - } - - if let Err(args_err) = args.parse_from_cli() { - writeln!(io::stderr(), "{}", args_err).expect("Failed to write to stderr"); - process::exit(1); - }; - - // load kernel - - let kernel_path: String = args.value_of("kernel").unwrap(); - let kernel_path = Path::new(&kernel_path); - let mut kernel_file = match File::open(kernel_path) { - Ok(file) => file, - Err(err) => { - writeln!( - io::stderr(), - "Failed to open kernel at {:?}: {}", - kernel_path, - err - ) - .expect("Failed to write to stderr"); - process::exit(1); - } - }; - let kernel_size = kernel_file - .metadata() - .map(|m| m.len()) - .unwrap_or_else(|err| { - writeln!(io::stderr(), "Failed to read size of kernel: {}", err) - .expect("Failed to write to stderr"); - process::exit(1); - }); - let kernel_info_block = create_kernel_info_block(kernel_size, None); - - // build bootloader - - let mut build_args = vec![ - "--manifest-path".into(), - "../Cargo.toml".into(), - "--target".into(), - "../x86_64-bootloader.json".into(), - "--release".into(), - ]; - if args.value_of("no-default-features").unwrap() { - build_args.push("--no-default-features".into()); - } - if args.value_of("all-features").unwrap() { - build_args.push("--all-features".into()); - } - if let Some(features) = args.optional_value_of("features").unwrap() { - build_args.push("--features".into()); - build_args.push(features); - } - - let exit_status = run_xbuild(&build_args); - if !exit_status.map(|s| s.success()).unwrap_or(false) { - process::exit(1) - } - - let bootloader_elf_path = Path::new("../target/x86_64-bootloader/release/bootloader"); - let mut bootloader_elf_bytes = Vec::new(); - File::open(bootloader_elf_path) - .and_then(|mut f| f.read_to_end(&mut bootloader_elf_bytes)) - .expect("failed to read bootloader ELF file"); - - // read bootloader section of ELF file - - let elf_file = xmas_elf::ElfFile::new(&bootloader_elf_bytes).unwrap(); - xmas_elf::header::sanity_check(&elf_file).unwrap(); - let bootloader_section = elf_file - .find_section_by_name(".bootloader") - .expect("bootloader must have a .bootloader section"); - let bootloader_bytes = bootloader_section.raw_data(&elf_file); - - // create output file - - let output_file_path = Path::new("../target/x86_64-bootloader/release/bootimage.bin"); - - let mut output_file = File::create(output_file_path).expect("Failed to create output file"); - output_file - .write_all(bootloader_bytes) - .expect("Failed to write bootloader bytes to output file"); - output_file - .write_all(&kernel_info_block) - .expect("Failed to write kernel info block to output file"); - - write_file_to_file(&mut output_file, &mut kernel_file) - .expect("Failed to write kernel to output file"); - pad_file(&mut output_file, kernel_size as usize, &[0; 512]).expect("Failed to pad file"); -} - -fn args() -> Args { - use getopts::Occur; - - let mut args = Args::new(PROGRAM_NAME, PROGRAM_DESC); - args.flag("h", "help", "Prints the help message"); - args.option( - "", - "kernel", - "Path to the kernel ELF file", - "KERNEL_PATH", - Occur::Req, - None, - ); - args.option( - "", - "features", - "Space-separated list of features to activate", - "FEATURES", - Occur::Optional, - None, - ); - args.flag("", "all-features", "Activate all available features"); - args.flag( - "", - "no-default-features", - "Do not activate the `default` feature", - ); - args -} - -fn help_arg_present() -> bool { - std::env::args() - .find(|a| a == "--help" || a == "-h") - .is_some() -} - -fn run_xbuild(args: &[String]) -> io::Result { - let mut command = process::Command::new("cargo"); - command.arg("xbuild"); - command.args(args); - let exit_status = command.status()?; - - - if !exit_status.success() { - let mut help_command = process::Command::new("cargo"); - help_command.arg("xbuild").arg("--help"); - help_command.stdout(process::Stdio::null()); - help_command.stderr(process::Stdio::null()); - if let Ok(help_exit_status) = help_command.status() { - if !help_exit_status.success() { - let mut stderr = io::stderr(); - writeln!( - stderr, - "Failed to run `cargo xbuild`. Perhaps it is not installed?" - )?; - writeln!(stderr, "Run `cargo install cargo-xbuild` to install it.")?; - } - } - } - - Ok(exit_status) -} - -fn create_kernel_info_block(kernel_size: u64, maybe_package_size: Option) -> KernelInfoBlock { - let kernel_size = if kernel_size <= u64::from(u32::max_value()) { - kernel_size as u32 - } else { - panic!("Kernel can't be loaded by BIOS bootloader because is too big") - }; - - let package_size = if let Some(size) = maybe_package_size { - if size <= u64::from(u32::max_value()) { - size as u32 - } else { - panic!("Package can't be loaded by BIOS bootloader because is too big") - } - } else { - 0 - }; - - let mut kernel_info_block = [0u8; BLOCK_SIZE]; - LittleEndian::write_u32(&mut kernel_info_block[0..4], kernel_size); - LittleEndian::write_u32(&mut kernel_info_block[8..12], package_size); - - kernel_info_block -} - -fn write_file_to_file(output: &mut File, datafile: &mut File) -> io::Result<()> { - let data_size = datafile.metadata()?.len(); - let mut buffer = [0u8; 1024]; - let mut acc = 0; - loop { - let (n, interrupted) = match datafile.read(&mut buffer) { - Ok(0) => break, - Ok(n) => (n, false), - Err(ref e) if e.kind() == io::ErrorKind::Interrupted => (0, true), - Err(e) => Err(e)?, - }; - if !interrupted { - acc += n; - output.write_all(&buffer[..n])? - } - } - - assert!(data_size == acc as u64); - - Ok(()) -} - -fn pad_file(output: &mut File, written_size: usize, padding: &[u8]) -> io::Result<()> { - let padding_size = (padding.len() - (written_size % padding.len())) % padding.len(); - output.write_all(&padding[..padding_size]) -} From 7861cac16fc712edb2c0f524e028c1479a84d828 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Sat, 23 Mar 2019 16:18:25 +0100 Subject: [PATCH 05/10] Add trailing newline --- .cargo/config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.cargo/config b/.cargo/config index 70ad1c6a..fb871b1b 100644 --- a/.cargo/config +++ b/.cargo/config @@ -1,2 +1,2 @@ [build] -target = "x86_64-bootloader.json" \ No newline at end of file +target = "x86_64-bootloader.json" From 1a17c6322e7e4206a262ad46f6097a3df9744bf3 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Sat, 23 Mar 2019 16:19:02 +0100 Subject: [PATCH 06/10] Use compile_error to fail compilation for wrong target --- src/main.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main.rs b/src/main.rs index 2dfa79b4..19160543 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,6 +7,9 @@ #![no_std] #![no_main] +#[cfg(not(target_os = "none"))] +compile_error!("The bootloader crate must be compiled for the `x86_64-bootloader.json` target"); + use bootloader::bootinfo::{BootInfo, FrameRange}; use core::panic::PanicInfo; use core::{mem, slice}; From e82169ac1ce85728fcfa8de2f0d1d72bc23efdf9 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Sat, 23 Mar 2019 16:24:36 +0100 Subject: [PATCH 07/10] Delete travis CI script --- .travis.yml | 45 --------------------------------------------- 1 file changed, 45 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 3915a6fd..00000000 --- a/.travis.yml +++ /dev/null @@ -1,45 +0,0 @@ -language: rust - -rust: -- nightly - -os: - - linux - - osx - - windows - -cache: - directories: - - $HOME/.cargo - - $HOME/Library/Caches/Homebrew - - $TRAVIS_BUILD_DIR/target - - $TRAVIS_BUILD_DIR/example-kernel/target - -addons: - apt: - packages: - - qemu-system-x86 - homebrew: - packages: - - qemu - -install: - - if [ $TRAVIS_OS_NAME = windows ]; then choco install qemu; export PATH="/c/Program Files/qemu:$PATH"; fi - -before_script: -- rustup component add rust-src -- "(test -x $HOME/.cargo/bin/cargo-xbuild || cargo install cargo-xbuild)" - -sudo: false - -notifications: - email: - on_success: never - on_failure: change - -script: -- cd example-kernel; cargo xbuild --target x86_64-example-kernel.json; cd .. -- cd builder; cargo run -- --kernel ../example-kernel/target/x86_64-example-kernel/debug/example-kernel; cd .. -- qemu-system-x86_64 -drive format=raw,file=target/x86_64-bootloader/release/bootimage.bin -device isa-debug-exit,iobase=0xf4,iosize=0x04 -display none; if [ $? -eq 123 ]; then (exit 0); else (exit 1); fi -- cd builder; cargo run -- --kernel ../example-kernel/target/x86_64-example-kernel/debug/example-kernel --features vga_320x200; cd .. -- qemu-system-x86_64 -drive format=raw,file=target/x86_64-bootloader/release/bootimage.bin -device isa-debug-exit,iobase=0xf4,iosize=0x04 -display none; if [ $? -eq 123 ]; then (exit 0); else (exit 1); fi From 98a33dcb23bdb1537292f66f16b1f208f057e1db Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Sat, 23 Mar 2019 16:24:57 +0100 Subject: [PATCH 08/10] Update azure pipelines script for new build system --- azure-pipelines.yml | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index e6111986..c7b8f1ae 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -10,8 +10,6 @@ trigger: - trying # Build pull requests. - master - # Build post braches - - post-* strategy: matrix: @@ -64,11 +62,11 @@ steps: displayName: 'Print Rust Version' continueOnError: true -- script: rustup component add rust-src - displayName: 'Install Rustup Src Component' +- script: rustup component add rust-src llvm-tools-preview + displayName: 'Install Rustup Components' -- script: cargo install cargo-xbuild bootimage --debug - displayName: 'Install cargo-xbuild and bootimage' +- script: cargo install cargo-xbuild cargo-binutils --debug + displayName: 'Install cargo-xbuild cargo-binutils' - script: sudo apt update && sudo apt install qemu-system-x86 condition: eq( variables['Agent.OS'], 'Linux' ) @@ -96,20 +94,15 @@ steps: workingDirectory: example-kernel displayName: 'Build Example Kernel' -- script: cargo run -- --kernel ../example-kernel/target/x86_64-example-kernel/debug/example-kernel - workingDirectory: builder +- script: cargo xbuild --release displayName: 'Build Bootloader' + env: { KERNEL: "example-kernel/target/x86_64-example-kernel/debug/example-kernel" } + +- script: cargo objcopy -- -I elf64-x86-64 -O binary --binary-architecture=i386:x86-64 target/x86_64-bootloader/release/bootloader target/x86_64-bootloader/release/bootloader.bin + displayName: 'Convert Bootloader ELF to Binary' - bash: | - qemu-system-x86_64 -drive format=raw,file=target/x86_64-bootloader/release/bootimage.bin -device isa-debug-exit,iobase=0xf4,iosize=0x04 -display none + qemu-system-x86_64 -drive format=raw,file=target/x86_64-bootloader/release/bootloader.bin -device isa-debug-exit,iobase=0xf4,iosize=0x04 -display none if [ $? -eq 123 ]; then (exit 0); else (exit 1); fi displayName: 'Test Bootloader' -- script: cargo run -- --kernel ../example-kernel/target/x86_64-example-kernel/debug/example-kernel --features vga_320x200 - workingDirectory: builder - displayName: 'Build Bootloader (Feature vga_320x200)' - -- bash: | - qemu-system-x86_64 -drive format=raw,file=target/x86_64-bootloader/release/bootimage.bin -device isa-debug-exit,iobase=0xf4,iosize=0x04 -display none - if [ $? -eq 123 ]; then (exit 0); else (exit 1); fi - displayName: 'Test Bootloader (Feature vga_320x200)' From b93414f8a0df105b78f86f0ddb8e32b2eea77030 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Mon, 25 Mar 2019 19:16:22 +0100 Subject: [PATCH 09/10] Objcopy replaces `-` with `_` in the generated symbols --- build.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/build.rs b/build.rs index 80ac965e..e2c4b0e9 100644 --- a/build.rs +++ b/build.rs @@ -20,7 +20,9 @@ fn main() { process::exit(1); } }); + let kernel_file_name = kernel.file_name().expect("KERNEL has no valid file name").to_str().expect("kernel file name not valid utf8"); + let kernel_file_name_replaced = kernel_file_name.replace('-', "_"); let kernel_out_path = out_dir.join(format!("kernel_bin-{}.o", kernel_file_name)); let kernel_archive_path = out_dir.join(format!("libkernel_bin-{}.a", kernel_file_name)); @@ -44,9 +46,9 @@ fn main() { cmd.arg("-O").arg("elf64-x86-64"); cmd.arg("--binary-architecture=i386:x86-64"); cmd.arg("--rename-section").arg(".data=.kernel"); - cmd.arg("--redefine-sym").arg(format!("_binary_{}_start=_kernel_start_addr", kernel_file_name)); - cmd.arg("--redefine-sym").arg(format!("_binary_{}_end=_kernel_end_addr", kernel_file_name)); - cmd.arg("--redefine-sym").arg(format!("_binary_{}_size=_kernel_size", kernel_file_name)); + cmd.arg("--redefine-sym").arg(format!("_binary_{}_start=_kernel_start_addr", kernel_file_name_replaced)); + cmd.arg("--redefine-sym").arg(format!("_binary_{}_end=_kernel_end_addr", kernel_file_name_replaced)); + cmd.arg("--redefine-sym").arg(format!("_binary_{}_size=_kernel_size", kernel_file_name_replaced)); cmd.current_dir(kernel.parent().expect("KERNEL has no valid parent dir")); cmd.arg(&kernel_file_name); cmd.arg(&kernel_out_path); From 01a0828f138ac3edd836f8c43aebfc2abbdab786 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Mon, 25 Mar 2019 19:16:44 +0100 Subject: [PATCH 10/10] Rerun build script if `KERNEL` environment variable has changed --- build.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/build.rs b/build.rs index e2c4b0e9..765e3f56 100644 --- a/build.rs +++ b/build.rs @@ -74,6 +74,7 @@ fn main() { process::exit(1); } + println!("cargo:rerun-if-env-changed=KERNEL"); println!("cargo:rerun-if-changed={}", kernel.display()); println!("cargo:rerun-if-changed=build.rs"); println!("cargo:rustc-link-search=native={}", out_dir.display());