Skip to content

Commit 3115471

Browse files
committed
Parse Cargo.toml from KERNEL_MANIFEST env var
1 parent cda5eb6 commit 3115471

File tree

3 files changed

+120
-35
lines changed

3 files changed

+120
-35
lines changed

Cargo.lock

Lines changed: 16 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,11 @@ optional = true
2626

2727
[build-dependencies]
2828
llvm-tools = { version = "0.1", optional = true }
29+
toml = { version = "0.5.1", optional = true }
2930

3031
[features]
3132
default = []
32-
binary = ["xmas-elf", "x86_64", "usize_conversions", "fixedvec", "llvm-tools"]
33+
binary = ["xmas-elf", "x86_64", "usize_conversions", "fixedvec", "llvm-tools", "toml"]
3334
vga_320x200 = ["font8x8"]
3435
recursive_page_table = []
3536
map_physical_memory = []

build.rs

Lines changed: 102 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -10,35 +10,71 @@ fn main() {
1010
compile_error!("This crate only supports the x86_64 architecture.");
1111
}
1212

13+
#[derive(Default)]
14+
struct BootloaderConfig {
15+
physical_memory_offset: Option<u64>,
16+
kernel_stack_address: Option<u64>,
17+
kernel_stack_size: Option<u64>,
18+
}
19+
1320
#[cfg(feature = "binary")]
14-
fn num_from_env(env: &'static str, aligned: bool) -> Option<u64> {
15-
use std::env;
16-
match env::var(env) {
17-
Err(env::VarError::NotPresent) => None,
18-
Err(env::VarError::NotUnicode(_)) => {
19-
panic!("The `{}` environment variable must be valid unicode", env,)
20-
}
21-
Ok(s) => {
22-
let num = if s.starts_with("0x") {
23-
u64::from_str_radix(&s[2..], 16)
24-
} else {
25-
u64::from_str_radix(&s, 10)
26-
};
27-
28-
let num = num.expect(&format!(
29-
"The `{}` environment variable must be an integer\
30-
(is `{}`).",
31-
env, s
32-
));
21+
fn parse_aligned_addr(key: &str, value: &str) -> u64 {
22+
let num = if value.starts_with("0x") {
23+
u64::from_str_radix(&value[2..], 16)
24+
} else {
25+
u64::from_str_radix(&value, 10)
26+
};
27+
28+
let num = num.expect(&format!(
29+
"`{}` in the kernel manifest must be an integer (is `{}`)",
30+
key, value
31+
));
3332

34-
if aligned && num % 0x1000 != 0 {
33+
if num % 0x1000 != 0 {
34+
panic!(
35+
"`{}` in the kernel manifest must be aligned to 4KiB (is `{}`)",
36+
key, value
37+
);
38+
} else {
39+
num
40+
}
41+
}
42+
43+
#[cfg(feature = "binary")]
44+
fn parse_to_config(cfg: &mut BootloaderConfig, table: &toml::value::Table) {
45+
use toml::Value;
46+
47+
for (key, value) in table {
48+
match (key.as_str(), value.clone()) {
49+
("kernel-stack-address", Value::Integer(i))
50+
| ("physical-memory-offset", Value::Integer(i)) => {
3551
panic!(
36-
"The `{}` environment variable must be aligned to 0x1000 (is `{:#x}`).",
37-
env, num
52+
"`{0}` in the kernel manifest must be given as a string, \
53+
as toml does not support unsigned 64-bit integers (try `{0} = \"{1}\"`)",
54+
key.as_str(),
55+
i
56+
);
57+
}
58+
("kernel-stack-address", Value::String(s)) => {
59+
cfg.kernel_stack_address = Some(parse_aligned_addr(key.as_str(), &s));
60+
}
61+
("physical-memory-offset", Value::String(s)) => {
62+
cfg.physical_memory_offset = Some(parse_aligned_addr(key.as_str(), &s));
63+
}
64+
("kernel-stack-size", Value::Integer(i)) => {
65+
if i <= 0 {
66+
panic!("`kernel-stack-size` in kernel manifest must be positive");
67+
} else {
68+
cfg.kernel_stack_size = Some(i as u64);
69+
}
70+
}
71+
(s, _) => {
72+
panic!(
73+
"unknown key '{}' in kernel manifest \
74+
- you may need to update the bootloader crate",
75+
s
3876
);
3977
}
40-
41-
Some(num)
4278
}
4379
}
4480
}
@@ -47,11 +83,12 @@ fn num_from_env(env: &'static str, aligned: bool) -> Option<u64> {
4783
fn main() {
4884
use std::{
4985
env,
50-
fs::File,
86+
fs::{self, File},
5187
io::Write,
5288
path::{Path, PathBuf},
5389
process::{self, Command},
5490
};
91+
use toml::Value;
5592

5693
let target = env::var("TARGET").expect("TARGET not set");
5794
if Path::new(&target)
@@ -185,22 +222,55 @@ fn main() {
185222
process::exit(1);
186223
}
187224

225+
// Parse the kernel's Cargo.toml which is given to us by bootimage
226+
let mut bootloader_config = BootloaderConfig::default();
227+
228+
match env::var("KERNEL_MANIFEST") {
229+
Err(env::VarError::NotPresent) => {
230+
panic!("The KERNEL_MANIFEST environment variable must be set for building the bootloader.\n\n\
231+
If you use `bootimage` for building you need at least version PLACEHOLDER. You can \
232+
update `bootimage` by running `cargo install bootimage --force`.");
233+
}
234+
Err(env::VarError::NotUnicode(_)) => {
235+
panic!("The KERNEL_MANIFEST environment variable contains invalid unicode")
236+
}
237+
Ok(path) => {
238+
println!("cargo:rerun-if-changed={}", path);
239+
240+
let contents = fs::read_to_string(&path).expect(&format!(
241+
"failed to read kernel manifest file (path: {})",
242+
path
243+
));
244+
245+
let manifest = contents
246+
.parse::<Value>()
247+
.expect("failed to parse kernel's Cargo.toml");
248+
249+
let table = manifest
250+
.get("package")
251+
.and_then(|table| table.get("metadata"))
252+
.and_then(|table| table.get("bootloader"))
253+
.and_then(|table| table.as_table());
254+
255+
if let Some(table) = table {
256+
parse_to_config(&mut bootloader_config, table);
257+
}
258+
}
259+
}
260+
188261
// Configure constants for the bootloader
189262
// We leave some variables as Option<T> rather than hardcoding their defaults so that they
190263
// can be calculated dynamically by the bootloader.
191264
let file_path = out_dir.join("bootloader_config.rs");
192265
let mut file = File::create(file_path).expect("failed to create bootloader_config.rs");
193-
let physical_memory_offset = num_from_env("BOOTLOADER_PHYSICAL_MEMORY_OFFSET", true);
194-
let kernel_stack_address = num_from_env("BOOTLOADER_KERNEL_STACK_ADDRESS", true);
195-
let kernel_stack_size = num_from_env("BOOTLOADER_KERNEL_STACK_SIZE", false);
196266
file.write_all(
197267
format!(
198268
"const PHYSICAL_MEMORY_OFFSET: Option<u64> = {:?};
199269
const KERNEL_STACK_ADDRESS: Option<u64> = {:?};
200270
const KERNEL_STACK_SIZE: u64 = {};",
201-
physical_memory_offset,
202-
kernel_stack_address,
203-
kernel_stack_size.unwrap_or(512), // size is in number of pages
271+
bootloader_config.physical_memory_offset,
272+
bootloader_config.kernel_stack_address,
273+
bootloader_config.kernel_stack_size.unwrap_or(512), // size is in number of pages
204274
)
205275
.as_bytes(),
206276
)
@@ -214,9 +284,7 @@ fn main() {
214284
);
215285

216286
println!("cargo:rerun-if-env-changed=KERNEL");
217-
println!("cargo:rerun-if-env-changed=BOOTLOADER_PHYSICAL_MEMORY_OFFSET");
218-
println!("cargo:rerun-if-env-changed=BOOTLOADER_KERNEL_STACK_ADDRESS");
219-
println!("cargo:rerun-if-env-changed=BOOTLOADER_KERNEL_STACK_SIZE");
287+
println!("cargo:rerun-if-env-changed=KERNEL_MANIFEST");
220288
println!("cargo:rerun-if-changed={}", kernel.display());
221289
println!("cargo:rerun-if-changed=build.rs");
222290
}

0 commit comments

Comments
 (0)