Next Generation WASM Microkernel Operating System
wasm os rust microkernel
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 219 lines 6.7 kB view raw
1// Copyright 2025 Jonas Kruckenberg 2// 3// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or 4// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or 5// http://opensource.org/licenses/MIT>, at your option. This file may not be 6// copied, modified, or distributed except according to those terms. 7 8#![allow(unused)] 9 10use std::collections::BTreeSet; 11use std::fmt::{Display, Formatter}; 12use std::hash::{DefaultHasher, Hasher}; 13use std::path::{Path, PathBuf}; 14 15use color_eyre::eyre::{Context, bail, eyre}; 16use serde::Deserialize; 17 18#[derive(Clone, Debug, Deserialize)] 19#[serde(rename_all = "kebab-case", deny_unknown_fields)] 20struct RawConfiguration { 21 arch: Architecture, 22 name: String, 23 #[serde(default)] 24 version: u32, 25 #[serde(default)] 26 max_log_level: LogLevel, 27 kernel: Kernel, 28 loader: Loader, 29} 30 31#[derive(Clone, Copy, Debug, Deserialize)] 32pub enum Architecture { 33 #[serde(rename = "riscv64")] 34 Riscv64, 35} 36 37#[repr(u8)] 38#[derive(Clone, Copy, Default, Debug, Deserialize)] 39#[serde(rename_all = "kebab-case")] 40pub enum LogLevel { 41 Trace = 0, 42 Debug, 43 #[default] 44 Info, 45 Warn, 46 Error, 47} 48 49#[derive(Clone, Debug, Deserialize)] 50#[serde(rename_all = "kebab-case", deny_unknown_fields)] 51pub struct Kernel { 52 pub target: RawRustTarget, 53 pub stacksize_pages: Option<u32>, 54 pub max_log_level: Option<LogLevel>, 55 #[serde(default)] 56 pub features: Vec<String>, 57 #[serde(default)] 58 pub no_default_features: bool, 59} 60 61#[derive(Clone, Debug, Deserialize)] 62#[serde(rename_all = "kebab-case", deny_unknown_fields)] 63pub struct Loader { 64 pub target: RawRustTarget, 65 #[serde(default)] 66 pub features: Vec<String>, 67 #[serde(default)] 68 pub no_default_features: bool, 69} 70 71#[derive(Clone, Debug, Deserialize)] 72pub struct RawRustTarget(String); 73 74#[derive(Clone, Debug)] 75pub enum RustTarget { 76 Builtin(String), 77 Json(PathBuf), 78} 79 80impl RawRustTarget { 81 pub fn resolve(&self, configuration: &Configuration) -> RustTarget { 82 if self.0.ends_with(".json") { 83 RustTarget::Json(configuration.resolve_path(&self.0).unwrap()) 84 } else { 85 RustTarget::Builtin(self.0.clone()) 86 } 87 } 88} 89 90impl RustTarget { 91 pub fn name(&self) -> &str { 92 match self { 93 RustTarget::Builtin(name) => name.as_str(), 94 RustTarget::Json(path) => path.file_stem().unwrap().to_str().unwrap(), 95 } 96 } 97} 98 99impl Display for RustTarget { 100 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 101 match self { 102 RustTarget::Builtin(s) => write!(f, "{s}"), 103 RustTarget::Json(p) => write!(f, "{}", p.display()), 104 } 105 } 106} 107 108#[derive(Clone, Debug)] 109pub struct Configuration { 110 pub arch: Architecture, 111 pub name: String, 112 pub version: u32, 113 pub max_log_level: LogLevel, 114 pub kernel: Kernel, 115 pub loader: Loader, 116 pub buildhash: u64, 117 pub file_path: PathBuf, 118} 119 120impl Configuration { 121 pub fn from_file(file_path: &Path) -> crate::Result<Self> { 122 let mut hasher = DefaultHasher::new(); 123 124 let doc = read_and_flatten_toml(file_path, &mut hasher, &mut BTreeSet::new())?; 125 let configuration_contents = doc.to_string(); 126 127 let toml: RawConfiguration = toml::from_str(&configuration_contents)?; 128 129 // if we had any other checks, perform them here 130 131 Ok(Self { 132 arch: toml.arch, 133 name: toml.name, 134 version: toml.version, 135 max_log_level: toml.max_log_level, 136 kernel: toml.kernel, 137 loader: toml.loader, 138 buildhash: hasher.finish(), 139 file_path: file_path.to_path_buf(), 140 }) 141 } 142 143 pub fn resolve_path(&self, path: impl AsRef<Path>) -> crate::Result<PathBuf> { 144 self.file_path 145 .parent() 146 .unwrap() 147 .join(path) 148 .canonicalize() 149 .map_err(Into::into) 150 } 151} 152 153fn read_and_flatten_toml( 154 configuration: &Path, 155 hasher: &mut DefaultHasher, 156 seen: &mut BTreeSet<PathBuf>, 157) -> crate::Result<toml_edit::DocumentMut> { 158 use toml_patch::merge_toml_documents; 159 160 // Prevent diamond inheritance 161 if !seen.insert(configuration.to_owned()) { 162 bail!( 163 "{configuration:?} is inherited more than once; \ 164 diamond dependencies are not allowed" 165 ); 166 } 167 let configuration_contents = std::fs::read(configuration) 168 .with_context(|| format!("could not read {}", configuration.display()))?; 169 170 // Accumulate the contents into the buildhash here, so that we hash both 171 // the inheritance file and the target (recursively, if necessary) 172 hasher.write(&configuration_contents); 173 174 let configuration_contents = 175 std::str::from_utf8(&configuration_contents).context("failed to read manifest as UTF-8")?; 176 177 // Additive TOML file inheritance 178 let mut doc = configuration_contents 179 .parse::<toml_edit::DocumentMut>() 180 .context("failed to parse TOML file")?; 181 let Some(inherited_from) = doc.remove("inherit") else { 182 // No further inheritance, so return the current document 183 return Ok(doc); 184 }; 185 186 use toml_edit::{Item, Value}; 187 let mut original = match inherited_from { 188 // Single inheritance 189 Item::Value(Value::String(s)) => { 190 let file = configuration.parent().unwrap().join(s.value()); 191 read_and_flatten_toml(&file, hasher, seen) 192 .with_context(|| format!("Could not load {file:?}"))? 193 } 194 // Multiple inheritance, applied sequentially 195 Item::Value(Value::Array(a)) => { 196 let mut doc: Option<toml_edit::DocumentMut> = None; 197 for a in a.iter() { 198 if let Value::String(s) = a { 199 let file = configuration.parent().unwrap().join(s.value()); 200 let next: toml_edit::DocumentMut = 201 read_and_flatten_toml(&file, hasher, seen) 202 .with_context(|| format!("Could not load {file:?}"))?; 203 match doc.as_mut() { 204 Some(doc) => merge_toml_documents(doc, next)?, 205 None => doc = Some(next), 206 } 207 } else { 208 bail!("could not inherit from {a}; bad type"); 209 } 210 } 211 doc.ok_or_else(|| eyre!("inherit array cannot be empty"))? 212 } 213 v => bail!("could not inherit from {v}; bad type"), 214 }; 215 216 // Finally, apply any changes that are local in this file 217 merge_toml_documents(&mut original, doc)?; 218 Ok(original) 219}