Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

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

scripts: add `generate_rust_target.rs`

This script takes care of generating the custom target specification
file for `rustc`, based on the kernel configuration.

It also serves as an example of a Rust host program.

A dummy architecture is kept in this patch so that a later patch
adds x86 support on top with as few changes as possible.

Reviewed-by: Kees Cook <keescook@chromium.org>
Co-developed-by: Alex Gaynor <alex.gaynor@gmail.com>
Signed-off-by: Alex Gaynor <alex.gaynor@gmail.com>
Co-developed-by: Wedson Almeida Filho <wedsonaf@google.com>
Signed-off-by: Wedson Almeida Filho <wedsonaf@google.com>
Co-developed-by: David Gow <davidgow@google.com>
Signed-off-by: David Gow <davidgow@google.com>
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>

+172
+1
scripts/.gitignore
··· 1 1 # SPDX-License-Identifier: GPL-2.0-only 2 2 /asn1_compiler 3 3 /bin2c 4 + /generate_rust_target 4 5 /insert-sys-cert 5 6 /kallsyms 6 7 /module.lds
+171
scripts/generate_rust_target.rs
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + //! The custom target specification file generator for `rustc`. 4 + //! 5 + //! To configure a target from scratch, a JSON-encoded file has to be passed 6 + //! to `rustc` (introduced in [RFC 131]). These options and the file itself are 7 + //! unstable. Eventually, `rustc` should provide a way to do this in a stable 8 + //! manner. For instance, via command-line arguments. Therefore, this file 9 + //! should avoid using keys which can be set via `-C` or `-Z` options. 10 + //! 11 + //! [RFC 131]: https://rust-lang.github.io/rfcs/0131-target-specification.html 12 + 13 + use std::{ 14 + collections::HashMap, 15 + fmt::{Display, Formatter, Result}, 16 + io::BufRead, 17 + }; 18 + 19 + enum Value { 20 + Boolean(bool), 21 + Number(i32), 22 + String(String), 23 + Object(Object), 24 + } 25 + 26 + type Object = Vec<(String, Value)>; 27 + 28 + /// Minimal "almost JSON" generator (e.g. no `null`s, no arrays, no escaping), 29 + /// enough for this purpose. 30 + impl Display for Value { 31 + fn fmt(&self, formatter: &mut Formatter<'_>) -> Result { 32 + match self { 33 + Value::Boolean(boolean) => write!(formatter, "{}", boolean), 34 + Value::Number(number) => write!(formatter, "{}", number), 35 + Value::String(string) => write!(formatter, "\"{}\"", string), 36 + Value::Object(object) => { 37 + formatter.write_str("{")?; 38 + if let [ref rest @ .., ref last] = object[..] { 39 + for (key, value) in rest { 40 + write!(formatter, "\"{}\": {},", key, value)?; 41 + } 42 + write!(formatter, "\"{}\": {}", last.0, last.1)?; 43 + } 44 + formatter.write_str("}") 45 + } 46 + } 47 + } 48 + } 49 + 50 + struct TargetSpec(Object); 51 + 52 + impl TargetSpec { 53 + fn new() -> TargetSpec { 54 + TargetSpec(Vec::new()) 55 + } 56 + } 57 + 58 + trait Push<T> { 59 + fn push(&mut self, key: &str, value: T); 60 + } 61 + 62 + impl Push<bool> for TargetSpec { 63 + fn push(&mut self, key: &str, value: bool) { 64 + self.0.push((key.to_string(), Value::Boolean(value))); 65 + } 66 + } 67 + 68 + impl Push<i32> for TargetSpec { 69 + fn push(&mut self, key: &str, value: i32) { 70 + self.0.push((key.to_string(), Value::Number(value))); 71 + } 72 + } 73 + 74 + impl Push<String> for TargetSpec { 75 + fn push(&mut self, key: &str, value: String) { 76 + self.0.push((key.to_string(), Value::String(value))); 77 + } 78 + } 79 + 80 + impl Push<&str> for TargetSpec { 81 + fn push(&mut self, key: &str, value: &str) { 82 + self.push(key, value.to_string()); 83 + } 84 + } 85 + 86 + impl Push<Object> for TargetSpec { 87 + fn push(&mut self, key: &str, value: Object) { 88 + self.0.push((key.to_string(), Value::Object(value))); 89 + } 90 + } 91 + 92 + impl Display for TargetSpec { 93 + fn fmt(&self, formatter: &mut Formatter<'_>) -> Result { 94 + // We add some newlines for clarity. 95 + formatter.write_str("{\n")?; 96 + if let [ref rest @ .., ref last] = self.0[..] { 97 + for (key, value) in rest { 98 + write!(formatter, " \"{}\": {},\n", key, value)?; 99 + } 100 + write!(formatter, " \"{}\": {}\n", last.0, last.1)?; 101 + } 102 + formatter.write_str("}") 103 + } 104 + } 105 + 106 + struct KernelConfig(HashMap<String, String>); 107 + 108 + impl KernelConfig { 109 + /// Parses `include/config/auto.conf` from `stdin`. 110 + fn from_stdin() -> KernelConfig { 111 + let mut result = HashMap::new(); 112 + 113 + let stdin = std::io::stdin(); 114 + let mut handle = stdin.lock(); 115 + let mut line = String::new(); 116 + 117 + loop { 118 + line.clear(); 119 + 120 + if handle.read_line(&mut line).unwrap() == 0 { 121 + break; 122 + } 123 + 124 + if line.starts_with('#') { 125 + continue; 126 + } 127 + 128 + let (key, value) = line.split_once('=').expect("Missing `=` in line."); 129 + result.insert(key.to_string(), value.trim_end_matches('\n').to_string()); 130 + } 131 + 132 + KernelConfig(result) 133 + } 134 + 135 + /// Does the option exist in the configuration (any value)? 136 + /// 137 + /// The argument must be passed without the `CONFIG_` prefix. 138 + /// This avoids repetition and it also avoids `fixdep` making us 139 + /// depend on it. 140 + fn has(&self, option: &str) -> bool { 141 + let option = "CONFIG_".to_owned() + option; 142 + self.0.contains_key(&option) 143 + } 144 + } 145 + 146 + fn main() { 147 + let cfg = KernelConfig::from_stdin(); 148 + let mut ts = TargetSpec::new(); 149 + 150 + // `llvm-target`s are taken from `scripts/Makefile.clang`. 151 + if cfg.has("DUMMY_ARCH") { 152 + ts.push("arch", "dummy_arch"); 153 + } else { 154 + panic!("Unsupported architecture"); 155 + } 156 + 157 + ts.push("emit-debug-gdb-scripts", false); 158 + ts.push("frame-pointer", "may-omit"); 159 + ts.push( 160 + "stack-probes", 161 + vec![("kind".to_string(), Value::String("none".to_string()))], 162 + ); 163 + 164 + // Everything else is LE, whether `CPU_LITTLE_ENDIAN` is declared or not 165 + // (e.g. x86). It is also `rustc`'s default. 166 + if cfg.has("CPU_BIG_ENDIAN") { 167 + ts.push("target-endian", "big"); 168 + } 169 + 170 + println!("{}", ts); 171 + }