Add sel4-config build helper for syncing crates to an seL4 kernel build.

sel4-config is a build helper for keeping a crate's features in sync
with an seL4 kernel. sel4_config::get_sel4_features parses a gen_config.h
artifact from an seL4 build and returns the intersection of the feature
set with the features listed in the caller's Cargo.toml.

Change sel4-sys to use sel4-config to collect features (instead of
depending only on features from Cargo.toml). sel4-sys finds the directory
with kernel artifacts using an SEL4_OUT_DIR environment variable. If
that's not set it falls back to ${ROOTDIR}/out/kata/kernel.

Change workspace crates to use resolver="2" to deal with cargo's
mishandling of dependent features (target build of serde polluted by
std build-dep indirect through cargo_toml).

While here make sel4-sys fall back to ${ROOTDIR}/kata/kernel when SEL4_DIR
is not set in the environment.

Change-Id: I47cf2eab4aa8cd2e502f741738f587c222e94716
GitOrigin-RevId: b661f0b78c0bfe70861965a420d25add8a128cb7
This commit is contained in:
Sam Leffler 2021-12-12 00:54:42 +00:00
parent 164a27b601
commit 9d2f298efa
11 changed files with 135 additions and 75 deletions

View File

@ -1,4 +0,0 @@
[env]
# Pathname to seL4 kernel for xml files and (eventually) tools scripts,
# defaults to "sel4" if not set
SEL4_DIR = { value = "../../../../../kernel", relative = true }

View File

@ -9,6 +9,7 @@ members = [
"kata-uart-client",
"zmodem",
]
resolver = "2"
[profile.dev]
opt-level = 0

View File

@ -5,6 +5,7 @@ members = [
"kata-ml-interface",
"kata-vec-core"
]
resolver = "2"
[profile.dev]
opt-level = 0

View File

@ -5,6 +5,8 @@ members = [
"kata-proc-interface",
"kata-proc-manager",
]
resolver = "2"
[profile.dev]
opt-level = 0

View File

@ -5,6 +5,7 @@ members = [
"kata-security-coordinator",
"kata-security-interface",
]
resolver = "2"
[profile.dev]
opt-level = 0

View File

@ -5,6 +5,7 @@ members = [
"kata-storage-interface",
"kata-storage-manager",
]
resolver = "2"
[profile.dev]
opt-level = 0

View File

@ -3,33 +3,5 @@ name = "kata-os-common"
version = "0.1.0"
edition = "2018"
[features]
default = [
"CONFIG_PRINTING",
"CONFIG_DEBUG_BUILD",
"CONFIG_KERNEL_MCS",
]
CONFIG_ARM_HYPERVISOR_SUPPORT = [
"sel4-sys/CONFIG_ARM_HYPERVISOR_SUPPORT",
]
CONFIG_ARM_SMMU = [
"sel4-sys/CONFIG_ARM_SMMU",
]
CONFIG_DEBUG_BUILD = [
"sel4-sys/CONFIG_DEBUG_BUILD",
]
CONFIG_KERNEL_MCS = [
"sel4-sys/CONFIG_KERNEL_MCS",
]
CONFIG_PRINTING = [
"sel4-sys/CONFIG_PRINTING",
]
CONFIG_SMP_SUPPORT = [
"sel4-sys/CONFIG_SMP_SUPPORT",
]
CONFIG_VTX = [
"sel4-sys/CONFIG_VTX",
]
[dependencies]
sel4-sys = { path = "src/sel4-sys" }

View File

@ -0,0 +1,11 @@
[package]
name = "sel4-config"
version = "0.1.0"
edition = "2018"
description = "build glue for seL4 kernel configuration"
[lib]
path = "src/lib.rs"
[dependencies]
cargo_toml = "0.10.2"

View File

@ -0,0 +1,46 @@
// Cargo/rust build glue to import seL4 kernel configuration. We
// parse the gen_config.h file from a build area to find features
// needed by a dependent crate (sel4-sys, kata-os-rootserver, etc).
//
// The caller is responsible for supplying a pathname to the top
// of the kernel build area. Typically this comes from the
// SEL4_OUT_DIR environment variable.
use std::collections::BTreeSet;
use std::env;
use std::fs::File;
use std::io::{BufRead, BufReader};
use std::path::PathBuf;
use std::string::String;
use std::vec::Vec;
pub fn get_sel4_features(sel4_out_dir: &str) -> Vec<String> {
// Parse the kernel's gen_config.h file to get features.
let gen_config_file =
File::open(format!("{}/gen_config/kernel/gen_config.h", sel4_out_dir)).unwrap();
let kernel_config_features = BufReader::new(gen_config_file)
.lines()
.filter_map(|line| {
let line = line.unwrap();
let mut splitted = line.split_whitespace();
match (splitted.next()?, splitted.next()?) {
("#define", param) => Some(param.to_owned()),
_ => None,
}
})
.collect::<BTreeSet<_>>();
println!("kernel_config_features {:?}", kernel_config_features);
// Return only features specified in the Cargo.toml.
let manifest_path = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()).join("Cargo.toml");
let manifest = cargo_toml::Manifest::from_path(manifest_path).unwrap();
manifest
.features
.into_keys()
.collect::<BTreeSet<String>>()
.intersection(&kernel_config_features)
.cloned()
.collect::<Vec<String>>()
}
// TODO(sleffler): unit tests

View File

@ -17,23 +17,28 @@ readme = "README.md"
license = "MIT/Apache-2.0"
build = "build.rs"
# NB: the sel4-config crate tries to sync features to a kernel build by
# parsing build artifacts (see the crate).
[build-dependencies]
sel4-config = { path = "../sel4-config" }
# NB: used by build.rs
[env]
[build-env]
# Name of python3 interpreter executable, defaults to "python3"
PYTHON = "python3"
# Pathname to seL4 kernel source
SEL4_DIR = "${ROOTDIR}kata/kernel"
# Pathname to seL4 kernel build artifacts (used by sel4-config)
SEL4_OUT_DIR = "${ROOTDIR}out/kata/kernel"
# Beware CONFIG_KERNEL_MCS & CONFIG_SMP_SUPPORT must match the kernel
# config for syscall numbering (aka invocation labeling) to line up.
# Other syscalls api's are generated only when the associated config
# knobs are set but do not affect the syscall ABI (e.g. CONFIG_PRINTING).
[features]
default = [
# "CONFIG_KERNEL_MCS",
"CONFIG_PRINTING",
"CONFIG_DEBUG_BUILD",
"CONFIG_SET_TLS_BASE_SELF",
]
# Changes api, blech
default = []
CONFIG_KERNEL_MCS = []
CONFIG_PRINTING = []
CONFIG_DEBUG_BUILD = []
@ -44,12 +49,9 @@ CONFIG_BENCHMARK_TRACK_UTILISATION = []
# TCBSetBreakpoint, TCBUnsetBreakpoint, TCBSetTLSBase
CONFIG_HARDWARE_DEBUG_API = []
CONFIG_SET_TLS_BASE_SELF = []
# note: if you're looking at these, be aware that hypervisor support is not
# yet available at all. these features shouldn't be enabled.
CONFIG_VTX = []
CONFIG_ARM_SMMU = []
CONFIG_ARM_HYPERVISOR_SUPPORT = []
unstable = [] # XXX?
[lib]
path = "lib.rs"

View File

@ -27,7 +27,29 @@ fn main() {
// Default to "seL4" for backwards compat; can either use git submodule or
// symbolic link (neither recommended)
let sel4_dir = env::var("SEL4_DIR").unwrap_or_else(|_| "seL4".to_string());
let sel4_dir = env::var("SEL4_DIR").unwrap_or_else(
|_| format!("{}/kata/kernel", env::var("ROOTDIR").unwrap())
);
println!("sel4_dir {}", sel4_dir);
// If SEL4_OUT_DIR is not set we expect the kernel build at a fixed
// location relative to the ROOTDIR env variable.
println!("SEL4_OUT_DIR {:?}", env::var("SEL4_OUT_DIR"));
let sel4_out_dir = env::var("SEL4_OUT_DIR").unwrap_or_else(
|_| format!("{}/out/kata/kernel", env::var("ROOTDIR").unwrap())
);
println!("sel4_out_dir {}", sel4_out_dir);
// Dredge seL4 kerenl config for settings we need as features to generate
// correct code: e.g. CONFIG_KERNEL_MCS enables MCS support which changes
// the system call numbering.
let features = sel4_config::get_sel4_features(&sel4_out_dir);
println!("features = {:?}", features);
let mut has_mcs = false;
for feature in features {
println!("cargo:rustc-cfg=feature=\"{}\"", feature);
if feature.as_str() == "CONFIG_KERNEL_MCS" { has_mcs = true; }
}
// Use CARGO_TARGET_ARCH and CARGO_TARGET_POINTER_WIDTH
// to select the target architecture;
@ -59,25 +81,25 @@ fn main() {
"{}/libsel4/sel4_arch_include/{}/interfaces/sel4arch.xml",
sel4_dir, arch
);
let args = vec![
"tools/syscall_stub_gen.py",
let mut cmd = Command::new("/usr/bin/env");
cmd.arg(&python_bin)
.arg("tools/syscall_stub_gen.py");
if has_mcs {
cmd.arg("--mcs");
}
cmd.args(&[
"-a",
arch,
"-w",
cargo_target_pointer_width.as_str(),
"--buffer",
#[cfg(feature = "CONFIG_KERNEL_MCS")]
"--mcs",
"-o",
&*outfile,
&*xml_interfaces_file,
&*xml_arch_file,
&*xml_sel4_arch_file,
];
let mut cmd = Command::new("/usr/bin/env");
cmd.arg(&python_bin).args(&args);
]);
println!("Running: {:?}", cmd);
assert!(cmd.status().unwrap().success());
@ -91,27 +113,30 @@ fn main() {
sel4_dir, arch
);
let mut cmd = Command::new("/usr/bin/env");
cmd.arg(&python_bin).args(&[
"tools/invocation_header_gen.py",
"--dest",
&*format!("{}/{}_invocation.rs", out_dir, arch),
&*xml_interfaces_file,
&*xml_arch_file,
&*xml_sel4_arch_file,
]);
cmd.arg(&python_bin)
.args(&[
"tools/invocation_header_gen.py",
"--dest",
&*format!("{}/{}_invocation.rs", out_dir, arch),
&*xml_interfaces_file,
&*xml_arch_file,
&*xml_sel4_arch_file,
]);
println!("Running {:?}", cmd);
assert!(cmd.status().unwrap().success());
// TODO(sleffler): requires pip install tempita
let mut cmd = Command::new("/usr/bin/env");
cmd.arg(&python_bin).args(&[
"tools/syscall_header_gen.py",
#[cfg(feature = "CONFIG_KERNEL_MCS")]
"--mcs",
"--xml",
&*format!("{}/libsel4/include/api/syscall.xml", sel4_dir),
"--dest",
&*format!("{}/syscalls.rs", out_dir),
cmd.arg(&python_bin)
.arg("tools/syscall_header_gen.py");
if has_mcs {
cmd.arg("--mcs");
}
cmd.args(&[
"--xml",
&*format!("{}/libsel4/include/api/syscall.xml", sel4_dir),
"--dest",
&*format!("{}/syscalls.rs", out_dir),
]);
println!("Running {:?}", cmd);
assert!(cmd.status().unwrap().success());
@ -128,12 +153,14 @@ fn main() {
))
.unwrap();
let mut cmd = Command::new("/usr/bin/env");
cmd.arg(&python_bin)
.arg("tools/bitfield_gen.py")
.arg("--language=rust")
// .arg("--word-size=32")
.stdin(unsafe { Stdio::from_raw_fd(bfin.as_raw_fd()) })
.stdout(unsafe { Stdio::from_raw_fd(bfout.as_raw_fd()) });
cmd.args(&[
&python_bin,
"tools/bitfield_gen.py",
"--language=rust",
// "--word-size=32"
])
.stdin(unsafe { Stdio::from_raw_fd(bfin.as_raw_fd()) })
.stdout(unsafe { Stdio::from_raw_fd(bfout.as_raw_fd()) });
println!("Running {:?}", cmd);
assert!(cmd.status().unwrap().success());
std::mem::forget(bfin);