cargo_image_runner/bootloader/
limine.rs1use super::{Bootloader, BootloaderFiles, ConfigFile};
2use crate::config::BootType;
3use crate::core::context::Context;
4use crate::core::error::{Error, Result};
5use std::path::PathBuf;
6
7#[cfg(feature = "limine")]
8use super::GitFetcher;
9
10pub struct LimineBootloader {
16 repo_url: String,
17}
18
19impl LimineBootloader {
20 const DEFAULT_REPO_URL: &'static str = "https://github.com/limine-bootloader/limine.git";
22
23 pub fn new() -> Self {
25 Self {
26 repo_url: Self::DEFAULT_REPO_URL.to_string(),
27 }
28 }
29
30 pub fn with_repo_url(repo_url: String) -> Self {
32 Self { repo_url }
33 }
34
35 fn get_version<'a>(&self, ctx: &'a Context) -> &'a str {
37 &ctx.config.bootloader.limine.version
38 }
39
40 #[cfg(feature = "limine")]
42 fn fetch_limine(&self, ctx: &Context) -> Result<PathBuf> {
43 let version = self.get_version(ctx);
44 let cache_dir = ctx.cache_dir.join("bootloaders");
45
46 let fetcher = GitFetcher::new(cache_dir, ctx.config.verbose);
47 fetcher.fetch_ref(&self.repo_url, "limine", version)
48 }
49
50 #[cfg(not(feature = "limine"))]
52 fn fetch_limine(&self, _ctx: &Context) -> Result<PathBuf> {
53 Err(Error::feature_not_enabled("limine"))
54 }
55}
56
57impl Default for LimineBootloader {
58 fn default() -> Self {
59 Self::new()
60 }
61}
62
63impl Bootloader for LimineBootloader {
64 fn prepare(&self, ctx: &Context) -> Result<BootloaderFiles> {
65 let limine_repo = self.fetch_limine(ctx)?;
66
67 let mut files = BootloaderFiles::new();
68
69 if ctx.config.boot.boot_type.needs_bios() {
71 let limine_bios = limine_repo.join("limine-bios.sys");
73 if !limine_bios.exists() {
74 return Err(Error::bootloader(
75 "limine-bios.sys not found in Limine repository. \
76 Make sure you're using a binary release (e.g., v8.x-binary)."
77 .to_string(),
78 ));
79 }
80
81 files = files.add_system_file(limine_bios, "limine-bios.sys".into());
82
83 let limine_bios_cd = limine_repo.join("limine-bios-cd.bin");
85 if !limine_bios_cd.exists() {
86 return Err(Error::bootloader(
87 "limine-bios-cd.bin not found in Limine repository. \
88 Make sure you're using a binary release (e.g., v8.x-binary)."
89 .to_string(),
90 ));
91 }
92 files = files.add_system_file(limine_bios_cd, "limine-bios-cd.bin".into());
93 }
94
95 if ctx.config.boot.boot_type.needs_uefi() {
97 let bootx64 = limine_repo.join("BOOTX64.EFI");
99 if !bootx64.exists() {
100 return Err(Error::bootloader(
101 "BOOTX64.EFI not found in Limine repository. \
102 Make sure you're using a binary release (e.g., v8.x-binary)."
103 .to_string(),
104 ));
105 }
106
107 files = files.add_uefi_file(bootx64, "efi/boot/bootx64.efi".into());
108
109 let limine_uefi_cd = limine_repo.join("limine-uefi-cd.bin");
111 if !limine_uefi_cd.exists() {
112 return Err(Error::bootloader(
113 "limine-uefi-cd.bin not found in Limine repository. \
114 Make sure you're using a binary release (e.g., v8.x-binary)."
115 .to_string(),
116 ));
117 }
118 files = files.add_system_file(limine_uefi_cd, "limine-uefi-cd.bin".into());
119 }
120
121 files = files.add_system_file(
123 ctx.executable.clone(),
124 PathBuf::from("boot").join(
125 ctx.executable
126 .file_name()
127 .ok_or_else(|| Error::config("invalid executable path"))?,
128 ),
129 );
130
131 Ok(files)
132 }
133
134 fn config_files(&self, ctx: &Context) -> Result<Vec<ConfigFile>> {
135 let mut configs = Vec::new();
136
137 let config_path = if let Some(ref path) = ctx.config.bootloader.config_file {
139 ctx.workspace_root.join(path)
140 } else {
141 ctx.workspace_root.join("limine.conf")
142 };
143
144 if config_path.exists() {
145 configs.push(
146 ConfigFile::new(config_path, "limine.conf".into())
147 .with_template_processing(),
148 );
149 } else {
150 return Err(Error::config(format!(
152 "limine.conf not found at {}. Please create a Limine configuration file.",
153 config_path.display()
154 )));
155 }
156
157 Ok(configs)
158 }
159
160 fn boot_type(&self) -> BootType {
161 BootType::Hybrid
163 }
164
165 fn name(&self) -> &str {
166 "Limine"
167 }
168
169 fn validate_config(&self, ctx: &Context) -> Result<()> {
170 let version = self.get_version(ctx);
172 if version.is_empty() {
173 return Err(Error::config(
174 "Limine version not specified in configuration",
175 ));
176 }
177
178 if !version.contains("binary") {
180 eprintln!(
181 "Warning: Limine version '{}' may require building from source. \
182 Consider using a binary release like 'v8.x-binary' for faster builds.",
183 version
184 );
185 }
186
187 Ok(())
188 }
189}