1#[cfg(feature = "alloc")]
15use alloc::{
16 collections::BTreeMap,
17 format,
18 string::{String, ToString},
19 vec,
20 vec::Vec,
21};
22
23use crate::error::{KernelError, KernelResult};
24
25#[derive(Debug, Clone, Copy, PartialEq, Eq)]
31pub struct VeridianTarget {
32 pub triple: &'static str,
34 pub arch: &'static str,
36 pub features: &'static str,
38}
39
40impl VeridianTarget {
41 pub const X86_64: VeridianTarget = VeridianTarget {
43 triple: "x86_64-veridian",
44 arch: "x86_64",
45 features: "-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-avx,-avx2,+soft-float",
46 };
47
48 pub const AARCH64: VeridianTarget = VeridianTarget {
50 triple: "aarch64-veridian",
51 arch: "aarch64",
52 features: "+strict-align",
53 };
54
55 pub const RISCV64: VeridianTarget = VeridianTarget {
57 triple: "riscv64gc-veridian",
58 arch: "riscv64",
59 features: "+m,+a,+f,+d,+c",
60 };
61
62 pub fn from_triple(triple: &str) -> Option<VeridianTarget> {
64 match triple {
65 "x86_64-veridian" => Some(Self::X86_64),
66 "aarch64-veridian" => Some(Self::AARCH64),
67 "riscv64gc-veridian" => Some(Self::RISCV64),
68 _ => None,
69 }
70 }
71
72 pub fn current() -> VeridianTarget {
74 #[cfg(target_arch = "x86_64")]
75 {
76 Self::X86_64
77 }
78 #[cfg(target_arch = "aarch64")]
79 {
80 Self::AARCH64
81 }
82 #[cfg(target_arch = "riscv64")]
83 {
84 Self::RISCV64
85 }
86 }
87}
88
89#[cfg(feature = "alloc")]
95#[derive(Debug, Clone, PartialEq, Eq)]
96pub enum ToolchainComponent {
97 Compiler { language: String },
99 Linker,
101 Assembler,
103 Debugger,
105 Profiler,
107}
108
109#[cfg(feature = "alloc")]
115#[derive(Debug, Clone)]
116pub struct Toolchain {
117 pub name: String,
119 pub version: String,
121 pub target_triple: String,
123 pub bin_path: String,
125 pub sysroot_path: String,
127 pub components: Vec<ToolchainComponent>,
129}
130
131#[cfg(feature = "alloc")]
132impl Toolchain {
133 pub fn new(
135 name: &str,
136 version: &str,
137 target_triple: &str,
138 bin_path: &str,
139 sysroot_path: &str,
140 ) -> Self {
141 Self {
142 name: String::from(name),
143 version: String::from(version),
144 target_triple: String::from(target_triple),
145 bin_path: String::from(bin_path),
146 sysroot_path: String::from(sysroot_path),
147 components: Vec::new(),
148 }
149 }
150
151 pub fn add_component(&mut self, component: ToolchainComponent) {
153 if !self.components.contains(&component) {
154 self.components.push(component);
155 }
156 }
157
158 pub fn has_component(&self, component: &ToolchainComponent) -> bool {
160 self.components.contains(component)
161 }
162}
163
164#[cfg(feature = "alloc")]
170#[derive(Debug, Clone)]
171pub struct ToolchainRegistry {
172 toolchains: BTreeMap<String, Toolchain>,
174 default_name: Option<String>,
176}
177
178#[cfg(feature = "alloc")]
179impl ToolchainRegistry {
180 pub fn new() -> Self {
182 Self {
183 toolchains: BTreeMap::new(),
184 default_name: None,
185 }
186 }
187
188 pub fn register(&mut self, toolchain: Toolchain) -> KernelResult<()> {
191 if self.toolchains.contains_key(&toolchain.name) {
192 return Err(KernelError::AlreadyExists {
193 resource: "toolchain",
194 id: 0,
195 });
196 }
197 self.toolchains.insert(toolchain.name.clone(), toolchain);
198 Ok(())
199 }
200
201 pub fn get(&self, name: &str) -> Option<&Toolchain> {
203 self.toolchains.get(name)
204 }
205
206 pub fn list(&self) -> Vec<&str> {
208 self.toolchains.keys().map(|k| k.as_str()).collect()
209 }
210
211 pub fn remove(&mut self, name: &str) -> KernelResult<Toolchain> {
213 if self.default_name.as_deref() == Some(name) {
215 self.default_name = None;
216 }
217 self.toolchains.remove(name).ok_or(KernelError::NotFound {
218 resource: "toolchain",
219 id: 0,
220 })
221 }
222
223 pub fn set_default(&mut self, name: &str) -> KernelResult<()> {
226 if !self.toolchains.contains_key(name) {
227 return Err(KernelError::NotFound {
228 resource: "toolchain",
229 id: 0,
230 });
231 }
232 self.default_name = Some(String::from(name));
233 Ok(())
234 }
235
236 pub fn get_default(&self) -> Option<&Toolchain> {
238 self.default_name
239 .as_deref()
240 .and_then(|name| self.toolchains.get(name))
241 }
242}
243
244#[cfg(feature = "alloc")]
245impl Default for ToolchainRegistry {
246 fn default() -> Self {
247 Self::new()
248 }
249}
250
251#[cfg(feature = "alloc")]
257#[derive(Debug, Clone)]
258pub struct CrossCompilerConfig {
259 pub cc: String,
261 pub cxx: String,
263 pub ar: String,
265 pub ld: String,
267 pub ranlib: String,
269 pub strip: String,
271}
272
273#[cfg(feature = "alloc")]
274impl CrossCompilerConfig {
275 pub fn for_target(target: &str) -> Self {
278 let prefix = match target {
279 "x86_64-veridian" | "x86_64-unknown-none" => "x86_64-veridian",
280 "aarch64-veridian" | "aarch64-unknown-none" => "aarch64-veridian",
281 "riscv64gc-veridian" | "riscv64gc-unknown-none-elf" => "riscv64gc-veridian",
282 other => other,
283 };
284 let sysroot = super::get_sysroot();
285
286 Self {
287 cc: format!("{}/bin/{}-gcc", sysroot, prefix),
288 cxx: format!("{}/bin/{}-g++", sysroot, prefix),
289 ar: format!("{}/bin/{}-ar", sysroot, prefix),
290 ld: format!("{}/bin/{}-ld", sysroot, prefix),
291 ranlib: format!("{}/bin/{}-ranlib", sysroot, prefix),
292 strip: format!("{}/bin/{}-strip", sysroot, prefix),
293 }
294 }
295
296 pub fn to_env_vars(&self) -> BTreeMap<String, String> {
299 let mut env = BTreeMap::new();
300 env.insert(String::from("CC"), self.cc.clone());
301 env.insert(String::from("CXX"), self.cxx.clone());
302 env.insert(String::from("AR"), self.ar.clone());
303 env.insert(String::from("LD"), self.ld.clone());
304 env.insert(String::from("RANLIB"), self.ranlib.clone());
305 env.insert(String::from("STRIP"), self.strip.clone());
306 env
307 }
308}
309
310#[cfg(feature = "alloc")]
313pub fn generate_cross_env(target: &str) -> BTreeMap<String, String> {
314 let cross = CrossCompilerConfig::for_target(target);
315 let mut env = cross.to_env_vars();
316
317 let sysroot = super::get_sysroot();
318 let target_info = VeridianTarget::from_triple(target);
319
320 env.insert(
322 String::from("CFLAGS"),
323 format!("--sysroot={} -ffreestanding -nostdlib", sysroot),
324 );
325 env.insert(
326 String::from("CXXFLAGS"),
327 format!("--sysroot={} -ffreestanding -nostdlib", sysroot),
328 );
329 env.insert(
330 String::from("LDFLAGS"),
331 format!("-L{}/lib/{} -nostdlib", sysroot, target),
332 );
333
334 env.insert(
336 String::from("PKG_CONFIG_SYSROOT_DIR"),
337 String::from(sysroot),
338 );
339 env.insert(
340 String::from("PKG_CONFIG_PATH"),
341 format!("{}/lib/{}/pkgconfig", sysroot, target),
342 );
343
344 if let Some(info) = target_info {
346 env.insert(String::from("VERIDIAN_ARCH"), String::from(info.arch));
347 env.insert(String::from("VERIDIAN_TARGET"), String::from(info.triple));
348 env.insert(
349 String::from("VERIDIAN_FEATURES"),
350 String::from(info.features),
351 );
352 }
353
354 env
355}
356
357#[cfg(feature = "alloc")]
363#[derive(Debug, Clone)]
364pub struct LinkerConfig {
365 pub linker_path: String,
367 pub linker_script: Option<String>,
369 pub search_paths: Vec<String>,
371 pub flags: Vec<String>,
373}
374
375#[cfg(feature = "alloc")]
376impl LinkerConfig {
377 pub fn for_target(target: &str) -> Self {
380 let sysroot = super::get_sysroot();
381 let cross = CrossCompilerConfig::for_target(target);
382 let lib_dir = format!("{}/lib/{}", sysroot, target);
383
384 let mut flags = vec![String::from("--gc-sections")];
385
386 match target {
388 "x86_64-veridian" | "x86_64-unknown-none" => {
389 flags.push(String::from("-z"));
390 flags.push(String::from("max-page-size=4096"));
391 }
392 "aarch64-veridian" | "aarch64-unknown-none" => {
393 flags.push(String::from("-z"));
394 flags.push(String::from("max-page-size=65536"));
395 }
396 "riscv64gc-veridian" | "riscv64gc-unknown-none-elf" => {
397 flags.push(String::from("-z"));
398 flags.push(String::from("max-page-size=4096"));
399 }
400 _ => {}
401 }
402
403 Self {
404 linker_path: cross.ld,
405 linker_script: None,
406 search_paths: vec![lib_dir],
407 flags,
408 }
409 }
410}
411
412#[cfg(feature = "alloc")]
424pub fn generate_linker_script(target: &str) -> String {
425 let (entry, origin) = match target {
426 "x86_64-veridian" | "x86_64-unknown-none" => ("_start", "0xFFFFFFFF80100000"),
427 "aarch64-veridian" | "aarch64-unknown-none" => ("_start", "0x40080000"),
428 "riscv64gc-veridian" | "riscv64gc-unknown-none-elf" => ("_start", "0x80200000"),
429 _ => ("_start", "0x100000"),
430 };
431
432 let mut s = String::new();
433 s.push_str("/* VeridianOS linker script - auto-generated */\n");
434 s.push_str(&format!("ENTRY({})\n\n", entry));
435 s.push_str("SECTIONS\n{\n");
436 s.push_str(&format!(" . = {};\n\n", origin));
437
438 s.push_str(" .text : ALIGN(4096)\n {\n");
440 s.push_str(" _text_start = .;\n");
441 s.push_str(" *(.text.boot)\n");
442 s.push_str(" *(.text .text.*)\n");
443 s.push_str(" _text_end = .;\n");
444 s.push_str(" }\n\n");
445
446 s.push_str(" .rodata : ALIGN(4096)\n {\n");
448 s.push_str(" _rodata_start = .;\n");
449 s.push_str(" *(.rodata .rodata.*)\n");
450 s.push_str(" _rodata_end = .;\n");
451 s.push_str(" }\n\n");
452
453 s.push_str(" .data : ALIGN(4096)\n {\n");
455 s.push_str(" _data_start = .;\n");
456 s.push_str(" *(.data .data.*)\n");
457 s.push_str(" _data_end = .;\n");
458 s.push_str(" }\n\n");
459
460 s.push_str(" .bss : ALIGN(4096)\n {\n");
462 s.push_str(" _bss_start = .;\n");
463 s.push_str(" *(.bss .bss.*)\n");
464 s.push_str(" *(COMMON)\n");
465 s.push_str(" _bss_end = .;\n");
466 s.push_str(" }\n\n");
467
468 s.push_str(" _kernel_end = .;\n\n");
469 s.push_str(" /DISCARD/ :\n {\n");
470 s.push_str(" *(.comment)\n");
471 s.push_str(" *(.note.*)\n");
472 s.push_str(" *(.eh_frame*)\n");
473 s.push_str(" }\n");
474 s.push_str("}\n");
475
476 s
477}
478
479#[cfg(feature = "alloc")]
485#[derive(Debug, Clone)]
486pub struct CMakeToolchainFile {
487 pub target: String,
489}
490
491#[cfg(feature = "alloc")]
492impl CMakeToolchainFile {
493 pub fn new(target: &str) -> Self {
495 Self {
496 target: target.to_string(),
497 }
498 }
499
500 pub fn generate(&self) -> String {
506 let cross = CrossCompilerConfig::for_target(&self.target);
507 let sysroot = super::get_sysroot();
508
509 let processor = match self.target.as_str() {
510 "x86_64-veridian" | "x86_64-unknown-none" => "x86_64",
511 "aarch64-veridian" | "aarch64-unknown-none" => "aarch64",
512 "riscv64gc-veridian" | "riscv64gc-unknown-none-elf" => "riscv64",
513 _ => "unknown",
514 };
515
516 let mut s = String::new();
517 s.push_str("# VeridianOS CMake toolchain file - auto-generated\n\n");
518 s.push_str("set(CMAKE_SYSTEM_NAME VeridianOS)\n");
519 s.push_str(&format!("set(CMAKE_SYSTEM_PROCESSOR {})\n\n", processor));
520
521 s.push_str(&format!("set(CMAKE_C_COMPILER {})\n", cross.cc));
522 s.push_str(&format!("set(CMAKE_CXX_COMPILER {})\n", cross.cxx));
523 s.push_str(&format!("set(CMAKE_AR {})\n", cross.ar));
524 s.push_str(&format!("set(CMAKE_RANLIB {})\n", cross.ranlib));
525 s.push_str(&format!("set(CMAKE_STRIP {})\n", cross.strip));
526 s.push_str(&format!("set(CMAKE_LINKER {})\n\n", cross.ld));
527
528 s.push_str(&format!("set(CMAKE_SYSROOT {})\n", sysroot));
529 s.push_str(&format!("set(CMAKE_FIND_ROOT_PATH {})\n\n", sysroot));
530
531 s.push_str("set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)\n");
532 s.push_str("set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)\n");
533 s.push_str("set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)\n");
534 s.push_str("set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)\n\n");
535
536 s.push_str("set(CMAKE_C_FLAGS_INIT \"-ffreestanding -nostdlib\")\n");
537 s.push_str("set(CMAKE_CXX_FLAGS_INIT \"-ffreestanding -nostdlib\")\n");
538
539 s
540 }
541}