diff --git a/Cargo.lock b/Cargo.lock
index 9ab14d3..963bebe 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -71,11 +71,11 @@ dependencies = [
"anyhow",
"bitflags",
"edera-sprout-config",
+ "edera-sprout-eficore",
"hex",
"log",
"sha2",
"shlex",
- "spin",
"toml",
"uefi",
"uefi-raw",
@@ -88,6 +88,18 @@ dependencies = [
"serde",
]
+[[package]]
+name = "edera-sprout-eficore"
+version = "0.0.22"
+dependencies = [
+ "anyhow",
+ "bitflags",
+ "log",
+ "spin",
+ "uefi",
+ "uefi-raw",
+]
+
[[package]]
name = "generic-array"
version = "0.14.9"
diff --git a/Cargo.toml b/Cargo.toml
index 7ce9d89..969077a 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,7 @@
[workspace]
members = [
"crates/config",
+ "crates/eficore",
"crates/sprout",
]
resolver = "3"
@@ -16,7 +17,6 @@ edition = "2024"
bitflags = "2.10.0"
log = "0.4.28"
spin = "0.10.0"
-uefi = "0.36.0"
uefi-raw = "0.12.0"
[workspace.dependencies.anyhow]
@@ -46,6 +46,11 @@ version = "0.9.8"
default-features = false
features = ["serde", "parse"]
+[workspace.dependencies.uefi]
+version = "0.36.0"
+default-features = false
+features = ["alloc", "global_allocator", "panic_handler"]
+
# Common build profiles
# NOTE: We have to compile everything for opt-level = 2 due to optimization passes
# which don't handle the UEFI target properly.
diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md
index 3bb3862..41d2965 100644
--- a/DEVELOPMENT.md
+++ b/DEVELOPMENT.md
@@ -11,6 +11,16 @@ We currently only support `x86_64-unknown-uefi` and `aarch64-unknown-uefi` targe
To test your changes in QEMU, please run `./hack/dev/boot.sh`, you can specify `x86_64` or `aarch64`
as an argument to boot.sh to boot the specified architecture.
+## Crate Structure
+
+Sprout is split into multiple crates:
+
+- `edera-sprout-config` at `crates/config`: Serialization structures for the Sprout configuration file.
+- `edera-sprout-eficore` at `crates/eficore`: Core library for Sprout EFI code.
+- `edera-sprout` as `crates/sprout`: Sprout's main crate that contains bootloader logic.
+
+It is intended that overtime Sprout will be split into even more crates.
+
## Hack Scripts
You can use the `./hack` scripts to run common development tasks:
diff --git a/crates/config/Cargo.toml b/crates/config/Cargo.toml
index 2381ebe..bd75968 100644
--- a/crates/config/Cargo.toml
+++ b/crates/config/Cargo.toml
@@ -13,3 +13,4 @@ default-features = false
[lib]
name = "edera_sprout_config"
+path = "src/lib.rs"
diff --git a/crates/eficore/Cargo.toml b/crates/eficore/Cargo.toml
new file mode 100644
index 0000000..6a6a89e
--- /dev/null
+++ b/crates/eficore/Cargo.toml
@@ -0,0 +1,20 @@
+[package]
+name = "edera-sprout-eficore"
+description = "Sprout EFI Core"
+license.workspace = true
+version.workspace = true
+homepage.workspace = true
+repository.workspace = true
+edition.workspace = true
+
+[dependencies]
+anyhow.workspace = true
+bitflags.workspace = true
+log.workspace = true
+spin.workspace = true
+uefi.workspace = true
+uefi-raw.workspace = true
+
+[lib]
+name = "eficore"
+path = "src/lib.rs"
diff --git a/crates/sprout/src/integrations/bootloader_interface.rs b/crates/eficore/src/bootloader_interface.rs
similarity index 97%
rename from crates/sprout/src/integrations/bootloader_interface.rs
rename to crates/eficore/src/bootloader_interface.rs
index b3cf6a8..1edfa5a 100644
--- a/crates/sprout/src/integrations/bootloader_interface.rs
+++ b/crates/eficore/src/bootloader_interface.rs
@@ -1,7 +1,6 @@
-use crate::integrations::bootloader_interface::bitflags::LoaderFeatures;
+use crate::bootloader_interface::bitflags::LoaderFeatures;
use crate::platform::timer::PlatformTimer;
-use crate::utils::device_path_subpath;
-use crate::utils::variables::{VariableClass, VariableController};
+use crate::variables::{VariableClass, VariableController};
use alloc::format;
use alloc::string::{String, ToString};
use alloc::vec::Vec;
@@ -103,7 +102,8 @@ impl BootloaderInterface {
/// Tell the system the relative path to the partition root of the current bootloader.
pub fn set_loader_path(path: &DevicePath) -> Result<()> {
- let subpath = device_path_subpath(path).context("unable to get loader path subpath")?;
+ let subpath =
+ crate::path::device_path_subpath(path).context("unable to get loader path subpath")?;
Self::VENDOR.set_cstr16(
"LoaderImageIdentifier",
&subpath,
diff --git a/crates/sprout/src/integrations/bootloader_interface/bitflags.rs b/crates/eficore/src/bootloader_interface/bitflags.rs
similarity index 100%
rename from crates/sprout/src/integrations/bootloader_interface/bitflags.rs
rename to crates/eficore/src/bootloader_interface/bitflags.rs
diff --git a/crates/sprout/src/utils/framebuffer.rs b/crates/eficore/src/framebuffer.rs
similarity index 100%
rename from crates/sprout/src/utils/framebuffer.rs
rename to crates/eficore/src/framebuffer.rs
diff --git a/crates/eficore/src/handle.rs b/crates/eficore/src/handle.rs
new file mode 100644
index 0000000..ed0ca1e
--- /dev/null
+++ b/crates/eficore/src/handle.rs
@@ -0,0 +1,26 @@
+use anyhow::{Context, Result};
+use uefi::boot::SearchType;
+use uefi::{Guid, Handle};
+use uefi_raw::Status;
+
+/// Find a handle that provides the specified `protocol`.
+pub fn find_handle(protocol: &Guid) -> Result