diff --git a/Cargo.lock b/Cargo.lock index d5b8dd9..99355fe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -20,6 +20,28 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "hashbrown" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" + +[[package]] +name = "indexmap" +version = "2.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" +dependencies = [ + "equivalent", + "hashbrown", +] + [[package]] name = "log" version = "0.4.28" @@ -64,10 +86,51 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_spanned" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5417783452c2be558477e104686f7de5dae53dba813c28435e0e70f82d9b04ee" +dependencies = [ + "serde_core", +] + [[package]] name = "sprout" version = "0.1.0" dependencies = [ + "serde", + "toml", "uefi", ] @@ -82,6 +145,45 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "toml" +version = "0.9.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00e5e5d9bf2475ac9d4f0d9edab68cc573dc2fd644b0dba36b0c30a92dd9eaa0" +dependencies = [ + "indexmap", + "serde_core", + "serde_spanned", + "toml_datetime", + "toml_parser", + "toml_writer", + "winnow", +] + +[[package]] +name = "toml_datetime" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f1085dec27c2b6632b04c80b3bb1b4300d6495d1e129693bdda7d91e72eec1" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_parser" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cf893c33be71572e0e9aa6dd15e6677937abd686b066eac3f8cd3531688a627" +dependencies = [ + "winnow", +] + +[[package]] +name = "toml_writer" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d163a63c116ce562a22cda521fcc4d79152e7aba014456fb5eb442f6d6a10109" + [[package]] name = "ucs2" version = "0.3.3" @@ -139,3 +241,9 @@ name = "unicode-ident" version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" + +[[package]] +name = "winnow" +version = "0.7.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" diff --git a/Cargo.toml b/Cargo.toml index 6ea09b9..87db0ea 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,6 +3,13 @@ name = "sprout" version = "0.1.0" edition = "2024" +[dependencies] +toml = "0.9.7" + +[dependencies.serde] +version = "1.0.228" +features = ["derive"] + [dependencies.uefi] version = "0.35.0" features = ["alloc"] diff --git a/boot/Dockerfile b/boot/Dockerfile index 6a62684..007172f 100644 --- a/boot/Dockerfile +++ b/boot/Dockerfile @@ -6,6 +6,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && apt-get update && apt-get install - rm -rf /var/lib/apt/lists/* WORKDIR /work COPY sprout.efi /work/${EFI_NAME}.EFI +COPY sprout.toml /work/SPROUT.TOML COPY kernel.efi /work/KERNEL.EFI RUN truncate -s256MiB sprout.img && \ parted --script sprout.img mklabel gpt > /dev/null 2>&1 && \ @@ -16,6 +17,7 @@ RUN truncate -s256MiB sprout.img && \ mmd -i sprout.img ::/EFI/BOOT && \ mcopy -i sprout.img ${EFI_NAME}.EFI ::/EFI/BOOT/ && \ mcopy -i sprout.img KERNEL.EFI ::/EFI/BOOT/ && \ + mcopy -i sprout.img SPROUT.TOML ::/ && \ mv sprout.img /sprout.img FROM scratch AS final diff --git a/hack/build.sh b/hack/build.sh index 81e1068..9b2652b 100755 --- a/hack/build.sh +++ b/hack/build.sh @@ -40,6 +40,7 @@ if [ "${SKIP_KERNEL_BUILD}" != "1" ]; then docker run --rm -i \ --mount="type=image,source=${DOCKER_PREFIX}/sprout-kernel-${TARGET_ARCH}:${DOCKER_TAG},target=/image" \ "${DOCKER_PREFIX}/sprout-utils-copy:${DOCKER_TAG}" cat /image/kernel.efi >"${FINAL_DIR}/kernel.efi" + cp hack/configs/kernel.sprout.toml "${FINAL_DIR}/sprout.toml" fi if [ "${SKIP_VM_BUILD}" != "1" ]; then @@ -61,6 +62,7 @@ if [ "${SKIP_SPROUT_BUILD}" != "1" ]; then if [ -f "${FINAL_DIR}/kernel.efi" ]; then cp "${FINAL_DIR}/kernel.efi" "${FINAL_DIR}/efi/EFI/BOOT/KERNEL.EFI" fi + cp "hack/configs/kernel.sprout.toml" "${FINAL_DIR}/efi/SPROUT.TOML" fi if [ "${SKIP_BOOT_BUILD}" != "1" ]; then diff --git a/hack/configs/kernel.sprout.toml b/hack/configs/kernel.sprout.toml new file mode 100644 index 0000000..c93ff1d --- /dev/null +++ b/hack/configs/kernel.sprout.toml @@ -0,0 +1,2 @@ +[[modules]] +chainloader = { path = "\\EFI\\BOOT\\KERNEL.EFI" } diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..803de11 --- /dev/null +++ b/src/config.rs @@ -0,0 +1,33 @@ +use serde::{Deserialize, Serialize}; +use uefi::cstr16; +use uefi::fs::{FileSystem, Path}; +use uefi::proto::media::fs::SimpleFileSystem; + +#[derive(Serialize, Deserialize, Default)] +pub struct RootConfiguration { + #[serde(default)] + pub modules: Vec, +} + +#[derive(Serialize, Deserialize, Default)] +pub struct ModuleConfiguration { + #[serde(default)] + pub chainloader: Option, +} + +#[derive(Serialize, Deserialize, Default)] +pub struct ChainloaderConfiguration { + pub path: String, +} + +pub fn load() -> RootConfiguration { + let fs = uefi::boot::open_protocol_exclusive::( + uefi::boot::get_handle_for_protocol::().expect("no filesystem protocol"), + ) + .expect("unable to open filesystem protocol"); + let mut fs = FileSystem::new(fs); + let content = fs + .read(Path::new(cstr16!("sprout.toml"))) + .expect("unable to read sprout.toml file"); + toml::from_slice(&content).expect("unable to parse sprout.toml file") +} diff --git a/src/main.rs b/src/main.rs index 74527a0..ccb751b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,10 +1,11 @@ #![feature(uefi_std)] -pub mod chainload; +pub mod config; +pub mod modules; pub mod setup; -const CHAINLOADER_TARGET: &str = "\\EFI\\BOOT\\KERNEL.efi"; - fn main() { setup::init(); - chainload::chainload(CHAINLOADER_TARGET); + + let config = config::load(); + modules::execute(config.modules); } diff --git a/src/modules.rs b/src/modules.rs new file mode 100644 index 0000000..1f23c47 --- /dev/null +++ b/src/modules.rs @@ -0,0 +1,13 @@ +use crate::config::ModuleConfiguration; + +pub mod chainloader; + +pub fn execute(modules: Vec) { + for module in modules { + if let Some(chainloader) = module.chainloader { + chainloader::chainloader(chainloader); + } else { + panic!("unknown module configuration"); + } + } +} diff --git a/src/chainload.rs b/src/modules/chainloader.rs similarity index 90% rename from src/chainload.rs rename to src/modules/chainloader.rs index f9452b2..978ad3a 100644 --- a/src/chainload.rs +++ b/src/modules/chainloader.rs @@ -1,3 +1,4 @@ +use crate::config::ChainloaderConfiguration; use uefi::{ CString16, proto::device_path::{ @@ -19,7 +20,7 @@ fn text_to_device_path(path: &str) -> PoolDevicePath { .expect("unable to convert text to device path") } -pub fn chainload(path: &str) { +pub fn chainloader(configuration: ChainloaderConfiguration) { let sprout_image = uefi::boot::image_handle(); let image_device_path_protocol = uefi::boot::open_protocol_exclusive::(sprout_image) @@ -42,9 +43,9 @@ pub fn chainload(path: &str) { .collect::>() .join("/"); full_path.push('/'); - full_path.push_str(path); + full_path.push_str(&configuration.path); - println!("chainload: {}", full_path); + println!("chainloader: path={}", full_path); let device_path = text_to_device_path(&full_path); @@ -57,5 +58,4 @@ pub fn chainload(path: &str) { ) .expect("failed to load image"); uefi::boot::start_image(image).expect("failed to start image"); - panic!("chainloaded image exited"); }