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
4 changes: 2 additions & 2 deletions build-fibonacci.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ TARGET_TRIPLE="riscv64imac-unknown-none-elf"
OUT_DIR="${ROOT}/target/${TARGET_TRIPLE}/$([ "$PROFILE" = "dev" ] && echo debug || echo "$PROFILE")"
BIN="${OUT_DIR}/fibonacci"

cargo spike build -p fibonacci --target "${TARGET_TRIPLE}" -- --quiet --features=debug --profile "${PROFILE}"
cargo spike build -p fibonacci --target "${TARGET_TRIPLE}" -- --quiet --features=debug,with-spike --profile "${PROFILE}"
OUT_NOSTD="$(mktemp)"
OUT_STD="$(mktemp)"
trap 'rm -f "${OUT_NOSTD}" "${OUT_STD}"' EXIT
Expand All @@ -28,7 +28,7 @@ TARGET_TRIPLE="riscv64imac-zero-linux-musl"
OUT_DIR="${ROOT}/target/${TARGET_TRIPLE}/$([ "$PROFILE" = "dev" ] && echo debug || echo "$PROFILE")"
BIN="${OUT_DIR}/fibonacci"

cargo spike build -p fibonacci --target "${TARGET_TRIPLE}" --mode std -- --quiet --features=std,debug --profile "${PROFILE}"
cargo spike build -p fibonacci --target "${TARGET_TRIPLE}" --mode std -- --quiet --features=std,debug,with-spike --profile "${PROFILE}"
RUST_LOG=debug cargo spike run "${BIN}" --isa RV64IMAC --instructions 100000000 | tee "${OUT_STD}"
grep -q "fibonacci(10) = 55" "${OUT_STD}"
grep -q "Test PASSED" "${OUT_STD}"
2 changes: 1 addition & 1 deletion build-std-smoke.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ BIN="${OUT_DIR}/std-smoke"
cd "${ROOT}"

echo "Building std-smoke example..."
cargo spike build -p std-smoke --target "${TARGET_TRIPLE}" --mode std --backtrace=enable -- --quiet --features=std,backtrace --profile "${PROFILE}"
cargo spike build -p std-smoke --target "${TARGET_TRIPLE}" --mode std --backtrace=enable --memory-size=40MiB --stack-size=4MiB --heap-size=8MiB -- --features=std,backtrace,with-spike --profile "${PROFILE}"

echo "Running on Spike simulator..."
OUT="$(mktemp)"
Expand Down
5 changes: 3 additions & 2 deletions crates/zeroos-arch-riscv/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ fn main() {
let arch = std::env::var("CARGO_CFG_TARGET_ARCH").unwrap_or_default();
if arch != "riscv32" && arch != "riscv64" {
panic!(
"{} is RISC-V-only; build with a RISC-V target.",
env!("CARGO_PKG_NAME")
"{} is RISC-V-only; build with a RISC-V target (current: {}).",
env!("CARGO_PKG_NAME"),
arch
);
}
}
5 changes: 3 additions & 2 deletions crates/zeroos-arch-riscv/src/trap.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
//! Platforms must provide `trap_handler(regs: *mut TrapFrame)`; this crate provides the entry/exit wrapper.
#[cfg(not(target_os = "none"))]
use core::arch::global_asm;

use cfg_if::cfg_if;

Expand Down Expand Up @@ -153,8 +155,6 @@ cfg_if! {
}
}

use core::arch::global_asm;

mod imp {
use super::*;

Expand Down Expand Up @@ -305,6 +305,7 @@ mod imp {

pub use imp::_default_trap_handler;

#[cfg(not(target_os = "none"))]
global_asm!(
".align 2",
".weak _trap_handler",
Expand Down
18 changes: 18 additions & 0 deletions crates/zeroos-build/src/cmds/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,17 @@ pub fn build_binary(
args: &BuildArgs,
toolchain_paths: Option<(PathBuf, PathBuf)>,
linker_template: Option<String>,
) -> Result<()> {
build_binary_with_rustflags(workspace_root, args, toolchain_paths, linker_template, None)
}

/// Build binary with optional additional rustflags (for platform-specific flags)
pub fn build_binary_with_rustflags(
workspace_root: &PathBuf,
args: &BuildArgs,
toolchain_paths: Option<(PathBuf, PathBuf)>,
linker_template: Option<String>,
additional_rustflags: Option<&[&str]>,
) -> Result<()> {
info!(
"Building binary for {:?} mode (fully: {})",
Expand Down Expand Up @@ -195,6 +206,13 @@ pub fn build_binary(
rustflags_parts.push("-Zmacro-backtrace".to_string());
}

// Add platform-specific rustflags
if let Some(flags) = additional_rustflags {
for flag in flags {
rustflags_parts.push(flag.to_string());
}
}

let encoded_rustflags = rustflags_parts.join("\x1f");
debug!("CARGO_ENCODED_RUSTFLAGS: {:?}", encoded_rustflags);

Expand Down
3 changes: 2 additions & 1 deletion crates/zeroos-build/src/cmds/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ pub mod linker;
pub mod target;

pub use build::{
build_binary, find_workspace_root, get_or_build_toolchain, parse_address, BuildArgs, StdMode,
build_binary, build_binary_with_rustflags, find_workspace_root, get_or_build_toolchain,
parse_address, BuildArgs, StdMode,
};
pub use linker::{generate_linker_script, GenerateLinkerArgs, LinkerGeneratorResult};
pub use target::{generate_target_spec, GenerateTargetArgs};
74 changes: 39 additions & 35 deletions crates/zeroos-build/src/toolchain/install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,40 +63,6 @@ fn host_arch() -> &'static str {
}
}

fn default_repo_from_git() -> Option<String> {
let out = Command::new("git")
.args(["config", "--get", "remote.origin.url"])
.output()
.ok()?;
if !out.status.success() {
return None;
}
let url = String::from_utf8_lossy(&out.stdout).trim().to_string();
if url.is_empty() {
return None;
}

// https://github.com/ORG/REPO.git
if let Some(rest) = url.strip_prefix("https://github.com/") {
let rest = rest.strip_suffix(".git").unwrap_or(rest);
let mut parts = rest.split('/');
let owner = parts.next()?;
let repo = parts.next()?;
return Some(format!("{}/{}", owner, repo));
}

// git@github.com:ORG/REPO.git
if let Some(rest) = url.strip_prefix("git@github.com:") {
let rest = rest.strip_suffix(".git").unwrap_or(rest);
let mut parts = rest.split('/');
let owner = parts.next()?;
let repo = parts.next()?;
return Some(format!("{}/{}", owner, repo));
}

None
}

fn run(cmd: &mut Command) -> Result<(), String> {
debug!("Running command: {:?}", cmd);
let status = cmd
Expand Down Expand Up @@ -214,7 +180,6 @@ pub fn install_musl_toolchain(config: &InstallConfig) -> Result<ToolchainPaths,
.repo
.clone()
.or_else(|| std::env::var("ZEROOS_MUSL_TOOLCHAIN_REPO").ok())
.or_else(default_repo_from_git)
.unwrap_or_else(|| "LayerZero-Labs/ZeroOS".to_string());

let output_dir = PathBuf::from(&config.output_dir);
Expand Down Expand Up @@ -328,3 +293,42 @@ pub fn get_or_install_toolchain(
Err(_e) => install_musl_toolchain(install),
}
}

/// Resolve toolchain, or download pre-built, or build from source as last resort.
///
/// Fallback chain:
/// 1. Try to resolve existing toolchain from args/env/default locations
/// 2. Try to download pre-built toolchain from GitHub Releases
/// 3. If `build_fallback` is true, build from source as last resort
pub fn get_or_install_or_build_toolchain(
musl_lib_arg: Option<PathBuf>,
gcc_lib_arg: Option<PathBuf>,
config: &ToolchainConfig,
install: &InstallConfig,
build_fallback: bool,
) -> Result<ToolchainPaths, String> {
use super::{build_musl_toolchain, resolve_toolchain_paths, BuildConfig};

// Try existing paths
if let Ok(paths) = resolve_toolchain_paths(musl_lib_arg, gcc_lib_arg, config) {
return Ok(paths);
}

// Try downloading pre-built
match install_musl_toolchain(install) {
Ok(paths) => return Ok(paths),
Err(e) if build_fallback => {
info!("Download failed: {}. Building from source...", e);
}
Err(e) => return Err(e),
}

// Build from source
info!("Building toolchain from source (this may take 5-15 minutes)...");
let build_config = BuildConfig {
arch: config.arch.clone(),
output_dir: install.output_dir.clone(),
..BuildConfig::default()
};
build_musl_toolchain(&build_config)
}
5 changes: 4 additions & 1 deletion crates/zeroos-build/src/toolchain/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ mod discovery;
mod install;

pub use discovery::{discover_toolchain, validate_toolchain_path, ToolchainPaths};
pub use install::{get_or_install_toolchain, install_musl_toolchain, InstallConfig};
pub use install::{
get_or_install_or_build_toolchain, get_or_install_toolchain, install_musl_toolchain,
InstallConfig,
};

use std::format;
use std::path::{Path, PathBuf};
Expand Down
32 changes: 29 additions & 3 deletions crates/zeroos-foundation/src/entry.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,19 @@
// - `#[no_mangle] fn main() -> !` (Rust, must call exit())
// Entry point for calling the user's main() function.
//
// `__main_entry` is defined as a weak symbol that jumps to `__default_main_entry`.
// Platforms/SDKs can provide their own strong `__main_entry` to override this.

#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
use core::arch::global_asm;

unsafe extern "C" {
/// # Safety
/// Entry point for the user's main function.
/// This is a weak symbol defined by foundation that can be overridden
/// by platforms/SDKs that need a different main() signature.
pub unsafe fn __main_entry(argc: i32, argv: *const *const u8, envp: *const *const u8) -> i32;
}

cfg_if::cfg_if! {
if #[cfg(feature = "libc-main")] {
extern "C" {
Expand All @@ -10,7 +25,7 @@ cfg_if::cfg_if! {
/// # Safety
/// The caller must provide `argv` and `envp` pointers that are valid per the platform ABI
/// (or null), and remain valid for the duration of the call.
pub unsafe extern "C" fn __main_entry(argc: i32, argv: *const *const u8, envp: *const *const u8) -> i32 {
pub unsafe extern "C" fn __default_main_entry(argc: i32, argv: *const *const u8, envp: *const *const u8) -> i32 {
main(argc, argv, envp)
}
} else {
Expand All @@ -22,7 +37,7 @@ cfg_if::cfg_if! {

#[no_mangle]
#[inline(never)]
pub extern "C" fn __main_entry(_argc: i32, _argv: *const *const u8, _envp: *const *const u8) -> i32 {
pub extern "C" fn __default_main_entry(_argc: i32, _argv: *const *const u8, _envp: *const *const u8) -> i32 {
debug::writeln!("[BOOT] __main_entry argc={} argv=0x{:x}", _argc, _argv as usize);

unsafe {
Expand All @@ -32,3 +47,14 @@ cfg_if::cfg_if! {
}
}
}

// Define __main_entry as a weak symbol that jumps to __default_main_entry.
// Platforms providing their own __main_entry can define a strong symbol to override.
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
global_asm!(
".weak __main_entry",
".type __main_entry, @function",
"__main_entry:",
"j {default}",
default = sym __default_main_entry,
);
Loading
Loading