rust-osdev / bootloader

An experimental pure-Rust x86 bootloader
Apache License 2.0
1.39k stars 212 forks source link

Embed bios and uefi binaries #395

Closed mysteriouslyseeing closed 10 months ago

mysteriouslyseeing commented 1 year ago

This crate embeds links to bios and uefi binaries created in the build.rs script, and that means you can't depend on it with a crate from crates.io, as the binaries created are deleted after the final binary (with the code that you actually wrote) is moved to .cargo/bin/ and it throws a file not found error. This was kind of annoying to pin down, because when I manually built it, it worked, until it stopped randomly. This was caused (although I didn't know this at the time) by the files being cleaned from the directory they were built in, no matter where the final binary was at that point.

So here is my solution; feature-gated binary embedding using include_bytes!() I had to rewrite part of mbr but the api is exactly the same when the feature is disabled.

The main reason I wanted to use it as a dependency was to make a command-line interface to replace bootimage, which doesn't work with 10.x or 11.x (the resulting command-line crate is here) and I liked the crate structure that bootimage encouraged (main.rs, entry_point!(), lib.rs etc.) as opposed to the crate structure currently recommended (a build.rs that links bootloader to a subpackage containing the kernel and a main.rs that calls qemu).

Anyway, if this is all a terrible idea, please let me know.

mysteriouslyseeing commented 1 year ago

I've made the changes you suggested, but it's now failing a check, specifically the Check docs.rs build.

The reason why is that the build.rs script passes in blank PathBufs into the UEFI_BOOTLOADER_PATH (and co) environment variables when running under the docsrs_dummy_build cfg directive. build.rs > uefi_main (lines 63 to 67):

#[cfg(not(docsrs_dummy_build))]
let uefi_path = build_uefi_bootloader(&out_dir).await;
// dummy implementation because docsrs builds have no network access
#[cfg(docsrs_dummy_build)]
let uefi_path = PathBuf::new();

The fact that the paths don't point to a file didn't matter for the original implementation without the include_bytes!, as the crate was only built, and not run, and therefore the path is never resolved. Now, because Rust tries to resolve the path during the build process with include_bytes!, it doesn't work, as the PathBuf is empty and so is resolved to just point at the root, which is /src/ in this case. The reason this wasn't an issue in previous commits was (I'm pretty sure) the check wasn't running with the embedded_binaries feature enabled.

This can be fixed changing the build script, so that rather than simply doing nothing if docsrs_dummy_build is set, it will instead populate the out_dir directory with dummy empty binaries (with std::fs::File::create).