someboot 0.1.3

Sparreal OS kernel
Documentation
use std::{fs, io::Write, path::PathBuf};

fn main() {
    println!("cargo::rustc-check-cfg=cfg(efi)");
    println!("cargo::rustc-check-cfg=cfg(page_size_4k)");
    println!("cargo::rustc-check-cfg=cfg(page_size_16k)");
    println!("cargo::rustc-check-cfg=cfg(uspace)");
    println!("cargo::rustc-check-cfg=cfg(hv)");

    let target = std::env::var("TARGET").unwrap();

    if target.contains("windows") || target.contains("linux") || target.contains("darwin") {
        return;
    }

    let out_dir = PathBuf::from(std::env::var("OUT_DIR").unwrap());
    println!("cargo:rustc-link-search={}", out_dir.display());

    if std::env::var("CARGO_FEATURE_EFI").is_ok() {
        println!("cargo:rustc-cfg=efi");
    }

    let arch = std::env::var("CARGO_CFG_TARGET_ARCH").unwrap();
    let uspace = std::env::var("CARGO_FEATURE_USPACE").is_ok();
    let hv = std::env::var("CARGO_FEATURE_HV").is_ok();

    let mut build = Build {
        arch: Arch::from(arch.as_str()),
        out_dir,
        kernel_vaddr: 0x200000,
        uspace,
        hv,
        page_size: 4096,
    };

    build.prepare();

    if build.hv {
        println!("cargo:rustc-cfg=hv");
    } else if build.uspace {
        println!("cargo:rustc-cfg=uspace");
    }

    if build.page_size == 4096 {
        println!("cargo:rustc-cfg=page_size_4k");
    } else if build.page_size == 16384 {
        println!("cargo:rustc-cfg=page_size_16k");
    }
}

#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
enum Arch {
    #[default]
    Loongarch64,
    Arch64,
}

impl From<&str> for Arch {
    fn from(s: &str) -> Self {
        match s {
            "loongarch64" => Arch::Loongarch64,
            "aarch64" => Arch::Arch64,
            _ => todo!(),
        }
    }
}

#[derive(Default)]
struct Build {
    arch: Arch,
    out_dir: PathBuf,
    kernel_vaddr: u64,
    uspace: bool,
    hv: bool,
    page_size: usize,
}

impl Build {
    const LD_NAME: &'static str = "someboot.x";

    fn prepare(&mut self) {
        match self.arch {
            Arch::Loongarch64 => self.prepare_loongarch64(),
            Arch::Arch64 => self.prepare_aarch64(),
        }

        self.gen_defines();
    }

    fn prepare_aarch64(&mut self) {
        println!("cargo::rustc-check-cfg=cfg(hard_float)");

        let ld_src = "src/arch/aarch64/link.ld";

        if self.hv {
            self.uspace = false;
            self.kernel_vaddr = 0xffff_8000_0000;
        } else {
            self.uspace = true;
            self.kernel_vaddr = 0xffff_ffff_8000_0000;
        }

        let kernel_vaddr = self.kernel_vaddr as usize;

        let ld = include_str!("src/arch/aarch64/link.ld")
            .replace("${kernel_load_vaddr}", &format!("{kernel_vaddr:#x}"));

        println!("cargo:rerun-if-changed={ld_src}");
        if std::env::var("CARGO_FEATURE_EFI").is_ok() {
            println!("cargo:rustc-cfg=efi");
        }
        let ld_dst = self.out_dir.join(Self::LD_NAME);

        fs::write(ld_dst, ld).unwrap();
    }

    fn prepare_loongarch64(&mut self) {
        let ld_src = "src/arch/loongarch64/link.ld";

        self.kernel_vaddr = 0xffff_ffff_8000_0000;

        let kernel_load_vaddr = self.kernel_vaddr as usize;

        let ld = include_str!("src/arch/loongarch64/link.ld")
            .replace("${kernel_load_vaddr}", &format!("{kernel_load_vaddr:#x}"));

        println!("cargo:rerun-if-changed={ld_src}");
        println!("cargo:rustc-cfg=efi");

        let ld_dst = self.out_dir.join(Self::LD_NAME);

        fs::write(ld_dst, ld).unwrap();
    }

    fn gen_defines(&self) {
        let kernel_load_vaddr = self.kernel_vaddr as usize;
        let defines = quote::quote! {
            #[allow(dead_code)]
            pub const VM_LOAD_ADDRESS: usize = #kernel_load_vaddr;
        };
        let syntax_tree = syn::parse2(defines).unwrap();
        let formatted = prettyplease::unparse(&syntax_tree);
        let mut out_file = fs::File::create(self.out_dir.join("defines.rs")).unwrap();
        out_file.write_all(formatted.as_bytes()).unwrap();
    }
}