Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 22 additions & 41 deletions components/someboot/build.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
use std::{fs, io::Write, path::PathBuf};

#[path = "build_support/linker.rs"]
mod linker;

use linker::{LinkerArch, LinkerConfig, render_linker_script, source_paths};

fn main() {
println!("cargo::rustc-check-cfg=cfg(efi)");
println!("cargo::rustc-check-cfg=cfg(page_size_4k)");
Expand Down Expand Up @@ -78,6 +83,10 @@ impl Build {
const LD_NAME: &'static str = "someboot.x";

fn prepare(&mut self) {
for path in source_paths() {
println!("cargo:rerun-if-changed={path}");
}

match self.arch {
Arch::Loongarch64 => self.prepare_loongarch64(),
Arch::Arch64 => self.prepare_aarch64(),
Expand All @@ -91,8 +100,6 @@ impl Build {
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;
Expand All @@ -101,73 +108,47 @@ impl Build {
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();
self.write_linker_script(LinkerArch::Aarch64);
}

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 kernel_load_paddr = self.kernel_paddr as usize;

let ld = include_str!("src/arch/loongarch64/link.ld")
.replace("${kernel_load_vaddr}", &format!("{kernel_load_vaddr:#x}"))
.replace("${kernel_load_paddr}", &format!("{kernel_load_paddr:#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();
self.write_linker_script(LinkerArch::Loongarch64);
}

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

self.kernel_vaddr = 0xffff_ffff_8000_0000;

let kernel_load_vaddr = self.kernel_vaddr as usize;

let ld = include_str!("src/arch/x86_64/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();
self.write_linker_script(LinkerArch::X86_64);
}

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

self.kernel_paddr = env_u64("SOMEBOOT_RISCV64_KERNEL_LOAD_PADDR").unwrap_or(0x8020_0000);
if self.uspace || self.hv {
self.kernel_vaddr = 0xffff_ffff_8000_0000;
} else {
self.kernel_vaddr = self.kernel_paddr;
}

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

println!("cargo:rerun-if-changed={ld_src}");
self.write_linker_script(LinkerArch::Riscv64);
}

fn write_linker_script(&self, arch: LinkerArch) {
let ld = render_linker_script(
arch,
LinkerConfig {
kernel_load_vaddr: self.kernel_vaddr,
kernel_load_paddr: self.kernel_paddr,
},
);
let ld_dst = self.out_dir.join(Self::LD_NAME);
fs::write(ld_dst, ld).unwrap();
}
Expand Down
224 changes: 224 additions & 0 deletions components/someboot/build_support/linker.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LinkerArch {
Aarch64,
Loongarch64,
X86_64,
Riscv64,
}

#[derive(Debug, Clone, Copy)]
pub struct LinkerConfig {
pub kernel_load_vaddr: u64,
pub kernel_load_paddr: u64,
}

struct LinkerTemplate {
path: &'static str,
content: &'static str,
replacements: &'static [(&'static str, &'static str)],
}

const DEFAULTS_PATH: &str = "src/ld/defaults.ld";
const TEXT_PATH: &str = "src/ld/text.ld";
const RODATA_PATH: &str = "src/ld/rodata.ld";
const DATA_PATH: &str = "src/ld/data.ld";
const RELA_DYN_PATH: &str = "src/ld/rela-dyn.ld";
const BSS_PATH: &str = "src/ld/bss.ld";
const DEBUG_PATH: &str = "src/ld/debug.ld";
const DISCARD_EXIT_PATH: &str = "src/ld/discard-exit.ld";
const DISCARD_DYNAMIC_PATH: &str = "src/ld/discard-dynamic.ld";

const FRAGMENTS: &[(&str, &str, &str)] = &[
(
DEFAULTS_PATH,
"${ld_defaults}",
include_str!("../src/ld/defaults.ld"),
),
(TEXT_PATH, "${ld_text}", include_str!("../src/ld/text.ld")),
(
RODATA_PATH,
"${ld_rodata}",
include_str!("../src/ld/rodata.ld"),
),
(DATA_PATH, "${ld_data}", include_str!("../src/ld/data.ld")),
(
RELA_DYN_PATH,
"${ld_rela_dyn}",
include_str!("../src/ld/rela-dyn.ld"),
),
(BSS_PATH, "${ld_bss}", include_str!("../src/ld/bss.ld")),
(
DEBUG_PATH,
"${ld_debug}",
include_str!("../src/ld/debug.ld"),
),
(
DISCARD_EXIT_PATH,
"${ld_discard_exit}",
include_str!("../src/ld/discard-exit.ld"),
),
(
DISCARD_DYNAMIC_PATH,
"${ld_discard_dynamic}",
include_str!("../src/ld/discard-dynamic.ld"),
),
];

const AARCH64_REPLACEMENTS: &[(&str, &str)] = &[
("${text_output}", ""),
("${rodata_extra}", ""),
(
"${data_extra}",
r#" *(.got .got.*)
*(.got.plt .got.plt.*)
*(.igot .igot.*)"#,
),
("${percpu_align}", "64"),
("${tdata_align}", ""),
("${tdata_output}", ":text :tls"),
("${post_tdata_sections}", ""),
("${edata_align}", ". = ALIGN(8);"),
("${bss_start_before_tbss}", "__bss_start = .;"),
("${bss_start_after_tbss}", ""),
("${tbss_align}", ""),
("${tbss_output}", ":text :tls"),
("${pre_sbss_align}", ". = ALIGN(8);"),
("${sbss_extra}", ""),
("${bss_output}", ":text"),
("${cpu_stack_align}", ". = ALIGN(PAGE_SIZE);"),
("${discard_options}", "*(.options)"),
("${discard_dynamic_extra}", "*(.eh_frame .eh_frame_hdr)"),
];

const LOONGARCH64_REPLACEMENTS: &[(&str, &str)] = &[
("${text_output}", ":text = 0"),
("${rodata_extra}", ""),
("${data_extra}", ""),
("${percpu_align}", "PAGE_SIZE"),
("${tdata_align}", ""),
("${tdata_output}", ":text :tls"),
("${post_tdata_sections}", ""),
("${edata_align}", ". = ALIGN(8);"),
("${bss_start_before_tbss}", "__bss_start = .;"),
("${bss_start_after_tbss}", ""),
("${tbss_align}", ""),
("${tbss_output}", ":text :tls"),
("${pre_sbss_align}", ". = ALIGN(8);"),
("${sbss_extra}", ""),
("${bss_output}", ""),
("${cpu_stack_align}", ". = ALIGN(PAGE_SIZE);"),
("${discard_options}", "*(.options)"),
("${discard_dynamic_extra}", "*(.eh_frame)"),
];

const X86_64_REPLACEMENTS: &[(&str, &str)] = &[
("${text_output}", ":text = 0"),
("${rodata_extra}", ""),
("${data_extra}", "*(.got .got.*)"),
("${percpu_align}", "PAGE_SIZE"),
("${tdata_align}", "ALIGN(16)"),
("${tdata_output}", ":text :tls"),
("${post_tdata_sections}", ""),
("${edata_align}", ""),
("${bss_start_before_tbss}", "__bss_start = .;"),
("${bss_start_after_tbss}", ""),
("${tbss_align}", "ALIGN(16)"),
("${tbss_output}", ":text :tls"),
("${pre_sbss_align}", ""),
("${sbss_extra}", ""),
("${bss_output}", ":text"),
("${cpu_stack_align}", ". = ALIGN(PAGE_SIZE);"),
("${discard_options}", ""),
("${discard_dynamic_extra}", "*(.eh_frame)"),
];

const RISCV64_REPLACEMENTS: &[(&str, &str)] = &[
("${text_output}", ""),
("${rodata_extra}", "*(.srodata .srodata.*)"),
("${data_extra}", ""),
("${percpu_align}", "PAGE_SIZE"),
("${tdata_align}", ""),
("${tdata_output}", ""),
(
"${post_tdata_sections}",
r#"
.dynamic : ALIGN(8) {
*(.dynamic)
}
.got : ALIGN(8) {
*(.got .got.*)
}"#,
),
("${edata_align}", ""),
("${bss_start_before_tbss}", ""),
("${bss_start_after_tbss}", "__bss_start = .;"),
("${tbss_align}", ""),
("${tbss_output}", ""),
("${pre_sbss_align}", ""),
("${sbss_extra}", "*(.sbss.*)"),
("${bss_output}", ""),
("${cpu_stack_align}", ""),
("${discard_options}", ""),
("${discard_dynamic_extra}", ""),
];

pub fn render_linker_script(arch: LinkerArch, config: LinkerConfig) -> String {
let template = arch.template();
let mut script = template.content.to_string();

for (_, token, fragment) in FRAGMENTS {
script = script.replace(token, fragment.trim_end());
}
for (token, value) in template.replacements {
script = script.replace(token, value);
}

script
.replace(
"${kernel_load_vaddr}",
&format!("{:#x}", config.kernel_load_vaddr as usize),
)
.replace(
"${kernel_load_paddr}",
&format!("{:#x}", config.kernel_load_paddr as usize),
)
}

pub fn source_paths() -> Vec<&'static str> {
let mut paths = vec![
"build_support/linker.rs",
LinkerArch::Aarch64.template().path,
LinkerArch::Loongarch64.template().path,
LinkerArch::X86_64.template().path,
LinkerArch::Riscv64.template().path,
];
paths.extend(FRAGMENTS.iter().map(|(path, ..)| *path));
paths
}

impl LinkerArch {
fn template(self) -> LinkerTemplate {
match self {
LinkerArch::Aarch64 => LinkerTemplate {
path: "src/arch/aarch64/link.ld",
content: include_str!("../src/arch/aarch64/link.ld"),
replacements: AARCH64_REPLACEMENTS,
},
LinkerArch::Loongarch64 => LinkerTemplate {
path: "src/arch/loongarch64/link.ld",
content: include_str!("../src/arch/loongarch64/link.ld"),
replacements: LOONGARCH64_REPLACEMENTS,
},
LinkerArch::X86_64 => LinkerTemplate {
path: "src/arch/x86_64/link.ld",
content: include_str!("../src/arch/x86_64/link.ld"),
replacements: X86_64_REPLACEMENTS,
},
LinkerArch::Riscv64 => LinkerTemplate {
path: "src/arch/riscv64/link.ld",
content: include_str!("../src/arch/riscv64/link.ld"),
replacements: RISCV64_REPLACEMENTS,
},
}
}
}
Loading