1use std::collections::BTreeMap;
2use std::fmt::{self, Display};
3use std::path::{Path, PathBuf};
4use std::str::FromStr;
5
6pub mod deserialization;
7pub mod serialization;
8
9pub use deserialization::ImportError;
10
11const DEFAULT_CONFIG_CONTENT: &str = include_str!("../default_config.toml");
12
13pub fn get_default_config() -> full::Full {
15 DEFAULT_CONFIG_CONTENT
16 .parse()
17 .map_err(|e| format!("{}", e))
18 .expect("Default config content should always be valid.")
19}
20
21#[derive(Copy, Clone)]
23pub enum RustArch {
24 Aarch64,
25 Arm,
26 Armebv7r,
27 Armv5te,
28 Armv7,
29 Armv7r,
30 Armv7s,
31 Asmjs,
32 I386,
33 I586,
34 I686,
35 Mips,
36 Mips64,
37 Mips64el,
38 Mipsel,
39 Nvptx64,
40 Powerpc,
41 Powerpc64,
42 Powerpc64le,
43 Riscv32imac,
44 Riscv32imc,
45 Riscv64gc,
46 Riscv64imac,
47 S390x,
48 Sparc64,
49 Sparcv9,
50 Thumbv6m,
51 Thumbv7em,
52 Thumbv7m,
53 Thumbv7neon,
54 Thumbv8mmain,
55 Wasm32,
56 X86_64,
57}
58
59impl FromStr for RustArch {
60 type Err = String;
61
62 fn from_str(s: &str) -> Result<Self, Self::Err> {
63 match s {
64 "aarch64" => Ok(RustArch::Aarch64),
65 "arm" => Ok(RustArch::Arm),
66 "armebv7r" => Ok(RustArch::Armebv7r),
67 "armv5te" => Ok(RustArch::Armv5te),
68 "armv7" => Ok(RustArch::Armv7),
69 "armv7r" => Ok(RustArch::Armv7r),
70 "armv7s" => Ok(RustArch::Armv7s),
71 "asmjs" => Ok(RustArch::Asmjs),
72 "i386" => Ok(RustArch::I386),
73 "i586" => Ok(RustArch::I586),
74 "i686" => Ok(RustArch::I686),
75 "mips" => Ok(RustArch::Mips),
76 "mips64" => Ok(RustArch::Mips64),
77 "mips64el" => Ok(RustArch::Mips64el),
78 "mipsel" => Ok(RustArch::Mipsel),
79 "nvptx64" => Ok(RustArch::Nvptx64),
80 "powerpc" => Ok(RustArch::Powerpc),
81 "powerpc64" => Ok(RustArch::Powerpc64),
82 "powerpc64le" => Ok(RustArch::Powerpc64le),
83 "riscv32imac" => Ok(RustArch::Riscv32imac),
84 "riscv32imc" => Ok(RustArch::Riscv32imc),
85 "riscv64gc" => Ok(RustArch::Riscv64gc),
86 "riscv64imac" => Ok(RustArch::Riscv32imc),
87 "s390x" => Ok(RustArch::S390x),
88 "sparc64" => Ok(RustArch::Sparc64),
89 "sparcv9" => Ok(RustArch::Sparcv9),
90 "thumbv6m" => Ok(RustArch::Thumbv6m),
91 "thumbv7em" => Ok(RustArch::Thumbv7em),
92 "thumbv7m" => Ok(RustArch::Thumbv7m),
93 "thumbv7neon" => Ok(RustArch::Thumbv7neon),
94 "thumbv8m.main" => Ok(RustArch::Thumbv8mmain),
95 "wasm32" => Ok(RustArch::Wasm32),
96 "x86_64" => Ok(RustArch::X86_64),
97 _ => Err("Unrecognized rust arch".to_string()),
98 }
99 }
100}
101
102#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
104pub enum SeL4Arch {
105 Aarch32,
106 Aarch64,
107 ArmHyp,
108 Ia32,
109 X86_64,
110 Riscv32,
111 Riscv64,
112}
113
114impl FromStr for SeL4Arch {
115 type Err = String;
116
117 fn from_str(s: &str) -> Result<Self, Self::Err> {
118 match s {
119 "aarch32" => Ok(SeL4Arch::Aarch32),
120 "aarch64" => Ok(SeL4Arch::Aarch64),
121 "arm_hyp" => Ok(SeL4Arch::ArmHyp),
122 "ia32" => Ok(SeL4Arch::Ia32),
123 "riscv32" => Ok(SeL4Arch::Riscv32),
124 "riscv64" => Ok(SeL4Arch::Riscv64),
125 "x86_64" => Ok(SeL4Arch::X86_64),
126 _ => Err("Unrecognized sel4_arch".to_string()),
127 }
128 }
129}
130
131impl SeL4Arch {
132 pub fn from_rust_arch(rust_arch: RustArch) -> Option<SeL4Arch> {
134 match rust_arch {
135 RustArch::Aarch64 => Some(SeL4Arch::Aarch64),
136
137 RustArch::Arm
138 | RustArch::Armebv7r
139 | RustArch::Armv7
140 | RustArch::Armv7r
141 | RustArch::Armv7s => Some(SeL4Arch::Aarch32),
142
143 RustArch::I386 | RustArch::I586 | RustArch::I686 => Some(SeL4Arch::Ia32),
144
145 RustArch::Riscv32imac | RustArch::Riscv32imc => Some(SeL4Arch::Riscv32),
146
147 RustArch::Riscv64gc | RustArch::Riscv64imac => Some(SeL4Arch::Riscv64),
148
149 RustArch::Thumbv6m
150 | RustArch::Thumbv7em
151 | RustArch::Thumbv7m
152 | RustArch::Thumbv7neon => Some(SeL4Arch::Aarch32),
153
154 RustArch::Thumbv8mmain => Some(SeL4Arch::Aarch64),
155
156 RustArch::X86_64 => Some(SeL4Arch::X86_64),
157 _ => None,
158 }
159 }
160}
161
162impl Display for SeL4Arch {
163 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
164 let s = match self {
165 SeL4Arch::Aarch32 => "aarch32",
166 SeL4Arch::Aarch64 => "aarch64",
167 SeL4Arch::ArmHyp => "arm_hyp",
168 SeL4Arch::Ia32 => "ia32",
169 SeL4Arch::X86_64 => "x86_64",
170 SeL4Arch::Riscv32 => "riscv32",
171 SeL4Arch::Riscv64 => "riscv64",
172 };
173 write!(f, "{}", s)
174 }
175}
176
177#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
179pub enum Arch {
180 Arm,
181 X86,
182 Riscv,
183}
184
185impl FromStr for Arch {
186 type Err = String;
187
188 fn from_str(s: &str) -> Result<Self, Self::Err> {
189 match s {
190 "arm" => Ok(Arch::Arm),
191 "x86" => Ok(Arch::X86),
192 "riscv" => Ok(Arch::Riscv),
193 _ => Err("Unrecognized arch".to_string()),
194 }
195 }
196}
197
198impl Arch {
199 pub fn from_sel4_arch(sel4_arch: SeL4Arch) -> Arch {
200 match sel4_arch {
201 SeL4Arch::Aarch32 | SeL4Arch::Aarch64 | SeL4Arch::ArmHyp => Arch::Arm,
202 SeL4Arch::Ia32 | SeL4Arch::X86_64 => Arch::X86,
203 SeL4Arch::Riscv32 | SeL4Arch::Riscv64 => Arch::Riscv,
204 }
205 }
206
207 pub fn from_rust_arch(rust_arch: RustArch) -> Option<Arch> {
209 SeL4Arch::from_rust_arch(rust_arch).map(Arch::from_sel4_arch)
210 }
211}
212
213impl Display for Arch {
214 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
215 let s = match self {
216 Arch::Arm => "arm",
217 Arch::X86 => "x86",
218 Arch::Riscv => "riscv",
219 };
220 write!(f, "{}", s)
221 }
222}
223
224#[derive(Clone, Debug, Eq, PartialEq, Hash)]
226pub struct Platform(pub String);
227impl Display for Platform {
228 fn fmt(&self, mut f: &mut fmt::Formatter) -> fmt::Result {
229 self.0.fmt(&mut f)
230 }
231}
232
233#[derive(Clone, Debug, PartialOrd, PartialEq, Hash)]
234pub enum SingleValue {
235 String(String),
236 Integer(i64),
237 Boolean(bool),
238}
239
240#[derive(Debug, Clone, Eq, PartialEq, Hash)]
241pub struct SeL4Sources {
242 pub kernel: RepoSource,
243 pub tools: RepoSource,
244 pub util_libs: RepoSource,
245}
246
247impl SeL4Sources {
248 fn relative_to<P: AsRef<Path>>(&self, base_dir: &Option<P>) -> Self {
249 SeL4Sources {
250 kernel: self.kernel.relative_to(base_dir),
251 tools: self.tools.relative_to(base_dir),
252 util_libs: self.util_libs.relative_to(base_dir),
253 }
254 }
255}
256
257#[derive(Debug, Clone, Eq, PartialEq, Hash)]
258pub enum RepoSource {
259 LocalPath(PathBuf),
260 RemoteGit { url: String, target: GitTarget },
261}
262
263impl RepoSource {
264 fn relative_to<P: AsRef<Path>>(&self, base_dir: &Option<P>) -> Self {
265 match self {
266 RepoSource::LocalPath(p) => RepoSource::LocalPath(p.relative_to(base_dir)),
267 s => s.clone(),
268 }
269 }
270}
271
272#[derive(Debug, Clone, Eq, PartialEq, Hash)]
273pub enum GitTarget {
274 Branch(String),
275 Rev(String),
276 Tag(String),
277}
278
279impl GitTarget {
280 pub fn kind(&self) -> &'static str {
281 match self {
282 GitTarget::Branch(_) => "branch",
283 GitTarget::Rev(_) => "rev",
284 GitTarget::Tag(_) => "tag",
285 }
286 }
287 pub fn value(&self) -> &str {
288 match self {
289 GitTarget::Branch(s) | GitTarget::Rev(s) | GitTarget::Tag(s) => s,
290 }
291 }
292}
293
294pub mod full {
295 use super::*;
296 use std::collections::btree_map::BTreeMap;
297
298 #[derive(Debug, Clone, PartialEq)]
299 pub struct Full {
300 pub sel4: SeL4,
301 pub build: BTreeMap<String, PlatformBuild>,
302 pub metadata: Metadata,
303 }
304
305 #[derive(Debug, Clone, PartialEq)]
306 pub struct SeL4 {
307 pub sources: SeL4Sources,
308 pub config: Config,
309 }
310
311 #[derive(Debug, Clone, Eq, PartialEq, Default, Hash)]
312 pub struct PlatformBuild {
313 pub cross_compiler_prefix: Option<String>,
314 pub toolchain_dir: Option<PathBuf>,
315 pub debug_build_profile: Option<PlatformBuildProfile>,
316 pub release_build_profile: Option<PlatformBuildProfile>,
317 }
318
319 #[derive(Debug, Clone, Eq, PartialEq, Default, Hash)]
320 pub struct PlatformBuildProfile {
321 pub make_root_task: Option<String>,
322 pub root_task_image: PathBuf,
323 }
324
325 impl SeL4 {
326 pub fn new(sources: SeL4Sources, config: Config) -> Self {
327 SeL4 { sources, config }
328 }
329 }
330
331 pub type Config = PropertiesTree;
332 pub type Metadata = PropertiesTree;
333
334 #[derive(Debug, Default, Clone, PartialEq)]
338 pub struct PropertiesTree {
339 pub shared: BTreeMap<String, SingleValue>,
340 pub debug: BTreeMap<String, SingleValue>,
341 pub release: BTreeMap<String, SingleValue>,
342 pub contextual: BTreeMap<String, BTreeMap<String, SingleValue>>,
343 }
344}
345
346trait RelativePath {
347 fn relative_to<P: AsRef<Path>>(&self, base: &Option<P>) -> PathBuf;
350}
351
352impl RelativePath for Path {
353 fn relative_to<P: AsRef<Path>>(&self, base: &Option<P>) -> PathBuf {
354 if self.is_relative() {
355 match base {
356 Some(p) => p.as_ref().join(self),
357 None => self.to_path_buf(),
358 }
359 } else {
360 self.to_path_buf()
361 }
362 }
363}
364
365pub mod contextualized {
366 use super::*;
367
368 #[derive(Debug, Clone, PartialEq, Hash)]
369 pub struct Contextualized {
370 pub sel4_sources: SeL4Sources,
371 pub context: Context,
372 pub sel4_config: BTreeMap<String, SingleValue>,
373 pub build: Build,
374 pub metadata: BTreeMap<String, SingleValue>,
375 }
376
377 #[derive(Debug, Clone, Eq, PartialEq, Default, Hash)]
378 pub struct Build {
379 pub cross_compiler_prefix: Option<String>,
380 pub toolchain_dir: Option<PathBuf>,
381 pub root_task: Option<RootTask>,
382 }
383
384 #[derive(Debug, Clone, Eq, PartialEq, Default, Hash)]
385 pub struct RootTask {
386 pub make_command: Option<String>,
387 pub image_path: PathBuf,
388 }
389
390 #[derive(Debug, Clone, PartialEq, Hash)]
391 pub struct Context {
392 pub platform: Platform,
393 pub is_debug: bool,
394 pub base_dir: Option<PathBuf>,
395 pub arch: Arch,
396 pub sel4_arch: SeL4Arch,
397 }
398
399 impl Contextualized {
400 pub fn from_str(
401 source_toml: &str,
402 arch: Arch,
403 sel4_arch: SeL4Arch,
404 is_debug: bool,
405 platform: Platform,
406 base_dir: Option<&Path>,
407 ) -> Result<Contextualized, ImportError> {
408 let f: full::Full = source_toml.parse()?;
409 Self::from_full(&f, arch, sel4_arch, is_debug, platform, base_dir)
410 }
411
412 pub fn from_full(
413 f: &full::Full,
414 arch: Arch,
415 sel4_arch: SeL4Arch,
416 is_debug: bool,
417 platform: Platform,
418 base_dir: Option<&Path>,
419 ) -> Result<Contextualized, ImportError> {
420 let context = Context {
421 platform: platform.clone(),
422 arch,
423 sel4_arch,
424 is_debug,
425 base_dir: base_dir.map(Path::to_path_buf),
426 };
427 Contextualized::from_full_context(&f, context)
428 }
429
430 pub fn from_full_context(
431 f: &full::Full,
432 context: Context,
433 ) -> Result<Contextualized, ImportError> {
434 let platform_build = f
435 .build
436 .get(&context.platform.to_string())
437 .ok_or_else(|| ImportError::NoBuildSupplied {
438 platform: context.platform.to_string(),
439 profile: if context.is_debug {
440 "debug"
441 } else {
442 "release "
443 },
444 })?
445 .clone();
446 let build_profile = if context.is_debug {
447 platform_build.debug_build_profile
448 } else {
449 platform_build.release_build_profile
450 };
451 let root_task = build_profile.map(|bp| RootTask {
452 make_command: bp.make_root_task,
453 image_path: bp.root_task_image.relative_to(&context.base_dir),
454 });
455 let build = Build {
456 cross_compiler_prefix: platform_build.cross_compiler_prefix,
457 toolchain_dir: platform_build
458 .toolchain_dir
459 .map(|p| p.relative_to(&context.base_dir)),
460 root_task,
461 };
462
463 fn resolve_context(
464 tree: &full::PropertiesTree,
465 context: &Context,
466 ) -> BTreeMap<String, SingleValue> {
467 let mut flat_properties = tree.shared.clone();
468 if context.is_debug {
469 flat_properties.extend(tree.debug.clone())
470 } else {
471 flat_properties.extend(tree.release.clone())
472 }
473
474 if let Some(arch_props) = tree.contextual.get(&context.arch.to_string()) {
475 flat_properties.extend(arch_props.clone());
476 }
477 if let Some(sel4_arch_props) = tree.contextual.get(&context.sel4_arch.to_string()) {
478 flat_properties.extend(sel4_arch_props.clone());
479 }
480 if let Some(platform_props) = tree.contextual.get(&context.platform.to_string()) {
481 flat_properties.extend(platform_props.clone());
482 }
483 flat_properties
484 }
485
486 let sel4_config = resolve_context(&f.sel4.config, &context);
487 let metadata = resolve_context(&f.metadata, &context);
488
489 let sel4_sources = f.sel4.sources.relative_to(&context.base_dir);
490
491 Ok(Contextualized {
492 sel4_sources,
493 context,
494 sel4_config,
495 build,
496 metadata,
497 })
498 }
499 }
500}
501
502#[cfg(test)]
503mod tests {
504 use super::*;
505 use std::path::PathBuf;
506
507 impl full::Full {
508 fn empty() -> Self {
509 full::Full {
510 sel4: full::SeL4 {
511 sources: SeL4Sources {
512 kernel: RepoSource::LocalPath(PathBuf::from(".")),
513 tools: RepoSource::LocalPath(PathBuf::from(".")),
514 util_libs: RepoSource::LocalPath(PathBuf::from(".")),
515 },
516 config: Default::default(),
517 },
518 build: Default::default(),
519 metadata: Default::default(),
520 }
521 }
522 }
523
524 #[test]
525 fn default_content_is_valid() {
526 let f: full::Full = get_default_config();
527 assert_eq!(
529 RepoSource::RemoteGit {
530 url: "https://github.com/seL4/seL4".to_string(),
531 target: GitTarget::Rev("4d0f02c029560cae0e8d93727eb17d58bcecc2ac".to_string())
532 },
533 f.sel4.sources.kernel
534 )
535 }
536
537 #[test]
538 fn override_default_platform_contextualization() {
539 let mut f = full::Full::empty();
540 let expected = Platform("sabre".to_owned());
541 f.build.insert(
542 expected.to_string(),
543 full::PlatformBuild {
544 cross_compiler_prefix: None,
545 toolchain_dir: None,
546 debug_build_profile: None,
547 release_build_profile: Some(full::PlatformBuildProfile {
548 make_root_task: Some("cmake".to_string()),
549 root_task_image: PathBuf::from("over_here"),
550 }),
551 },
552 );
553 let c = contextualized::Contextualized::from_full(
554 &f,
555 Arch::Arm,
556 SeL4Arch::Aarch32,
557 false,
558 expected.clone(),
559 None,
560 )
561 .unwrap();
562 assert_eq!(expected, c.context.platform);
563 assert_eq!(false, c.context.is_debug);
564 assert_eq!(Arch::Arm, c.context.arch);
565 assert_eq!(SeL4Arch::Aarch32, c.context.sel4_arch);
566 assert_eq!(
567 "cmake",
568 c.build
569 .root_task
570 .as_ref()
571 .unwrap()
572 .make_command
573 .as_ref()
574 .unwrap()
575 );
576 assert_eq!(
577 PathBuf::from("over_here"),
578 c.build.root_task.unwrap().image_path
579 );
580 }
581}