From b27aee9b8b21b367d12b499de29023d429b0ba79 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Wed, 9 Oct 2024 22:22:13 +0300 Subject: [PATCH 01/49] stabilize `ci_rustc_if_unchanged_logic` test Signed-off-by: onur-ozkan --- src/bootstrap/src/core/builder/tests.rs | 39 +++++++------------------ 1 file changed, 11 insertions(+), 28 deletions(-) diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index 4ab1ef1ad0ffd..695a66834d45d 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -1,7 +1,5 @@ use std::thread; -use build_helper::git::get_closest_merge_commit; - use super::*; use crate::Flags; use crate::core::build_steps::doc::DocumentationFormat; @@ -214,8 +212,6 @@ fn alias_and_path_for_library() { assert_eq!(first(cache.all::()), &[doc_std!(A => A, stage = 0)]); } -// FIXME: This is failing in various runners in merge CI. -#[ignore] #[test] fn ci_rustc_if_unchanged_logic() { let config = Config::parse_inner( @@ -227,10 +223,6 @@ fn ci_rustc_if_unchanged_logic() { |&_| Ok(Default::default()), ); - if config.rust_info.is_from_tarball() { - return; - } - let build = Build::new(config.clone()); let builder = Builder::new(&build); @@ -240,26 +232,17 @@ fn ci_rustc_if_unchanged_logic() { builder.run_step_descriptions(&Builder::get_step_descriptions(config.cmd.kind()), &[]); - let compiler_path = build.src.join("compiler"); - let library_path = build.src.join("library"); - - let commit = - get_closest_merge_commit(Some(&builder.config.src), &builder.config.git_config(), &[ - compiler_path.clone(), - library_path.clone(), - ]) - .unwrap(); - - let has_changes = !helpers::git(Some(&builder.src)) - .args(["diff-index", "--quiet", &commit]) - .arg("--") - .args([compiler_path, library_path]) - .as_command_mut() - .status() - .unwrap() - .success(); - - assert!(has_changes == config.download_rustc_commit.is_none()); + // Make sure "if-unchanged" logic doesn't try to use CI rustc while there are changes + // in compiler and/or library. + if config.download_rustc_commit.is_some() { + let has_changes = + config.last_modified_commit(&["compiler", "library"], "download-rustc", true).is_none(); + + assert!( + !has_changes, + "CI-rustc can't be used with 'if-unchanged' while there are changes in compiler and/or library." + ); + } } mod defaults { From de744eafe134a2f0ddde8db1b0d94ec5f8bc1481 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Thu, 10 Oct 2024 08:33:14 +0300 Subject: [PATCH 02/49] update `rustc_borrowck::places_conflict` doc-comment Signed-off-by: onur-ozkan --- compiler/rustc_borrowck/src/places_conflict.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_borrowck/src/places_conflict.rs b/compiler/rustc_borrowck/src/places_conflict.rs index 519ba0b9e0c9f..679e111caa984 100644 --- a/compiler/rustc_borrowck/src/places_conflict.rs +++ b/compiler/rustc_borrowck/src/places_conflict.rs @@ -3,7 +3,7 @@ //! we can prove overlap one way or another. Essentially, we treat `Overlap` as //! a monoid and report a conflict if the product ends up not being `Disjoint`. //! -//! At each step, if we didn't run out of borrow or place, we know that our elements +//! On each step, if we didn't run out of borrow or place, we know that our elements //! have the same type, and that they only overlap if they are the identical. //! //! For example, if we are comparing these: From 26f472d9800b7b7bd51b6a83dcb8a63d39af1fd7 Mon Sep 17 00:00:00 2001 From: Max Niederman Date: Mon, 27 May 2024 19:42:48 -0700 Subject: [PATCH 03/49] add armv7a-vex-v5 target --- compiler/rustc_target/src/spec/mod.rs | 2 + .../src/spec/targets/armv7a_vex_v5.rs | 34 ++++++++++++ .../targets/armv7a_vex_v5_linker_script.ld | 52 +++++++++++++++++++ 3 files changed, 88 insertions(+) create mode 100644 compiler/rustc_target/src/spec/targets/armv7a_vex_v5.rs create mode 100644 compiler/rustc_target/src/spec/targets/armv7a_vex_v5_linker_script.ld diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 82e11a3afce32..a7ef7ee8e55fd 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1913,6 +1913,8 @@ supported_targets! { ("armv7-sony-vita-newlibeabihf", armv7_sony_vita_newlibeabihf), + ("armv7a-vex-v5", armv7a_vex_v5), + ("armv7-unknown-linux-uclibceabi", armv7_unknown_linux_uclibceabi), ("armv7-unknown-linux-uclibceabihf", armv7_unknown_linux_uclibceabihf), diff --git a/compiler/rustc_target/src/spec/targets/armv7a_vex_v5.rs b/compiler/rustc_target/src/spec/targets/armv7a_vex_v5.rs new file mode 100644 index 0000000000000..bac7747e7d80e --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/armv7a_vex_v5.rs @@ -0,0 +1,34 @@ +use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions}; + +const LINK_SCRIPT: &str = include_str!("./armv7a_vex_v5_linker_script.ld"); + +pub(crate) fn target() -> Target { + Target { + llvm_target: "armv7a-none-eabi".into(), + metadata: crate::spec::TargetMetadata { + description: None, + tier: None, + host_tools: None, + std: None, + }, + pointer_width: 32, + data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), + arch: "arm".into(), + options: TargetOptions { + abi: "eabi".into(), + linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), + linker: Some("rust-lld".into()), + link_script: Some(LINK_SCRIPT.into()), + features: "+v7,+thumb2,+soft-float,-neon,+strict-align".into(), + relocation_model: RelocModel::Static, + disable_redzone: true, + max_atomic_width: Some(64), + panic_strategy: PanicStrategy::Abort, + emit_debug_gdb_scripts: false, + c_enum_min_bits: Some(8), + os: "vexos".into(), + vendor: "vex".into(), + ..Default::default() + }, + } +} diff --git a/compiler/rustc_target/src/spec/targets/armv7a_vex_v5_linker_script.ld b/compiler/rustc_target/src/spec/targets/armv7a_vex_v5_linker_script.ld new file mode 100644 index 0000000000000..f9436907c7feb --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/armv7a_vex_v5_linker_script.ld @@ -0,0 +1,52 @@ +OUTPUT_FORMAT("elf32-littlearm") + +ENTRY(_start) + +__cold_start = 0x03800000; +__cold_length = 0x04800000; +__cold_end = __cold_start + __cold_length; + +MEMORY { + COLD : ORIGIN = __cold_start, LENGTH = __cold_length +} + +__stack_length = 0x400000; +/* +I'm not sure why subtracting anything is necessary, but it fixes memory permission errors. +0x1000 is an arbitrary number that works. +*/ +__heap_end = __cold_end - __stack_length - 0x1000; + +SECTIONS { + .code_signature { + KEEP(*(.code_signature)) + . = __cold_start + 0x20; + } > COLD + .text : { + KEEP(*(.text.boot)) + *(.text .text.*) + } > COLD + .rodata : { + __rodata_start = .; + *(.rodata1 .rodata1.*) + __rodata_end = .; + } > COLD + .data : { + *(.data .data.*) + *(.data1 .data1.*) + } > COLD + .bss : { + __bss_start = .; + *(.bss .bss.*) + __bss_end = .; + } > COLD + .heap (NOLOAD) : ALIGN(4) { + __heap_start = .; + . = __heap_end; + } > COLD + .stack (NOLOAD) : ALIGN(8) { + __stack_end = .; + . += __stack_length; + __stack_start = .; + } > COLD +} From e5173851afede9229b7f2e0a6835854dc9f09bc1 Mon Sep 17 00:00:00 2001 From: Max Niederman Date: Mon, 27 May 2024 20:31:34 -0700 Subject: [PATCH 04/49] add (shimmed) std support for armv7a-vex-v5 --- library/std/Cargo.toml | 3 +++ library/std/build.rs | 1 + library/std/src/sys/pal/mod.rs | 3 +++ library/std/src/sys/pal/vexos/mod.rs | 31 ++++++++++++++++++++++++++++ src/bootstrap/src/core/sanity.rs | 1 + src/bootstrap/src/lib.rs | 2 +- 6 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 library/std/src/sys/pal/vexos/mod.rs diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index f2669326065d5..93e527c316d00 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -90,6 +90,9 @@ wasi = { version = "0.11.0", features = [ r-efi = { version = "4.5.0", features = ['rustc-dep-of-std'] } r-efi-alloc = { version = "1.0.0", features = ['rustc-dep-of-std'] } +[target.'cfg(target_os = "vexos")'.dependencies] +vex-sdk = { version = "0.16.1", features = ['rustc-dep-of-std'] } + [features] backtrace = [ 'addr2line/rustc-dep-of-std', diff --git a/library/std/build.rs b/library/std/build.rs index 032326556bd5b..8eef23d2747a0 100644 --- a/library/std/build.rs +++ b/library/std/build.rs @@ -56,6 +56,7 @@ fn main() { || target_os == "zkvm" || target_os == "rtems" || target_os == "nuttx" + || target_os == "vexos" // See src/bootstrap/src/core/build_steps/synthetic_targets.rs || env::var("RUSTC_BOOTSTRAP_SYNTHETIC_TARGET").is_ok() diff --git a/library/std/src/sys/pal/mod.rs b/library/std/src/sys/pal/mod.rs index 9be018c8a5312..45c692c805c80 100644 --- a/library/std/src/sys/pal/mod.rs +++ b/library/std/src/sys/pal/mod.rs @@ -61,6 +61,9 @@ cfg_if::cfg_if! { } else if #[cfg(target_os = "zkvm")] { mod zkvm; pub use self::zkvm::*; + } else if #[cfg(target_os = "vexos")] { + mod vexos; + pub use self::vexos::*; } else { mod unsupported; pub use self::unsupported::*; diff --git a/library/std/src/sys/pal/vexos/mod.rs b/library/std/src/sys/pal/vexos/mod.rs new file mode 100644 index 0000000000000..d57afead5606b --- /dev/null +++ b/library/std/src/sys/pal/vexos/mod.rs @@ -0,0 +1,31 @@ +#[path = "../unsupported/alloc.rs"] +pub mod alloc; +#[path = "../unsupported/args.rs"] +pub mod args; +#[path = "../unsupported/env.rs"] +pub mod env; +#[path = "../unsupported/fs.rs"] +pub mod fs; +#[path = "../unsupported/io.rs"] +pub mod io; +#[path = "../unsupported/net.rs"] +pub mod net; +#[path = "../unsupported/os.rs"] +pub mod os; +#[path = "../unsupported/pipe.rs"] +pub mod pipe; +#[path = "../unsupported/process.rs"] +pub mod process; +#[path = "../unsupported/stdio.rs"] +pub mod stdio; +#[path = "../unsupported/thread.rs"] +pub mod thread; +#[path = "../unsupported/thread_local_key.rs"] +pub mod thread_local_key; +#[path = "../unsupported/time.rs"] +pub mod time; + +#[path = "../unsupported/common.rs"] +#[deny(unsafe_op_in_unsafe_fn)] +mod common; +pub use common::*; diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index 6fbdd76ed5b6c..f2c13e7af1c84 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -33,6 +33,7 @@ pub struct Finder { // // Targets can be removed from this list once they are present in the stage0 compiler (usually by updating the beta compiler of the bootstrap). const STAGE0_MISSING_TARGETS: &[&str] = &[ + "armv7a-vex-v5", // just a dummy comment so the list doesn't get onelined "armv7-rtems-eabihf", "riscv32e-unknown-none-elf", diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index ecb219ea33fd6..7c91af9e8789a 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -665,7 +665,7 @@ impl Build { } // Generate memcpy, etc. FIXME: Remove this once compiler-builtins // automatically detects this target. - if target.contains("zkvm") { + if target.contains("zkvm") || target.contains("vex") { features.insert("compiler-builtins-mem"); } From c165bed1fa2311894adc1ac897c2f8894ee96b06 Mon Sep 17 00:00:00 2001 From: Max Niederman Date: Tue, 28 May 2024 11:39:16 -0700 Subject: [PATCH 05/49] add panic, stdio, and alloc support to armv7a-vex-v5 --- .../targets/armv7a_vex_v5_linker_script.ld | 2 +- library/panic_abort/src/lib.rs | 1 + library/std/Cargo.toml | 2 +- library/std/src/sys/pal/vexos/alloc.rs | 97 +++++++++++++++++++ library/std/src/sys/pal/vexos/mod.rs | 17 +++- library/std/src/sys/pal/vexos/stdio.rs | 86 ++++++++++++++++ 6 files changed, 201 insertions(+), 4 deletions(-) create mode 100644 library/std/src/sys/pal/vexos/alloc.rs create mode 100644 library/std/src/sys/pal/vexos/stdio.rs diff --git a/compiler/rustc_target/src/spec/targets/armv7a_vex_v5_linker_script.ld b/compiler/rustc_target/src/spec/targets/armv7a_vex_v5_linker_script.ld index f9436907c7feb..c62b872fd84c4 100644 --- a/compiler/rustc_target/src/spec/targets/armv7a_vex_v5_linker_script.ld +++ b/compiler/rustc_target/src/spec/targets/armv7a_vex_v5_linker_script.ld @@ -18,7 +18,7 @@ I'm not sure why subtracting anything is necessary, but it fixes memory permissi __heap_end = __cold_end - __stack_length - 0x1000; SECTIONS { - .code_signature { + .code_signature : { KEEP(*(.code_signature)) . = __cold_start + 0x20; } > COLD diff --git a/library/panic_abort/src/lib.rs b/library/panic_abort/src/lib.rs index dc2b42bb90ae8..6e2b29a41a995 100644 --- a/library/panic_abort/src/lib.rs +++ b/library/panic_abort/src/lib.rs @@ -51,6 +51,7 @@ pub unsafe fn __rust_start_panic(_payload: &mut dyn PanicPayload) -> u32 { all(target_vendor = "fortanix", target_env = "sgx"), target_os = "xous", target_os = "uefi", + target_os = "vexos", ))] { unsafe fn abort() -> ! { // call std::sys::abort_internal diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 93e527c316d00..033dcffefc95e 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -68,7 +68,7 @@ path = "../windows_targets" rand = { version = "0.8.5", default-features = false, features = ["alloc"] } rand_xorshift = "0.3.0" -[target.'cfg(any(all(target_family = "wasm", target_os = "unknown"), target_os = "xous", all(target_vendor = "fortanix", target_env = "sgx")))'.dependencies] +[target.'cfg(any(all(target_family = "wasm", target_os = "unknown"), target_os = "vexos", target_os = "xous", all(target_vendor = "fortanix", target_env = "sgx")))'.dependencies] dlmalloc = { version = "0.2.4", features = ['rustc-dep-of-std'] } [target.x86_64-fortanix-unknown-sgx.dependencies] diff --git a/library/std/src/sys/pal/vexos/alloc.rs b/library/std/src/sys/pal/vexos/alloc.rs new file mode 100644 index 0000000000000..8ff93fe03335e --- /dev/null +++ b/library/std/src/sys/pal/vexos/alloc.rs @@ -0,0 +1,97 @@ +use crate::{ + alloc::{GlobalAlloc, Layout, System}, + ptr, + sync::atomic::{AtomicBool, Ordering}, +}; + +static mut DLMALLOC: dlmalloc::Dlmalloc = dlmalloc::Dlmalloc::new_with_allocator(Vexos); + +extern "C" { + static mut __heap_start: u8; + static mut __heap_end: u8; +} + +struct Vexos; + +unsafe impl dlmalloc::Allocator for Vexos { + /// Allocs system resources + fn alloc(&self, _size: usize) -> (*mut u8, usize, u32) { + static INIT: AtomicBool = AtomicBool::new(false); + + if !INIT.swap(true, Ordering::Relaxed) { + unsafe { + ( + ptr::addr_of_mut!(__heap_start).cast(), + ptr::addr_of!(__heap_end).byte_offset_from(ptr::addr_of!(__heap_start)) as _, + 0, + ) + } + } else { + (ptr::null_mut(), 0, 0) + } + } + + fn remap(&self, _ptr: *mut u8, _oldsize: usize, _newsize: usize, _can_move: bool) -> *mut u8 { + ptr::null_mut() + } + + fn free_part(&self, _ptr: *mut u8, _oldsize: usize, _newsize: usize) -> bool { + false + } + + fn free(&self, _ptr: *mut u8, _size: usize) -> bool { + return false; + } + + fn can_release_part(&self, _flags: u32) -> bool { + false + } + + fn allocates_zeros(&self) -> bool { + false + } + + fn page_size(&self) -> usize { + 0x1000 + } +} + +#[stable(feature = "alloc_system_type", since = "1.28.0")] +unsafe impl GlobalAlloc for System { + #[inline] + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + // SAFETY: DLMALLOC access is guaranteed to be safe because the lock gives us unique and non-reentrant access. + // Calling malloc() is safe because preconditions on this function match the trait method preconditions. + let _lock = lock::lock(); + unsafe { DLMALLOC.malloc(layout.size(), layout.align()) } + } + + #[inline] + unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { + // SAFETY: DLMALLOC access is guaranteed to be safe because the lock gives us unique and non-reentrant access. + // Calling calloc() is safe because preconditions on this function match the trait method preconditions. + let _lock = lock::lock(); + unsafe { DLMALLOC.calloc(layout.size(), layout.align()) } + } + + #[inline] + unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { + // SAFETY: DLMALLOC access is guaranteed to be safe because the lock gives us unique and non-reentrant access. + // Calling free() is safe because preconditions on this function match the trait method preconditions. + let _lock = lock::lock(); + unsafe { DLMALLOC.free(ptr, layout.size(), layout.align()) } + } + + #[inline] + unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { + // SAFETY: DLMALLOC access is guaranteed to be safe because the lock gives us unique and non-reentrant access. + // Calling realloc() is safe because preconditions on this function match the trait method preconditions. + let _lock = lock::lock(); + unsafe { DLMALLOC.realloc(ptr, layout.size(), layout.align(), new_size) } + } +} + +mod lock { + #[inline] + pub fn lock() {} // we don't have threads, which makes this real easy +} diff --git a/library/std/src/sys/pal/vexos/mod.rs b/library/std/src/sys/pal/vexos/mod.rs index d57afead5606b..26423c68a8ca2 100644 --- a/library/std/src/sys/pal/vexos/mod.rs +++ b/library/std/src/sys/pal/vexos/mod.rs @@ -1,4 +1,3 @@ -#[path = "../unsupported/alloc.rs"] pub mod alloc; #[path = "../unsupported/args.rs"] pub mod args; @@ -16,7 +15,6 @@ pub mod os; pub mod pipe; #[path = "../unsupported/process.rs"] pub mod process; -#[path = "../unsupported/stdio.rs"] pub mod stdio; #[path = "../unsupported/thread.rs"] pub mod thread; @@ -29,3 +27,18 @@ pub mod time; #[deny(unsafe_op_in_unsafe_fn)] mod common; pub use common::*; + +// This function is needed by the panic runtime. The symbol is named in +// pre-link args for the target specification, so keep that in sync. +#[cfg(not(test))] +#[no_mangle] +// NB. used by both libunwind and libpanic_abort +pub extern "C" fn __rust_abort() -> ! { + unsafe { + vex_sdk::vexSystemExitRequest(); + } + + loop { + crate::hint::spin_loop() + } +} diff --git a/library/std/src/sys/pal/vexos/stdio.rs b/library/std/src/sys/pal/vexos/stdio.rs new file mode 100644 index 0000000000000..eb09b4a5c51d3 --- /dev/null +++ b/library/std/src/sys/pal/vexos/stdio.rs @@ -0,0 +1,86 @@ +use crate::io; + +pub struct Stdin(()); +pub struct Stdout(()); +pub struct Stderr(()); + +const STDIO_CHANNEL: u32 = 1; + +impl Stdin { + pub const fn new() -> Stdin { + Stdin(()) + } +} + +impl io::Read for Stdin { + fn read(&mut self, mut buf: &mut [u8]) -> io::Result { + let mut written = 0; + + while let Some((out_byte, new_buf)) = buf.split_first_mut() { + buf = new_buf; + + let byte = unsafe { vex_sdk::vexSerialReadChar(STDIO_CHANNEL) }; + if byte < 0 { + break; + } + + *out_byte = byte as u8; + written += 1; + } + + Ok(written) + } +} + +impl Stdout { + pub const fn new() -> Stdout { + Stdout(()) + } +} + +impl io::Write for Stdout { + fn write(&mut self, buf: &[u8]) -> io::Result { + let written = + unsafe { vex_sdk::vexSerialWriteBuffer(STDIO_CHANNEL, buf.as_ptr(), buf.len() as u32) }; + + if written < 0 { + return Err(io::Error::new(io::ErrorKind::Other, "Internal write error occurred.")); + } + + Ok(written as usize) + } + + fn flush(&mut self) -> io::Result<()> { + unsafe { + vex_sdk::vexTasksRun(); + } + + Ok(()) + } +} + +impl Stderr { + pub const fn new() -> Stderr { + Stderr(()) + } +} + +impl io::Write for Stderr { + fn write(&mut self, buf: &[u8]) -> io::Result { + Ok(buf.len()) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +pub const STDIN_BUF_SIZE: usize = 0; + +pub fn is_ebadf(_err: &io::Error) -> bool { + true +} + +pub fn panic_output() -> Option { + Some(Stdout::new()) +} From 7919692c2494e7ea9893f252d1ae33b1cca5fb57 Mon Sep 17 00:00:00 2001 From: Max Niederman Date: Wed, 29 May 2024 23:19:23 -0700 Subject: [PATCH 06/49] fix linker script and call main --- .../targets/armv7a_vex_v5_linker_script.ld | 54 ++++++++++--------- library/std/Cargo.toml | 2 +- library/std/src/sys/pal/vexos/mod.rs | 49 +++++++++++++++-- 3 files changed, 74 insertions(+), 31 deletions(-) diff --git a/compiler/rustc_target/src/spec/targets/armv7a_vex_v5_linker_script.ld b/compiler/rustc_target/src/spec/targets/armv7a_vex_v5_linker_script.ld index c62b872fd84c4..ccdd6110e2eb6 100644 --- a/compiler/rustc_target/src/spec/targets/armv7a_vex_v5_linker_script.ld +++ b/compiler/rustc_target/src/spec/targets/armv7a_vex_v5_linker_script.ld @@ -2,51 +2,53 @@ OUTPUT_FORMAT("elf32-littlearm") ENTRY(_start) -__cold_start = 0x03800000; -__cold_length = 0x04800000; -__cold_end = __cold_start + __cold_length; +__user_ram_start = 0x03800000; +__user_ram_length = 0x04800000; +__user_ram_end = __user_ram_start + __user_ram_length; MEMORY { - COLD : ORIGIN = __cold_start, LENGTH = __cold_length + USER_RAM : ORIGIN = __user_ram_start, LENGTH = __user_ram_length } __stack_length = 0x400000; -/* -I'm not sure why subtracting anything is necessary, but it fixes memory permission errors. -0x1000 is an arbitrary number that works. -*/ -__heap_end = __cold_end - __stack_length - 0x1000; +__heap_end = __user_ram_end - __stack_length - 64; SECTIONS { - .code_signature : { + .code_signature __user_ram_start : { KEEP(*(.code_signature)) - . = __cold_start + 0x20; - } > COLD - .text : { - KEEP(*(.text.boot)) + } > USER_RAM = 0 + + .text __user_ram_start + 0x20 : { + *(.text.boot) *(.text .text.*) - } > COLD + } > USER_RAM + .rodata : { - __rodata_start = .; - *(.rodata1 .rodata1.*) - __rodata_end = .; - } > COLD + *(.rodata .rodata.*) + } > USER_RAM + .data : { *(.data .data.*) - *(.data1 .data1.*) - } > COLD + } > USER_RAM + .bss : { __bss_start = .; *(.bss .bss.*) __bss_end = .; - } > COLD + } > USER_RAM + .heap (NOLOAD) : ALIGN(4) { __heap_start = .; . = __heap_end; - } > COLD + } > USER_RAM + .stack (NOLOAD) : ALIGN(8) { - __stack_end = .; + __stack_bottom = .; . += __stack_length; - __stack_start = .; - } > COLD + __stack_top = .; + } > USER_RAM + + /DISCARD/ : { + *(.ARM.exidx) + } } diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 033dcffefc95e..c87834eae6daf 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -91,7 +91,7 @@ r-efi = { version = "4.5.0", features = ['rustc-dep-of-std'] } r-efi-alloc = { version = "1.0.0", features = ['rustc-dep-of-std'] } [target.'cfg(target_os = "vexos")'.dependencies] -vex-sdk = { version = "0.16.1", features = ['rustc-dep-of-std'] } +vex-sdk = { version = "0.17.0", features = ['rustc-dep-of-std'] } [features] backtrace = [ diff --git a/library/std/src/sys/pal/vexos/mod.rs b/library/std/src/sys/pal/vexos/mod.rs index 26423c68a8ca2..41354a20603c2 100644 --- a/library/std/src/sys/pal/vexos/mod.rs +++ b/library/std/src/sys/pal/vexos/mod.rs @@ -15,6 +15,7 @@ pub mod os; pub mod pipe; #[path = "../unsupported/process.rs"] pub mod process; +#[path = "../unsupported/stdio.rs"] pub mod stdio; #[path = "../unsupported/thread.rs"] pub mod thread; @@ -23,10 +24,22 @@ pub mod thread_local_key; #[path = "../unsupported/time.rs"] pub mod time; -#[path = "../unsupported/common.rs"] -#[deny(unsafe_op_in_unsafe_fn)] -mod common; -pub use common::*; +use crate::arch::asm; + +#[cfg(not(test))] +#[no_mangle] +#[link_section = ".text.boot"] +pub unsafe extern "C" fn _start() -> ! { + extern "C" { + fn main() -> i32; + } + + asm!("ldr sp, =__stack_top", options(nostack)); + + main(); + + abort_internal() +} // This function is needed by the panic runtime. The symbol is named in // pre-link args for the target specification, so keep that in sync. @@ -34,6 +47,30 @@ pub use common::*; #[no_mangle] // NB. used by both libunwind and libpanic_abort pub extern "C" fn __rust_abort() -> ! { + abort_internal() +} + +pub unsafe fn init(_argc: isize, _argv: *const *const u8, _sigpipe: u8) {} + +pub unsafe fn cleanup() {} + +pub fn unsupported() -> crate::io::Result { + Err(unsupported_err()) +} + +pub fn unsupported_err() -> crate::io::Error { + crate::io::Error::UNSUPPORTED_PLATFORM +} + +pub fn is_interrupted(_code: i32) -> bool { + false +} + +pub fn decode_error_kind(_code: i32) -> crate::io::ErrorKind { + crate::io::ErrorKind::Uncategorized +} + +pub fn abort_internal() -> ! { unsafe { vex_sdk::vexSystemExitRequest(); } @@ -42,3 +79,7 @@ pub extern "C" fn __rust_abort() -> ! { crate::hint::spin_loop() } } + +pub fn hashmap_random_keys() -> (u64, u64) { + (1, 2) +} From dcfa3bd640156ea51ebf37962c1389c4b28b1f9d Mon Sep 17 00:00:00 2001 From: Max Niederman Date: Wed, 17 Jul 2024 16:16:47 -0700 Subject: [PATCH 07/49] zero out bss section in _start --- library/std/src/sys/pal/vexos/mod.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/pal/vexos/mod.rs b/library/std/src/sys/pal/vexos/mod.rs index 41354a20603c2..c077871671c61 100644 --- a/library/std/src/sys/pal/vexos/mod.rs +++ b/library/std/src/sys/pal/vexos/mod.rs @@ -24,18 +24,29 @@ pub mod thread_local_key; #[path = "../unsupported/time.rs"] pub mod time; -use crate::arch::asm; +use crate::{arch::asm, ptr::{self, addr_of_mut}}; #[cfg(not(test))] #[no_mangle] #[link_section = ".text.boot"] pub unsafe extern "C" fn _start() -> ! { extern "C" { + static mut __bss_start: u8; + static mut __bss_end: u8; + fn main() -> i32; } asm!("ldr sp, =__stack_top", options(nostack)); + ptr::slice_from_raw_parts_mut( + addr_of_mut!(__bss_start), + addr_of_mut!(__bss_end).offset_from(addr_of_mut!(__bss_start)) as usize, + ) + .as_mut() + .unwrap_unchecked() + .fill(0); + main(); abort_internal() From 8095ebd5a32cfd5130a494238cdce0bf8eaeb2bd Mon Sep 17 00:00:00 2001 From: Max Niederman Date: Wed, 17 Jul 2024 16:29:44 -0700 Subject: [PATCH 08/49] use static TLS implementation on vexos --- library/std/src/sys/thread_local/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/std/src/sys/thread_local/mod.rs b/library/std/src/sys/thread_local/mod.rs index 31d3b43906004..378296a5260c8 100644 --- a/library/std/src/sys/thread_local/mod.rs +++ b/library/std/src/sys/thread_local/mod.rs @@ -28,6 +28,7 @@ cfg_if::cfg_if! { all(target_family = "wasm", not(target_feature = "atomics")), target_os = "uefi", target_os = "zkvm", + target_os = "vexos", ))] { mod statik; pub use statik::{EagerStorage, LazyStorage, thread_local_inner}; From 1780a6af1f89f5a30fb401fa1c7033ffa9c74c3e Mon Sep 17 00:00:00 2001 From: Max Niederman Date: Wed, 17 Jul 2024 16:30:45 -0700 Subject: [PATCH 09/49] make minor improvements to linker script --- .../src/spec/targets/armv7a_vex_v5_linker_script.ld | 8 +++++++- library/std/src/sys/pal/vexos/alloc.rs | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_target/src/spec/targets/armv7a_vex_v5_linker_script.ld b/compiler/rustc_target/src/spec/targets/armv7a_vex_v5_linker_script.ld index ccdd6110e2eb6..a3d45b0a660c0 100644 --- a/compiler/rustc_target/src/spec/targets/armv7a_vex_v5_linker_script.ld +++ b/compiler/rustc_target/src/spec/targets/armv7a_vex_v5_linker_script.ld @@ -11,7 +11,11 @@ MEMORY { } __stack_length = 0x400000; -__heap_end = __user_ram_end - __stack_length - 64; +/* +It's currently unclear why subtracting anything is necessary, but it fixes memory permission errors. +0x100 is an arbitrary number that works. +*/ +__heap_end = __user_ram_end - __stack_length - 0x1000; SECTIONS { .code_signature __user_ram_start : { @@ -25,10 +29,12 @@ SECTIONS { .rodata : { *(.rodata .rodata.*) + *(.rodata1 .rodata1.*) } > USER_RAM .data : { *(.data .data.*) + *(.data1 .data1.*) } > USER_RAM .bss : { diff --git a/library/std/src/sys/pal/vexos/alloc.rs b/library/std/src/sys/pal/vexos/alloc.rs index 8ff93fe03335e..f760ebef770f9 100644 --- a/library/std/src/sys/pal/vexos/alloc.rs +++ b/library/std/src/sys/pal/vexos/alloc.rs @@ -40,7 +40,7 @@ unsafe impl dlmalloc::Allocator for Vexos { } fn free(&self, _ptr: *mut u8, _size: usize) -> bool { - return false; + false } fn can_release_part(&self, _flags: u32) -> bool { From 31c0e194a35bf2937d5bbdc9f533e4a731511784 Mon Sep 17 00:00:00 2001 From: Max Niederman Date: Wed, 17 Jul 2024 17:36:53 -0700 Subject: [PATCH 10/49] enable stdio and fix stdout flushing --- library/std/src/sys/pal/vexos/mod.rs | 5 +++-- library/std/src/sys/pal/vexos/stdio.rs | 7 +++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/library/std/src/sys/pal/vexos/mod.rs b/library/std/src/sys/pal/vexos/mod.rs index c077871671c61..e0466b90b8a6f 100644 --- a/library/std/src/sys/pal/vexos/mod.rs +++ b/library/std/src/sys/pal/vexos/mod.rs @@ -15,7 +15,6 @@ pub mod os; pub mod pipe; #[path = "../unsupported/process.rs"] pub mod process; -#[path = "../unsupported/stdio.rs"] pub mod stdio; #[path = "../unsupported/thread.rs"] pub mod thread; @@ -63,7 +62,9 @@ pub extern "C" fn __rust_abort() -> ! { pub unsafe fn init(_argc: isize, _argv: *const *const u8, _sigpipe: u8) {} -pub unsafe fn cleanup() {} +pub unsafe fn cleanup() { + stdio:: +} pub fn unsupported() -> crate::io::Result { Err(unsupported_err()) diff --git a/library/std/src/sys/pal/vexos/stdio.rs b/library/std/src/sys/pal/vexos/stdio.rs index eb09b4a5c51d3..998592e762434 100644 --- a/library/std/src/sys/pal/vexos/stdio.rs +++ b/library/std/src/sys/pal/vexos/stdio.rs @@ -52,7 +52,9 @@ impl io::Write for Stdout { fn flush(&mut self) -> io::Result<()> { unsafe { - vex_sdk::vexTasksRun(); + while (vex_sdk::vexSerialWriteFree(STDIO_CHANNEL) as usize) != STDOUT_BUF_SIZE { + vex_sdk::vexTasksRun(); + } } Ok(()) @@ -75,7 +77,8 @@ impl io::Write for Stderr { } } -pub const STDIN_BUF_SIZE: usize = 0; +pub const STDIN_BUF_SIZE: usize = 4096; +const STDOUT_BUF_SIZE: usize = 2048; pub fn is_ebadf(_err: &io::Error) -> bool { true From 9b51015c706e1a3dbc2359fd961e4c0f6c2a400a Mon Sep 17 00:00:00 2001 From: Gavin-Niederman Date: Wed, 17 Jul 2024 17:59:01 -0700 Subject: [PATCH 11/49] add: `Instant` implementation --- library/std/src/sys/pal/vexos/mod.rs | 1 - library/std/src/sys/pal/vexos/time.rs | 46 +++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 library/std/src/sys/pal/vexos/time.rs diff --git a/library/std/src/sys/pal/vexos/mod.rs b/library/std/src/sys/pal/vexos/mod.rs index e0466b90b8a6f..432e041d3cfa7 100644 --- a/library/std/src/sys/pal/vexos/mod.rs +++ b/library/std/src/sys/pal/vexos/mod.rs @@ -20,7 +20,6 @@ pub mod stdio; pub mod thread; #[path = "../unsupported/thread_local_key.rs"] pub mod thread_local_key; -#[path = "../unsupported/time.rs"] pub mod time; use crate::{arch::asm, ptr::{self, addr_of_mut}}; diff --git a/library/std/src/sys/pal/vexos/time.rs b/library/std/src/sys/pal/vexos/time.rs new file mode 100644 index 0000000000000..94699d64d2307 --- /dev/null +++ b/library/std/src/sys/pal/vexos/time.rs @@ -0,0 +1,46 @@ +use crate::time::Duration; + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] +pub struct Instant(Duration); + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] +pub struct SystemTime(Duration); + +pub const UNIX_EPOCH: SystemTime = SystemTime(Duration::from_secs(0)); + +impl Instant { + pub fn now() -> Instant { + let micros = unsafe { vex_sdk::vexSystemHighResTimeGet() }; + Self(Duration::from_micros(micros)) + } + + pub fn checked_sub_instant(&self, other: &Instant) -> Option { + self.0.checked_sub(other.0) + } + + pub fn checked_add_duration(&self, other: &Duration) -> Option { + Some(Instant(self.0.checked_add(*other)?)) + } + + pub fn checked_sub_duration(&self, other: &Duration) -> Option { + Some(Instant(self.0.checked_sub(*other)?)) + } +} + +impl SystemTime { + pub fn now() -> SystemTime { + panic!("time not implemented on this platform") + } + + pub fn sub_time(&self, other: &SystemTime) -> Result { + self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0) + } + + pub fn checked_add_duration(&self, other: &Duration) -> Option { + Some(SystemTime(self.0.checked_add(*other)?)) + } + + pub fn checked_sub_duration(&self, other: &Duration) -> Option { + Some(SystemTime(self.0.checked_sub(*other)?)) + } +} From b1cbee0bcb66751f3fabc1eaaaf6f936fd220350 Mon Sep 17 00:00:00 2001 From: Max Niederman Date: Wed, 17 Jul 2024 18:06:29 -0700 Subject: [PATCH 12/49] remove broken cleanup --- library/std/src/sys/pal/vexos/mod.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/library/std/src/sys/pal/vexos/mod.rs b/library/std/src/sys/pal/vexos/mod.rs index 432e041d3cfa7..9189ac2a47925 100644 --- a/library/std/src/sys/pal/vexos/mod.rs +++ b/library/std/src/sys/pal/vexos/mod.rs @@ -61,9 +61,7 @@ pub extern "C" fn __rust_abort() -> ! { pub unsafe fn init(_argc: isize, _argv: *const *const u8, _sigpipe: u8) {} -pub unsafe fn cleanup() { - stdio:: -} +pub unsafe fn cleanup() {} pub fn unsupported() -> crate::io::Result { Err(unsupported_err()) From 651a267c6b68ad4f0515e706d2e406297a6a70cf Mon Sep 17 00:00:00 2001 From: Tropical <42101043+Tropix126@users.noreply.github.com> Date: Wed, 17 Jul 2024 22:56:53 -0400 Subject: [PATCH 13/49] fix `.code_signature` section error --- .../src/spec/targets/armv7a_vex_v5_linker_script.ld | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_target/src/spec/targets/armv7a_vex_v5_linker_script.ld b/compiler/rustc_target/src/spec/targets/armv7a_vex_v5_linker_script.ld index a3d45b0a660c0..8ff88f24adf38 100644 --- a/compiler/rustc_target/src/spec/targets/armv7a_vex_v5_linker_script.ld +++ b/compiler/rustc_target/src/spec/targets/armv7a_vex_v5_linker_script.ld @@ -15,11 +15,13 @@ __stack_length = 0x400000; It's currently unclear why subtracting anything is necessary, but it fixes memory permission errors. 0x100 is an arbitrary number that works. */ -__heap_end = __user_ram_end - __stack_length - 0x1000; +__heap_end = __user_ram_end - __stack_length - 0x100; SECTIONS { .code_signature __user_ram_start : { + __code_signature_start = .; KEEP(*(.code_signature)) + . = __code_signature_start + 0x20; } > USER_RAM = 0 .text __user_ram_start + 0x20 : { From 48155eb26358c87a32f791c40020f1349abe230b Mon Sep 17 00:00:00 2001 From: Tropical <42101043+Tropix126@users.noreply.github.com> Date: Wed, 17 Jul 2024 23:07:27 -0400 Subject: [PATCH 14/49] move `.code_signature` section into `.text` --- .../targets/armv7a_vex_v5_linker_script.ld | 18 +++++++----------- library/std/src/sys/pal/vexos/mod.rs | 2 +- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_target/src/spec/targets/armv7a_vex_v5_linker_script.ld b/compiler/rustc_target/src/spec/targets/armv7a_vex_v5_linker_script.ld index 8ff88f24adf38..37fc390401ead 100644 --- a/compiler/rustc_target/src/spec/targets/armv7a_vex_v5_linker_script.ld +++ b/compiler/rustc_target/src/spec/targets/armv7a_vex_v5_linker_script.ld @@ -18,19 +18,15 @@ It's currently unclear why subtracting anything is necessary, but it fixes memor __heap_end = __user_ram_end - __stack_length - 0x100; SECTIONS { - .code_signature __user_ram_start : { - __code_signature_start = .; + .text : { + __text_start = .; KEEP(*(.code_signature)) - . = __code_signature_start + 0x20; - } > USER_RAM = 0 - - .text __user_ram_start + 0x20 : { - *(.text.boot) + . = __text_start + 0x20; + *(.boot) *(.text .text.*) - } > USER_RAM + } > USER_RAM = 0 - .rodata : { - *(.rodata .rodata.*) + .rodata1 : { *(.rodata1 .rodata1.*) } > USER_RAM @@ -59,4 +55,4 @@ SECTIONS { /DISCARD/ : { *(.ARM.exidx) } -} +} \ No newline at end of file diff --git a/library/std/src/sys/pal/vexos/mod.rs b/library/std/src/sys/pal/vexos/mod.rs index 9189ac2a47925..cb80cf675a09c 100644 --- a/library/std/src/sys/pal/vexos/mod.rs +++ b/library/std/src/sys/pal/vexos/mod.rs @@ -26,7 +26,7 @@ use crate::{arch::asm, ptr::{self, addr_of_mut}}; #[cfg(not(test))] #[no_mangle] -#[link_section = ".text.boot"] +#[link_section = ".boot"] pub unsafe extern "C" fn _start() -> ! { extern "C" { static mut __bss_start: u8; From e1b69234d6d6e5f6575b5406a0ea1ad6935888b1 Mon Sep 17 00:00:00 2001 From: Tropical <42101043+Tropix126@users.noreply.github.com> Date: Thu, 18 Jul 2024 00:13:16 -0400 Subject: [PATCH 15/49] adjust `armv7a-vex-v5` target features for more aggressive hardware optimization --- compiler/rustc_target/src/spec/targets/armv7a_vex_v5.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_target/src/spec/targets/armv7a_vex_v5.rs b/compiler/rustc_target/src/spec/targets/armv7a_vex_v5.rs index bac7747e7d80e..bc117b64c2301 100644 --- a/compiler/rustc_target/src/spec/targets/armv7a_vex_v5.rs +++ b/compiler/rustc_target/src/spec/targets/armv7a_vex_v5.rs @@ -15,11 +15,12 @@ pub(crate) fn target() -> Target { data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), arch: "arm".into(), options: TargetOptions { - abi: "eabi".into(), + cpu: "cortex-a9".into(), + abi: "eabihf".into(), linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), linker: Some("rust-lld".into()), link_script: Some(LINK_SCRIPT.into()), - features: "+v7,+thumb2,+soft-float,-neon,+strict-align".into(), + features: "+v7,+thumb2,+vfp3,+neon".into(), relocation_model: RelocModel::Static, disable_redzone: true, max_atomic_width: Some(64), From 3295fed18c50ac70b7c8d588e7584e34c06941d0 Mon Sep 17 00:00:00 2001 From: Tropical <42101043+Tropix126@users.noreply.github.com> Date: Thu, 18 Jul 2024 00:31:41 -0400 Subject: [PATCH 16/49] switch `llvm_target` to use ARM hard-float abi --- compiler/rustc_target/src/spec/targets/armv7a_vex_v5.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_target/src/spec/targets/armv7a_vex_v5.rs b/compiler/rustc_target/src/spec/targets/armv7a_vex_v5.rs index bc117b64c2301..a6a6f542e3103 100644 --- a/compiler/rustc_target/src/spec/targets/armv7a_vex_v5.rs +++ b/compiler/rustc_target/src/spec/targets/armv7a_vex_v5.rs @@ -4,7 +4,7 @@ const LINK_SCRIPT: &str = include_str!("./armv7a_vex_v5_linker_script.ld"); pub(crate) fn target() -> Target { Target { - llvm_target: "armv7a-none-eabi".into(), + llvm_target: "armv7a-none-eabihf".into(), metadata: crate::spec::TargetMetadata { description: None, tier: None, From bffb60d786011196a2973f9f56d8cf01ede8d284 Mon Sep 17 00:00:00 2001 From: Tropical <42101043+Tropix126@users.noreply.github.com> Date: Thu, 18 Jul 2024 00:31:57 -0400 Subject: [PATCH 17/49] add `env` implementation for `vexos` PAL --- library/std/src/sys/pal/vexos/env.rs | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 library/std/src/sys/pal/vexos/env.rs diff --git a/library/std/src/sys/pal/vexos/env.rs b/library/std/src/sys/pal/vexos/env.rs new file mode 100644 index 0000000000000..381658cfd342e --- /dev/null +++ b/library/std/src/sys/pal/vexos/env.rs @@ -0,0 +1,9 @@ +pub mod os { + pub const FAMILY: &str = ""; + pub const OS: &str = "vexos"; + pub const DLL_PREFIX: &str = ""; + pub const DLL_SUFFIX: &str = ""; + pub const DLL_EXTENSION: &str = ""; + pub const EXE_SUFFIX: &str = ".bin"; + pub const EXE_EXTENSION: &str = "bin"; +} From 4981de1c748698677f5e5826c08bd11788199523 Mon Sep 17 00:00:00 2001 From: Gavin-Niederman Date: Wed, 17 Jul 2024 22:51:28 -0700 Subject: [PATCH 18/49] feat: experimental fs support --- library/std/src/sys/pal/vexos/fs.rs | 325 +++++++++++++++++++++++++++ library/std/src/sys/pal/vexos/mod.rs | 2 - 2 files changed, 325 insertions(+), 2 deletions(-) create mode 100644 library/std/src/sys/pal/vexos/fs.rs diff --git a/library/std/src/sys/pal/vexos/fs.rs b/library/std/src/sys/pal/vexos/fs.rs new file mode 100644 index 0000000000000..005dc2645990a --- /dev/null +++ b/library/std/src/sys/pal/vexos/fs.rs @@ -0,0 +1,325 @@ +use crate::ffi::{CString, OsString}; +use crate::fmt; +use crate::hash::Hash; +use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, SeekFrom}; +use crate::path::{Path, PathBuf}; +use crate::sys::time::SystemTime; +use crate::sys::unsupported; + +struct Fd(*mut vex_sdk::FIL); + +pub struct File(Fd); + +//TODO: We may be able to get some of this info +#[derive(Clone)] +pub struct FileAttr; + +pub struct ReadDir(!); + +pub struct DirEntry(!); + +#[derive(Clone, Debug)] +pub struct OpenOptions { + read: bool, + write: bool, + append: bool, +} + +#[derive(Copy, Clone, Debug, Default)] +pub struct FileTimes {} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct FilePermissions; + +#[derive(Clone, Debug, Copy, PartialEq, Eq, Hash)] +pub struct FileType { + is_dir: bool, +} + +#[derive(Debug)] +pub struct DirBuilder {} + +impl FileAttr { + pub fn size(&self) -> u64 { + todo!() + } + + pub fn perm(&self) -> FilePermissions { + todo!() + } + + pub fn file_type(&self) -> FileType { + todo!() + } + + pub fn modified(&self) -> io::Result { + todo!() + } + + pub fn accessed(&self) -> io::Result { + todo!() + } + + pub fn created(&self) -> io::Result { + todo!() + } +} + +impl FilePermissions { + pub fn readonly(&self) -> bool { + false + } + + pub fn set_readonly(&mut self, _readonly: bool) { + panic!("Perimissions do not exist") + } +} + +impl FileTimes { + pub fn set_accessed(&mut self, _t: SystemTime) {} + pub fn set_modified(&mut self, _t: SystemTime) {} +} + +impl FileType { + pub fn is_dir(&self) -> bool { + self.is_dir + } + + pub fn is_file(&self) -> bool { + !self.is_dir + } + + pub fn is_symlink(&self) -> bool { + false + } +} + +impl fmt::Debug for ReadDir { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0 + } +} + +impl Iterator for ReadDir { + type Item = io::Result; + + fn next(&mut self) -> Option> { + self.0 + } +} + +impl DirEntry { + pub fn path(&self) -> PathBuf { + self.0 + } + + pub fn file_name(&self) -> OsString { + self.0 + } + + pub fn metadata(&self) -> io::Result { + self.0 + } + + pub fn file_type(&self) -> io::Result { + self.0 + } +} + +impl OpenOptions { + pub fn new() -> OpenOptions { + OpenOptions { read: false, write: false, append: false } + } + + pub fn read(&mut self, read: bool) { + self.read = read; + } + pub fn write(&mut self, write: bool) { + self.write = write; + } + pub fn append(&mut self, append: bool) { + self.append = append; + } + pub fn truncate(&mut self, _truncate: bool) {} + pub fn create(&mut self, create: bool) { + self.write = create; + } + pub fn create_new(&mut self, _create_new: bool) {} +} + +impl File { + pub fn open(path: &Path, opts: &OpenOptions) -> io::Result { + let path = CString::new(path.as_os_str().as_encoded_bytes()).map_err(|_| { + io::Error::new(io::ErrorKind::InvalidData, "Path contained a null byte") + })?; + + let file = if opts.read && !opts.write { + // The second argument to this function is ignored. + // Open in read only mode + unsafe { vex_sdk::vexFileOpen(path.as_ptr(), c"".as_ptr()) } + } else if opts.write && opts.append { + // Open in read/write and append mode + unsafe { vex_sdk::vexFileOpenWrite(path.as_ptr()) } + } else if opts.write { + // Open in read/write mode + unsafe { vex_sdk::vexFileOpenCreate(path.as_ptr()) } + } else { + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + "Files cannot be opened without read or write access", + )); + }; + + if file.is_null() { + Err(io::Error::new(io::ErrorKind::NotFound, "Could not open file")) + } else { + Ok(Self(Fd(file))) + } + } + + pub fn file_attr(&self) -> io::Result { + todo!() + } + + pub fn fsync(&self) -> io::Result<()> { + todo!() + } + + pub fn datasync(&self) -> io::Result<()> { + todo!() + } + + pub fn truncate(&self, _size: u64) -> io::Result<()> { + todo!() + } + + pub fn read(&self, buf: &mut [u8]) -> io::Result { + let len = buf.len() as _; + let buf_ptr = buf.as_mut_ptr(); + let read = unsafe { vex_sdk::vexFileRead(buf_ptr.cast(), 1, len, self.0.0) }; + if read < 0 { + Err(io::Error::new( + io::ErrorKind::Other, + "Could not read from file", + )) + } else { + Ok(read as usize) + } + } + + pub fn read_vectored(&self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result { + todo!() + } + + pub fn is_read_vectored(&self) -> bool { + todo!() + } + + pub fn read_buf(&self, _cursor: BorrowedCursor<'_>) -> io::Result<()> { + todo!() + } + + pub fn write(&self, _buf: &[u8]) -> io::Result { + todo!() + } + + pub fn write_vectored(&self, _bufs: &[IoSlice<'_>]) -> io::Result { + todo!() + } + + pub fn is_write_vectored(&self) -> bool { + todo!() + } + + pub fn flush(&self) -> io::Result<()> { + todo!() + } + + pub fn seek(&self, _pos: SeekFrom) -> io::Result { + todo!() + } + + pub fn duplicate(&self) -> io::Result { + todo!() + } + + pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> { + todo!() + } + + pub fn set_times(&self, _times: FileTimes) -> io::Result<()> { + todo!() + } +} + +impl DirBuilder { + pub fn new() -> DirBuilder { + DirBuilder {} + } + + pub fn mkdir(&self, _p: &Path) -> io::Result<()> { + unsupported() + } +} + +impl fmt::Debug for File { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("File").finish_non_exhaustive() + } +} + +pub fn readdir(_p: &Path) -> io::Result { + unsupported() +} + +pub fn unlink(_p: &Path) -> io::Result<()> { + unsupported() +} + +pub fn rename(_old: &Path, _new: &Path) -> io::Result<()> { + unsupported() +} + +pub fn set_perm(_p: &Path, _perm: FilePermissions) -> io::Result<()> { + unsupported() +} + +pub fn rmdir(_p: &Path) -> io::Result<()> { + unsupported() +} + +pub fn remove_dir_all(_path: &Path) -> io::Result<()> { + unsupported() +} + +pub fn try_exists(_path: &Path) -> io::Result { + unsupported() +} + +pub fn readlink(_p: &Path) -> io::Result { + unsupported() +} + +pub fn symlink(_original: &Path, _link: &Path) -> io::Result<()> { + unsupported() +} + +pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> { + unsupported() +} + +pub fn stat(_p: &Path) -> io::Result { + unsupported() +} + +pub fn lstat(_p: &Path) -> io::Result { + unsupported() +} + +pub fn canonicalize(_p: &Path) -> io::Result { + unsupported() +} + +pub fn copy(_from: &Path, _to: &Path) -> io::Result { + unsupported() +} diff --git a/library/std/src/sys/pal/vexos/mod.rs b/library/std/src/sys/pal/vexos/mod.rs index cb80cf675a09c..bd99234b9e192 100644 --- a/library/std/src/sys/pal/vexos/mod.rs +++ b/library/std/src/sys/pal/vexos/mod.rs @@ -1,9 +1,7 @@ pub mod alloc; #[path = "../unsupported/args.rs"] pub mod args; -#[path = "../unsupported/env.rs"] pub mod env; -#[path = "../unsupported/fs.rs"] pub mod fs; #[path = "../unsupported/io.rs"] pub mod io; From 72111c525c1418782e23cd14ac029cf73fc1187a Mon Sep 17 00:00:00 2001 From: Tropical <42101043+Tropix126@users.noreply.github.com> Date: Thu, 18 Jul 2024 18:19:56 -0400 Subject: [PATCH 19/49] add support for more missing file operations --- library/std/src/sys/pal/vexos/fs.rs | 48 +++++++++++++++-------------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/library/std/src/sys/pal/vexos/fs.rs b/library/std/src/sys/pal/vexos/fs.rs index 005dc2645990a..ba5a704dbb768 100644 --- a/library/std/src/sys/pal/vexos/fs.rs +++ b/library/std/src/sys/pal/vexos/fs.rs @@ -6,9 +6,9 @@ use crate::path::{Path, PathBuf}; use crate::sys::time::SystemTime; use crate::sys::unsupported; -struct Fd(*mut vex_sdk::FIL); +struct FileDesc(*mut vex_sdk::FIL); -pub struct File(Fd); +pub struct File(FileDesc); //TODO: We may be able to get some of this info #[derive(Clone)] @@ -173,7 +173,7 @@ impl File { if file.is_null() { Err(io::Error::new(io::ErrorKind::NotFound, "Could not open file")) } else { - Ok(Self(Fd(file))) + Ok(Self(FileDesc(file))) } } @@ -182,15 +182,15 @@ impl File { } pub fn fsync(&self) -> io::Result<()> { - todo!() + self.flush() } pub fn datasync(&self) -> io::Result<()> { - todo!() + self.flush() } pub fn truncate(&self, _size: u64) -> io::Result<()> { - todo!() + unsupported() } pub fn read(&self, buf: &mut [u8]) -> io::Result { @@ -198,57 +198,59 @@ impl File { let buf_ptr = buf.as_mut_ptr(); let read = unsafe { vex_sdk::vexFileRead(buf_ptr.cast(), 1, len, self.0.0) }; if read < 0 { - Err(io::Error::new( - io::ErrorKind::Other, - "Could not read from file", - )) + Err(io::Error::new(io::ErrorKind::Other, "Could not read from file")) } else { Ok(read as usize) } } - pub fn read_vectored(&self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result { - todo!() + pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + crate::io::default_read_vectored(|buf| self.read(buf), bufs) } + #[inline] pub fn is_read_vectored(&self) -> bool { - todo!() + false } - pub fn read_buf(&self, _cursor: BorrowedCursor<'_>) -> io::Result<()> { - todo!() + pub fn read_buf(&self, cursor: BorrowedCursor<'_>) -> io::Result<()> { + crate::io::default_read_buf(|b| self.read(b), cursor) } pub fn write(&self, _buf: &[u8]) -> io::Result { todo!() } - pub fn write_vectored(&self, _bufs: &[IoSlice<'_>]) -> io::Result { - todo!() + pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { + crate::io::default_write_vectored(|buf| self.write(buf), bufs) } + #[inline] pub fn is_write_vectored(&self) -> bool { - todo!() + false } pub fn flush(&self) -> io::Result<()> { - todo!() + unsafe { + vex_sdk::vexFileSync(self.0.0); + } + Ok(()) } pub fn seek(&self, _pos: SeekFrom) -> io::Result { - todo!() + todo!(); } pub fn duplicate(&self) -> io::Result { - todo!() + unsupported!() } pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> { - todo!() + unsupported() } pub fn set_times(&self, _times: FileTimes) -> io::Result<()> { - todo!() + unsupported() } } From dc8dff0646e42b9728e489dded5b019445f41030 Mon Sep 17 00:00:00 2001 From: Gavin-Niederman Date: Thu, 18 Jul 2024 12:04:56 -0700 Subject: [PATCH 20/49] feat: file writes vectored writes and vectored reads --- library/std/src/sys/pal/vexos/fs.rs | 32 ++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/library/std/src/sys/pal/vexos/fs.rs b/library/std/src/sys/pal/vexos/fs.rs index ba5a704dbb768..7368eaecf6041 100644 --- a/library/std/src/sys/pal/vexos/fs.rs +++ b/library/std/src/sys/pal/vexos/fs.rs @@ -45,7 +45,7 @@ impl FileAttr { } pub fn perm(&self) -> FilePermissions { - todo!() + FilePermissions } pub fn file_type(&self) -> FileType { @@ -149,6 +149,13 @@ impl OpenOptions { impl File { pub fn open(path: &Path, opts: &OpenOptions) -> io::Result { + let fs_status = unsafe { vex_sdk::vexFileMountSD() }; + match fs_status { + vex_sdk::FRESULT::FR_OK => (), + //TODO: cover more results + _ => return Err(io::Error::new(io::ErrorKind::NotFound, "SD card cannot be written or read from")), + } + let path = CString::new(path.as_os_str().as_encoded_bytes()).map_err(|_| { io::Error::new(io::ErrorKind::InvalidData, "Path contained a null byte") })?; @@ -205,7 +212,7 @@ impl File { } pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { - crate::io::default_read_vectored(|buf| self.read(buf), bufs) + crate::io::default_read_vectored(|b| self.read(b), bufs) } #[inline] @@ -217,12 +224,22 @@ impl File { crate::io::default_read_buf(|b| self.read(b), cursor) } - pub fn write(&self, _buf: &[u8]) -> io::Result { - todo!() + pub fn write(&self, buf: &[u8]) -> io::Result { + let len = buf.len(); + let buf_ptr = buf.as_ptr(); + let written = unsafe { vex_sdk::vexFileWrite(buf_ptr.cast_mut().cast(), 1, len as _, self.0.0) }; + if written < 0 { + Err(io::Error::new( + io::ErrorKind::Other, + "Could not write to file", + )) + } else { + Ok(written as usize) + } } pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { - crate::io::default_write_vectored(|buf| self.write(buf), bufs) + crate::io::default_write_vectored(|b| self.write(b), bufs) } #[inline] @@ -269,6 +286,11 @@ impl fmt::Debug for File { f.debug_struct("File").finish_non_exhaustive() } } +impl Drop for File { + fn drop(&mut self) { + unsafe { vex_sdk::vexFileClose(self.0.0) }; + } +} pub fn readdir(_p: &Path) -> io::Result { unsupported() From ed9640f307056bf5eb13675ca67706ac06345b33 Mon Sep 17 00:00:00 2001 From: Tropical <42101043+Tropix126@users.noreply.github.com> Date: Sun, 21 Jul 2024 13:58:58 -0400 Subject: [PATCH 21/49] add helper for mapping FRESULT values --- library/std/src/sys/pal/vexos/fs.rs | 132 +++++++++++++++++++++++----- 1 file changed, 109 insertions(+), 23 deletions(-) diff --git a/library/std/src/sys/pal/vexos/fs.rs b/library/std/src/sys/pal/vexos/fs.rs index 7368eaecf6041..95eb9707539ff 100644 --- a/library/std/src/sys/pal/vexos/fs.rs +++ b/library/std/src/sys/pal/vexos/fs.rs @@ -6,9 +6,12 @@ use crate::path::{Path, PathBuf}; use crate::sys::time::SystemTime; use crate::sys::unsupported; +#[derive(Debug)] struct FileDesc(*mut vex_sdk::FIL); -pub struct File(FileDesc); +pub struct File { + fd: FileDesc, +} //TODO: We may be able to get some of this info #[derive(Clone)] @@ -149,12 +152,8 @@ impl OpenOptions { impl File { pub fn open(path: &Path, opts: &OpenOptions) -> io::Result { - let fs_status = unsafe { vex_sdk::vexFileMountSD() }; - match fs_status { - vex_sdk::FRESULT::FR_OK => (), - //TODO: cover more results - _ => return Err(io::Error::new(io::ErrorKind::NotFound, "SD card cannot be written or read from")), - } + // Mount sdcard volume as FAT filesystem + map_fresult(unsafe { vex_sdk::vexFileMountSD() })?; let path = CString::new(path.as_os_str().as_encoded_bytes()).map_err(|_| { io::Error::new(io::ErrorKind::InvalidData, "Path contained a null byte") @@ -180,7 +179,7 @@ impl File { if file.is_null() { Err(io::Error::new(io::ErrorKind::NotFound, "Could not open file")) } else { - Ok(Self(FileDesc(file))) + Ok(Self { fd: FileDesc(file) }) } } @@ -203,7 +202,7 @@ impl File { pub fn read(&self, buf: &mut [u8]) -> io::Result { let len = buf.len() as _; let buf_ptr = buf.as_mut_ptr(); - let read = unsafe { vex_sdk::vexFileRead(buf_ptr.cast(), 1, len, self.0.0) }; + let read = unsafe { vex_sdk::vexFileRead(buf_ptr.cast(), 1, len, self.fd.0) }; if read < 0 { Err(io::Error::new(io::ErrorKind::Other, "Could not read from file")) } else { @@ -227,12 +226,10 @@ impl File { pub fn write(&self, buf: &[u8]) -> io::Result { let len = buf.len(); let buf_ptr = buf.as_ptr(); - let written = unsafe { vex_sdk::vexFileWrite(buf_ptr.cast_mut().cast(), 1, len as _, self.0.0) }; + let written = + unsafe { vex_sdk::vexFileWrite(buf_ptr.cast_mut().cast(), 1, len as _, self.fd.0) }; if written < 0 { - Err(io::Error::new( - io::ErrorKind::Other, - "Could not write to file", - )) + Err(io::Error::new(io::ErrorKind::Other, "Could not write to file")) } else { Ok(written as usize) } @@ -249,7 +246,7 @@ impl File { pub fn flush(&self) -> io::Result<()> { unsafe { - vex_sdk::vexFileSync(self.0.0); + vex_sdk::vexFileSync(self.fd.0); } Ok(()) } @@ -259,7 +256,7 @@ impl File { } pub fn duplicate(&self) -> io::Result { - unsupported!() + unsupported() } pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> { @@ -283,17 +280,17 @@ impl DirBuilder { impl fmt::Debug for File { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("File").finish_non_exhaustive() + f.debug_struct("File").field("fd", &self.fd.0).finish() } } impl Drop for File { fn drop(&mut self) { - unsafe { vex_sdk::vexFileClose(self.0.0) }; + unsafe { vex_sdk::vexFileClose(self.fd.0) }; } } pub fn readdir(_p: &Path) -> io::Result { - unsupported() + todo!() } pub fn unlink(_p: &Path) -> io::Result<()> { @@ -317,7 +314,7 @@ pub fn remove_dir_all(_path: &Path) -> io::Result<()> { } pub fn try_exists(_path: &Path) -> io::Result { - unsupported() + todo!() } pub fn readlink(_p: &Path) -> io::Result { @@ -333,7 +330,7 @@ pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> { } pub fn stat(_p: &Path) -> io::Result { - unsupported() + todo!() } pub fn lstat(_p: &Path) -> io::Result { @@ -344,6 +341,95 @@ pub fn canonicalize(_p: &Path) -> io::Result { unsupported() } -pub fn copy(_from: &Path, _to: &Path) -> io::Result { - unsupported() +pub fn copy(from: &Path, to: &Path) -> io::Result { + use crate::fs::File; + + let mut reader = File::open(from)?; + let mut writer = File::create(to)?; + + io::copy(&mut reader, &mut writer) +} + +fn map_fresult(fresult: vex_sdk::FRESULT) -> io::Result<()> { + // VEX presumably uses a derivative of FatFs (most likely the xilffs library) + // for sdcard filesystem functions. + // + // Documentation for each FRESULT originates from here: + // + match fresult { + vex_sdk::FRESULT::FR_OK => Ok(()), + vex_sdk::FRESULT::FR_DISK_ERR => Err(io::Error::new( + io::ErrorKind::Uncategorized, + "internal function reported an unrecoverable hard error", + )), + vex_sdk::FRESULT::FR_INT_ERR => Err(io::Error::new( + io::ErrorKind::Uncategorized, + "assertion failed and an insanity is detected in the internal process", + )), + vex_sdk::FRESULT::FR_NOT_READY => Err(io::Error::new( + io::ErrorKind::Uncategorized, + "the storage device could not be prepared to work", + )), + vex_sdk::FRESULT::FR_NO_FILE => { + Err(io::Error::new(io::ErrorKind::NotFound, "could not find the file in the directory")) + } + vex_sdk::FRESULT::FR_NO_PATH => Err(io::Error::new( + io::ErrorKind::NotFound, + "a directory in the path name could not be found", + )), + vex_sdk::FRESULT::FR_INVALID_NAME => Err(io::Error::new( + io::ErrorKind::InvalidInput, + "the given string is invalid as a path name", + )), + vex_sdk::FRESULT::FR_DENIED => Err(io::Error::new( + io::ErrorKind::PermissionDenied, + "the required access for this operation was denied", + )), + vex_sdk::FRESULT::FR_EXIST => Err(io::Error::new( + io::ErrorKind::AlreadyExists, + "an object with the same name already exists in the directory", + )), + vex_sdk::FRESULT::FR_INVALID_OBJECT => Err(io::Error::new( + io::ErrorKind::Uncategorized, + "invalid or null file/directory object", + )), + vex_sdk::FRESULT::FR_WRITE_PROTECTED => Err(io::Error::new( + io::ErrorKind::PermissionDenied, + "a write operation was performed on write-protected media", + )), + vex_sdk::FRESULT::FR_INVALID_DRIVE => Err(io::Error::new( + io::ErrorKind::InvalidInput, + "an invalid drive number was specified in the path name", + )), + vex_sdk::FRESULT::FR_NOT_ENABLED => Err(io::Error::new( + io::ErrorKind::Uncategorized, + "work area for the logical drive has not been registered", + )), + vex_sdk::FRESULT::FR_NO_FILESYSTEM => Err(io::Error::new( + io::ErrorKind::Uncategorized, + "valid FAT volume could not be found on the drive", + )), + vex_sdk::FRESULT::FR_MKFS_ABORTED => { + Err(io::Error::new(io::ErrorKind::Uncategorized, "failed to create filesystem volume")) + } + vex_sdk::FRESULT::FR_TIMEOUT => Err(io::Error::new( + io::ErrorKind::TimedOut, + "the function was canceled due to a timeout of thread-safe control", + )), + vex_sdk::FRESULT::FR_LOCKED => Err(io::Error::new( + io::ErrorKind::Uncategorized, + "the operation to the object was rejected by file sharing control", + )), + vex_sdk::FRESULT::FR_NOT_ENOUGH_CORE => { + Err(io::Error::new(io::ErrorKind::OutOfMemory, "not enough memory for the operation")) + } + vex_sdk::FRESULT::FR_TOO_MANY_OPEN_FILES => Err(io::Error::new( + io::ErrorKind::Uncategorized, + "maximum number of open files has been reached", + )), + vex_sdk::FRESULT::FR_INVALID_PARAMETER => { + Err(io::Error::new(io::ErrorKind::InvalidInput, "a given parameter was invalid")) + } + _ => unreachable!(), // C-style enum + } } From 3886ee9a246e93c166e5d7af36dcf2b2ae7df60b Mon Sep 17 00:00:00 2001 From: Gavin-Niederman Date: Sun, 21 Jul 2024 12:53:31 -0700 Subject: [PATCH 22/49] add: try_file_exists and stat --- library/std/src/sys/pal/vexos/fs.rs | 76 ++++++++++++++++++++++++----- 1 file changed, 65 insertions(+), 11 deletions(-) diff --git a/library/std/src/sys/pal/vexos/fs.rs b/library/std/src/sys/pal/vexos/fs.rs index 95eb9707539ff..aa7e8540292f8 100644 --- a/library/std/src/sys/pal/vexos/fs.rs +++ b/library/std/src/sys/pal/vexos/fs.rs @@ -15,7 +15,9 @@ pub struct File { //TODO: We may be able to get some of this info #[derive(Clone)] -pub struct FileAttr; +pub struct FileAttr { + size: u64, +} pub struct ReadDir(!); @@ -26,6 +28,7 @@ pub struct OpenOptions { read: bool, write: bool, append: bool, + create_new: bool, } #[derive(Copy, Clone, Debug, Default)] @@ -44,7 +47,7 @@ pub struct DirBuilder {} impl FileAttr { pub fn size(&self) -> u64 { - todo!() + self.size } pub fn perm(&self) -> FilePermissions { @@ -131,7 +134,7 @@ impl DirEntry { impl OpenOptions { pub fn new() -> OpenOptions { - OpenOptions { read: false, write: false, append: false } + OpenOptions { read: false, write: false, append: false, create_new: false } } pub fn read(&mut self, read: bool) { @@ -143,11 +146,17 @@ impl OpenOptions { pub fn append(&mut self, append: bool) { self.append = append; } - pub fn truncate(&mut self, _truncate: bool) {} + pub fn truncate(&mut self, truncate: bool) { + if truncate { + panic!("Truncation is not supported") + } + } pub fn create(&mut self, create: bool) { self.write = create; } - pub fn create_new(&mut self, _create_new: bool) {} + pub fn create_new(&mut self, create_new: bool) { + self.create_new = create_new; + } } impl File { @@ -159,6 +168,18 @@ impl File { io::Error::new(io::ErrorKind::InvalidData, "Path contained a null byte") })?; + if opts.create_new { + let file_exists = unsafe { + vex_sdk::vexFileStatus(path.as_ptr()) + }; + if file_exists != 0 { + return Err(io::Error::new( + io::ErrorKind::AlreadyExists, + "File already exists" + )) + } + } + let file = if opts.read && !opts.write { // The second argument to this function is ignored. // Open in read only mode @@ -313,8 +334,19 @@ pub fn remove_dir_all(_path: &Path) -> io::Result<()> { unsupported() } -pub fn try_exists(_path: &Path) -> io::Result { - todo!() +pub fn try_exists(path: &Path) -> io::Result { + let path = CString::new(path.as_os_str().as_encoded_bytes()).map_err(|_| { + io::Error::new(io::ErrorKind::InvalidData, "Path contained a null byte") + })?; + + let file_exists = unsafe { + vex_sdk::vexFileStatus(path.as_ptr()) + }; + if file_exists != 0 { + Ok(true) + } else { + Ok(false) + } } pub fn readlink(_p: &Path) -> io::Result { @@ -329,12 +361,34 @@ pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> { unsupported() } -pub fn stat(_p: &Path) -> io::Result { - todo!() +pub fn stat(p: &Path) -> io::Result { + let mut opts = OpenOptions::new(); + opts.read(true); + let file = File::open(p, &opts)?; + let fd = file.fd.0; + + const SEEK_END: i32 = 2; + + let end = unsafe { + map_fresult(vex_sdk::vexFileSeek(fd, 0, SEEK_END))?; + vex_sdk::vexFileTell(fd) + }; + + if end >= 0 { + Ok(FileAttr { + size: end as u64, + }) + } else { + Err(io::Error::new( + io::ErrorKind::NotSeekable, + "Failed to seek file" + )) + } } -pub fn lstat(_p: &Path) -> io::Result { - unsupported() +pub fn lstat(p: &Path) -> io::Result { + // Symlinks aren't supported in our filesystem + stat(p) } pub fn canonicalize(_p: &Path) -> io::Result { From c5ec31f341c2db62a396e8c80ff7c58c8dad1d33 Mon Sep 17 00:00:00 2001 From: Gavin-Niederman Date: Sun, 21 Jul 2024 13:26:58 -0700 Subject: [PATCH 23/49] add: fileattr functions --- library/std/src/sys/pal/vexos/fs.rs | 46 +++++++++++------------------ 1 file changed, 18 insertions(+), 28 deletions(-) diff --git a/library/std/src/sys/pal/vexos/fs.rs b/library/std/src/sys/pal/vexos/fs.rs index aa7e8540292f8..a56ea5c4da0d5 100644 --- a/library/std/src/sys/pal/vexos/fs.rs +++ b/library/std/src/sys/pal/vexos/fs.rs @@ -55,19 +55,21 @@ impl FileAttr { } pub fn file_type(&self) -> FileType { - todo!() + FileType { + is_dir: false, + } } pub fn modified(&self) -> io::Result { - todo!() + unsupported() } pub fn accessed(&self) -> io::Result { - todo!() + unsupported() } pub fn created(&self) -> io::Result { - todo!() + unsupported() } } @@ -146,11 +148,7 @@ impl OpenOptions { pub fn append(&mut self, append: bool) { self.append = append; } - pub fn truncate(&mut self, truncate: bool) { - if truncate { - panic!("Truncation is not supported") - } - } + pub fn truncate(&mut self, _truncate: bool) {} pub fn create(&mut self, create: bool) { self.write = create; } @@ -169,14 +167,9 @@ impl File { })?; if opts.create_new { - let file_exists = unsafe { - vex_sdk::vexFileStatus(path.as_ptr()) - }; + let file_exists = unsafe { vex_sdk::vexFileStatus(path.as_ptr()) }; if file_exists != 0 { - return Err(io::Error::new( - io::ErrorKind::AlreadyExists, - "File already exists" - )) + return Err(io::Error::new(io::ErrorKind::AlreadyExists, "File already exists")); } } @@ -335,18 +328,11 @@ pub fn remove_dir_all(_path: &Path) -> io::Result<()> { } pub fn try_exists(path: &Path) -> io::Result { - let path = CString::new(path.as_os_str().as_encoded_bytes()).map_err(|_| { - io::Error::new(io::ErrorKind::InvalidData, "Path contained a null byte") - })?; + let path = CString::new(path.as_os_str().as_encoded_bytes()) + .map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "Path contained a null byte"))?; - let file_exists = unsafe { - vex_sdk::vexFileStatus(path.as_ptr()) - }; - if file_exists != 0 { - Ok(true) - } else { - Ok(false) - } + let file_exists = unsafe { vex_sdk::vexFileStatus(path.as_ptr()) }; + if file_exists != 0 { Ok(true) } else { Ok(false) } } pub fn readlink(_p: &Path) -> io::Result { @@ -368,10 +354,14 @@ pub fn stat(p: &Path) -> io::Result { let fd = file.fd.0; const SEEK_END: i32 = 2; + const SEEK_SET: i32 = 0; let end = unsafe { + let cur = vex_sdk::vexFileTell(fd); map_fresult(vex_sdk::vexFileSeek(fd, 0, SEEK_END))?; - vex_sdk::vexFileTell(fd) + let end = vex_sdk::vexFileTell(fd); + map_fresult(vex_sdk::vexFileSeek(fd, cur as _, SEEK_SET))?; + end }; if end >= 0 { From 99ef1aec20349c56e97e967808f019dd10dd8b9a Mon Sep 17 00:00:00 2001 From: Gavin-Niederman Date: Sun, 21 Jul 2024 14:39:26 -0700 Subject: [PATCH 24/49] fix: check current position in file when getting size --- library/std/src/sys/pal/vexos/fs.rs | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/library/std/src/sys/pal/vexos/fs.rs b/library/std/src/sys/pal/vexos/fs.rs index a56ea5c4da0d5..2a4c9511d45a3 100644 --- a/library/std/src/sys/pal/vexos/fs.rs +++ b/library/std/src/sys/pal/vexos/fs.rs @@ -55,9 +55,7 @@ impl FileAttr { } pub fn file_type(&self) -> FileType { - FileType { - is_dir: false, - } + FileType { is_dir: false } } pub fn modified(&self) -> io::Result { @@ -358,6 +356,9 @@ pub fn stat(p: &Path) -> io::Result { let end = unsafe { let cur = vex_sdk::vexFileTell(fd); + if cur < 0 { + return Err(io::Error::new(io::ErrorKind::NotSeekable, "Failed to seek file")); + } map_fresult(vex_sdk::vexFileSeek(fd, 0, SEEK_END))?; let end = vex_sdk::vexFileTell(fd); map_fresult(vex_sdk::vexFileSeek(fd, cur as _, SEEK_SET))?; @@ -365,14 +366,9 @@ pub fn stat(p: &Path) -> io::Result { }; if end >= 0 { - Ok(FileAttr { - size: end as u64, - }) + Ok(FileAttr { size: end as u64 }) } else { - Err(io::Error::new( - io::ErrorKind::NotSeekable, - "Failed to seek file" - )) + Err(io::Error::new(io::ErrorKind::NotSeekable, "Failed to seek file")) } } From cf0224e0896bfce342e116a3a5f6cd7ff4bae02a Mon Sep 17 00:00:00 2001 From: Gavin-Niederman Date: Sun, 21 Jul 2024 15:23:45 -0700 Subject: [PATCH 25/49] refactor: pseudorandom hashmap keys --- library/std/src/sys/pal/vexos/mod.rs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/pal/vexos/mod.rs b/library/std/src/sys/pal/vexos/mod.rs index bd99234b9e192..2469b6fa855ed 100644 --- a/library/std/src/sys/pal/vexos/mod.rs +++ b/library/std/src/sys/pal/vexos/mod.rs @@ -21,6 +21,7 @@ pub mod thread_local_key; pub mod time; use crate::{arch::asm, ptr::{self, addr_of_mut}}; +use crate::hash::{DefaultHasher, Hasher}; #[cfg(not(test))] #[no_mangle] @@ -87,6 +88,18 @@ pub fn abort_internal() -> ! { } } +fn hash_time() -> u64 { + let mut hasher = DefaultHasher::new(); + // The closest we can get to a random number is the time since program start + let time = unsafe { + vex_sdk::vexSystemHighResTimeGet() + }; + hasher.write_u64(time); + hasher.finish() +} + pub fn hashmap_random_keys() -> (u64, u64) { - (1, 2) + let key1 = hash_time(); + let key2 = hash_time(); + (key1, key2) } From e3d39564d87e10f9690078121536f39703551bf1 Mon Sep 17 00:00:00 2001 From: Gavin-Niederman Date: Mon, 22 Jul 2024 14:39:48 -0700 Subject: [PATCH 26/49] fix: support File::file_attr and dissalow read and write mode at the same time --- library/std/src/sys/pal/vexos/fs.rs | 60 ++++++++++++++++++----------- 1 file changed, 37 insertions(+), 23 deletions(-) diff --git a/library/std/src/sys/pal/vexos/fs.rs b/library/std/src/sys/pal/vexos/fs.rs index 2a4c9511d45a3..785639ad1d340 100644 --- a/library/std/src/sys/pal/vexos/fs.rs +++ b/library/std/src/sys/pal/vexos/fs.rs @@ -28,6 +28,7 @@ pub struct OpenOptions { read: bool, write: bool, append: bool, + truncate: bool, create_new: bool, } @@ -46,6 +47,19 @@ pub struct FileType { pub struct DirBuilder {} impl FileAttr { + /// Creates a FileAttr by getting data from an opened file. + fn from_fd(fd: *mut vex_sdk::FIL) -> io::Result { + let size = unsafe { + vex_sdk::vexFileSize(fd) + }; + + if size >= 0 { + Ok(Self { size: size as u64 }) + } else { + Err(io::Error::new(io::ErrorKind::NotSeekable, "Failed to seek file")) + } + } + pub fn size(&self) -> u64 { self.size } @@ -134,7 +148,7 @@ impl DirEntry { impl OpenOptions { pub fn new() -> OpenOptions { - OpenOptions { read: false, write: false, append: false, create_new: false } + OpenOptions { read: false, write: false, append: false, truncate: false, create_new: false } } pub fn read(&mut self, read: bool) { @@ -146,7 +160,9 @@ impl OpenOptions { pub fn append(&mut self, append: bool) { self.append = append; } - pub fn truncate(&mut self, _truncate: bool) {} + pub fn truncate(&mut self, truncate: bool) { + self.truncate = truncate; + } pub fn create(&mut self, create: bool) { self.write = create; } @@ -164,6 +180,12 @@ impl File { io::Error::new(io::ErrorKind::InvalidData, "Path contained a null byte") })?; + if opts.write && opts.read { + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + "Files cannot be opened with read and write access", + )); + } if opts.create_new { let file_exists = unsafe { vex_sdk::vexFileStatus(path.as_ptr()) }; if file_exists != 0 { @@ -178,9 +200,19 @@ impl File { } else if opts.write && opts.append { // Open in read/write and append mode unsafe { vex_sdk::vexFileOpenWrite(path.as_ptr()) } - } else if opts.write { + } else if opts.write && opts.truncate { // Open in read/write mode unsafe { vex_sdk::vexFileOpenCreate(path.as_ptr()) } + } else if opts.write { + // Open in read/write and overwrite mode + unsafe { + // Open in read/write and append mode + let fd = vex_sdk::vexFileOpenWrite(path.as_ptr()); + // Seek to beginning of the file + vex_sdk::vexFileSeek(fd, 0, 0); + + fd + } } else { return Err(io::Error::new( io::ErrorKind::InvalidInput, @@ -196,7 +228,7 @@ impl File { } pub fn file_attr(&self) -> io::Result { - todo!() + FileAttr::from_fd(self.fd.0) } pub fn fsync(&self) -> io::Result<()> { @@ -351,25 +383,7 @@ pub fn stat(p: &Path) -> io::Result { let file = File::open(p, &opts)?; let fd = file.fd.0; - const SEEK_END: i32 = 2; - const SEEK_SET: i32 = 0; - - let end = unsafe { - let cur = vex_sdk::vexFileTell(fd); - if cur < 0 { - return Err(io::Error::new(io::ErrorKind::NotSeekable, "Failed to seek file")); - } - map_fresult(vex_sdk::vexFileSeek(fd, 0, SEEK_END))?; - let end = vex_sdk::vexFileTell(fd); - map_fresult(vex_sdk::vexFileSeek(fd, cur as _, SEEK_SET))?; - end - }; - - if end >= 0 { - Ok(FileAttr { size: end as u64 }) - } else { - Err(io::Error::new(io::ErrorKind::NotSeekable, "Failed to seek file")) - } + FileAttr::from_fd(fd) } pub fn lstat(p: &Path) -> io::Result { From e54eb6d58e922c10f77807fdb99e022a3c59a8c0 Mon Sep 17 00:00:00 2001 From: Gavin-Niederman Date: Mon, 22 Jul 2024 15:19:26 -0700 Subject: [PATCH 27/49] feat: seek implementation --- library/std/src/sys/pal/vexos/fs.rs | 85 +++++++++++++++++++++++++++-- 1 file changed, 79 insertions(+), 6 deletions(-) diff --git a/library/std/src/sys/pal/vexos/fs.rs b/library/std/src/sys/pal/vexos/fs.rs index 785639ad1d340..43f637c30ce27 100644 --- a/library/std/src/sys/pal/vexos/fs.rs +++ b/library/std/src/sys/pal/vexos/fs.rs @@ -49,10 +49,8 @@ pub struct DirBuilder {} impl FileAttr { /// Creates a FileAttr by getting data from an opened file. fn from_fd(fd: *mut vex_sdk::FIL) -> io::Result { - let size = unsafe { - vex_sdk::vexFileSize(fd) - }; - + let size = unsafe { vex_sdk::vexFileSize(fd) }; + if size >= 0 { Ok(Self { size: size as u64 }) } else { @@ -295,8 +293,83 @@ impl File { Ok(()) } - pub fn seek(&self, _pos: SeekFrom) -> io::Result { - todo!(); + fn tell(&self) -> io::Result { + let position = unsafe { vex_sdk::vexFileTell(self.fd.0) }; + position.try_into().map_err(|_| { + io::Error::new(io::ErrorKind::InvalidData, "Failed to get current location in file") + }) + } + + pub fn seek(&self, pos: SeekFrom) -> io::Result { + const SEEK_SET: i32 = 0; + const SEEK_CUR: i32 = 1; + const SEEK_END: i32 = 2; + + fn try_convert_offset>(offset: T) -> io::Result { + offset.try_into().map_err(|_| { + io::Error::new( + io::ErrorKind::InvalidInput, + "Cannot seek to an offset too large to fit in a 32 bit integer", + ) + }) + } + + match pos { + SeekFrom::Start(offset) => unsafe { + map_fresult(vex_sdk::vexFileSeek(self.fd.0, try_convert_offset(offset)?, SEEK_SET))? + }, + + // The VEX SDK does not allow seeking with negative offsets. + // That means we need to calculate the offset from the start for both of these. + SeekFrom::End(offset) => unsafe { + // If our offset is positive, everything is easy + if offset >= 0 { + map_fresult(vex_sdk::vexFileSeek( + self.fd.0, + try_convert_offset(offset)?, + SEEK_END, + ))? + } else { + // Get the position of the end of the file... + map_fresult(vex_sdk::vexFileSeek( + self.fd.0, + try_convert_offset(offset)?, + SEEK_END, + ))?; + // The number returned by the VEX SDK tell is stored as a 32 bit interger, + // and therefore this conversion cannot fail. + let position = self.tell()? as i64; + + // Offset from that position + let new_position = position + offset; + map_fresult(vex_sdk::vexFileSeek( + self.fd.0, + try_convert_offset(new_position)?, + SEEK_SET, + ))? + } + }, + SeekFrom::Current(offset) => unsafe { + if offset >= 0 { + map_fresult(vex_sdk::vexFileSeek( + self.fd.0, + try_convert_offset(offset)?, + SEEK_CUR, + ))? + } else { + let position = self.tell()? as i64; + + let new_position = position + offset; + map_fresult(vex_sdk::vexFileSeek( + self.fd.0, + try_convert_offset(new_position)?, + SEEK_SET, + ))? + } + }, + } + + Ok(self.tell()?) } pub fn duplicate(&self) -> io::Result { From 477aeeb88de9ba8f16133ff2b680c4acc3aa4982 Mon Sep 17 00:00:00 2001 From: Gavin-Niederman Date: Mon, 22 Jul 2024 18:40:53 -0700 Subject: [PATCH 28/49] feat: almost working directory reading --- library/std/src/sys/pal/vexos/fs.rs | 104 +++++++++++++++++++++------- 1 file changed, 80 insertions(+), 24 deletions(-) diff --git a/library/std/src/sys/pal/vexos/fs.rs b/library/std/src/sys/pal/vexos/fs.rs index 43f637c30ce27..614dfc133df9a 100644 --- a/library/std/src/sys/pal/vexos/fs.rs +++ b/library/std/src/sys/pal/vexos/fs.rs @@ -17,11 +17,18 @@ pub struct File { #[derive(Clone)] pub struct FileAttr { size: u64, + is_dir: bool, } -pub struct ReadDir(!); +#[derive(Debug)] +pub struct ReadDir { + entries: Vec, +} -pub struct DirEntry(!); +#[derive(Debug)] +pub struct DirEntry { + path: PathBuf, +} #[derive(Clone, Debug)] pub struct OpenOptions { @@ -52,9 +59,31 @@ impl FileAttr { let size = unsafe { vex_sdk::vexFileSize(fd) }; if size >= 0 { - Ok(Self { size: size as u64 }) + Ok(Self { size: size as u64, is_dir: false }) + } else { + Err(io::Error::new(io::ErrorKind::InvalidData, "Failed to get file size")) + } + } + + fn from_path(path: &Path) -> io::Result { + let c_path = CString::new(path.as_os_str().as_encoded_bytes()).map_err(|_| { + io::Error::new(io::ErrorKind::InvalidData, "Path contained a null byte") + })?; + + let file_type = unsafe { vex_sdk::vexFileStatus(c_path.as_ptr()) }; + let is_dir = file_type == 3; + println!("{is_dir}"); + + // We can't get the size if its a directory because we cant open it as a file + if is_dir { + Ok(Self { size: 0, is_dir: true }) } else { - Err(io::Error::new(io::ErrorKind::NotSeekable, "Failed to seek file")) + let mut opts = OpenOptions::new(); + opts.read(true); + let file = File::open(path, &opts)?; + let fd = file.fd.0; + + Self::from_fd(fd) } } @@ -67,7 +96,7 @@ impl FileAttr { } pub fn file_type(&self) -> FileType { - FileType { is_dir: false } + FileType { is_dir: self.is_dir } } pub fn modified(&self) -> io::Result { @@ -112,35 +141,32 @@ impl FileType { } } -impl fmt::Debug for ReadDir { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0 - } -} - impl Iterator for ReadDir { type Item = io::Result; fn next(&mut self) -> Option> { - self.0 + self.entries.pop().map(Ok) } } impl DirEntry { pub fn path(&self) -> PathBuf { - self.0 + self.path.clone() } pub fn file_name(&self) -> OsString { - self.0 + self.path + .file_name() + .unwrap_or(crate::ffi::OsStr::new("")) + .to_os_string() } pub fn metadata(&self) -> io::Result { - self.0 + stat(&self.path) } pub fn file_type(&self) -> io::Result { - self.0 + Ok(self.metadata()?.file_type()) } } @@ -406,8 +432,43 @@ impl Drop for File { } } -pub fn readdir(_p: &Path) -> io::Result { - todo!() +pub fn readdir(p: &Path) -> io::Result { + if !stat(p)?.file_type().is_dir() { + return Err(io::Error::new(io::ErrorKind::InvalidInput, "Given directory was not a path")); + } + + // getting directory entries does not work with trailing slashes + let path = p + .to_str() + .ok_or(io::Error::new(io::ErrorKind::InvalidInput, "Path contained invalid characters"))? + .trim_end_matches("/"); + let path = CString::new(path.as_bytes()) + .map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "Path contained a null byte"))?; + + //TODO: Figure out if there is any way to check the number of entries in a directory/the needed length + let mut filenames_buffer = [0u8; 1000]; + unsafe { + vex_sdk::vexFileDirectoryGet( + path.as_ptr(), + filenames_buffer.as_mut_ptr().cast(), + filenames_buffer.len() as _, + ); + } + let filenames_buffer = filenames_buffer.to_vec(); + // stop at null-terminator + let filenames = match filenames_buffer.split(|&e| e == 0).next() { + Some(filenames) => filenames, + None => &filenames_buffer + }; + let filenames = String::from_utf8(filenames.to_vec()).map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "Path contained a null byte"))?; + let paths = filenames.split('\n').map(|filename| { + let mut path = PathBuf::new(); + path.push(p); + path.push(filename); + DirEntry { path } + }).collect::>(); + + Ok(ReadDir { entries: paths }) } pub fn unlink(_p: &Path) -> io::Result<()> { @@ -451,12 +512,7 @@ pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> { } pub fn stat(p: &Path) -> io::Result { - let mut opts = OpenOptions::new(); - opts.read(true); - let file = File::open(p, &opts)?; - let fd = file.fd.0; - - FileAttr::from_fd(fd) + FileAttr::from_path(p) } pub fn lstat(p: &Path) -> io::Result { From 51a85f8b959282d993ad0a78ea13bf2918495aea Mon Sep 17 00:00:00 2001 From: Gavin-Niederman Date: Mon, 22 Jul 2024 18:47:18 -0700 Subject: [PATCH 29/49] fix: remove trailing slashes sooner --- library/std/src/sys/pal/vexos/fs.rs | 42 ++++++++++++++++------------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/library/std/src/sys/pal/vexos/fs.rs b/library/std/src/sys/pal/vexos/fs.rs index 614dfc133df9a..0d248f3770b28 100644 --- a/library/std/src/sys/pal/vexos/fs.rs +++ b/library/std/src/sys/pal/vexos/fs.rs @@ -155,10 +155,7 @@ impl DirEntry { } pub fn file_name(&self) -> OsString { - self.path - .file_name() - .unwrap_or(crate::ffi::OsStr::new("")) - .to_os_string() + self.path.file_name().unwrap_or(crate::ffi::OsStr::new("")).to_os_string() } pub fn metadata(&self) -> io::Result { @@ -433,16 +430,21 @@ impl Drop for File { } pub fn readdir(p: &Path) -> io::Result { + // getting directory entries does not work with trailing slashes + let p = Path::new( + p.to_str() + .ok_or(io::Error::new( + io::ErrorKind::InvalidInput, + "Path contained invalid characters", + ))? + .trim_end_matches("/"), + ); + if !stat(p)?.file_type().is_dir() { return Err(io::Error::new(io::ErrorKind::InvalidInput, "Given directory was not a path")); } - // getting directory entries does not work with trailing slashes - let path = p - .to_str() - .ok_or(io::Error::new(io::ErrorKind::InvalidInput, "Path contained invalid characters"))? - .trim_end_matches("/"); - let path = CString::new(path.as_bytes()) + let path = CString::new(p.as_os_str().as_encoded_bytes()) .map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "Path contained a null byte"))?; //TODO: Figure out if there is any way to check the number of entries in a directory/the needed length @@ -458,15 +460,19 @@ pub fn readdir(p: &Path) -> io::Result { // stop at null-terminator let filenames = match filenames_buffer.split(|&e| e == 0).next() { Some(filenames) => filenames, - None => &filenames_buffer + None => &filenames_buffer, }; - let filenames = String::from_utf8(filenames.to_vec()).map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "Path contained a null byte"))?; - let paths = filenames.split('\n').map(|filename| { - let mut path = PathBuf::new(); - path.push(p); - path.push(filename); - DirEntry { path } - }).collect::>(); + let filenames = String::from_utf8(filenames.to_vec()) + .map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "Path contained a null byte"))?; + let paths = filenames + .split('\n') + .map(|filename| { + let mut path = PathBuf::new(); + path.push(p); + path.push(filename); + DirEntry { path } + }) + .collect::>(); Ok(ReadDir { entries: paths }) } From 871058aa6e9c75fbde4630bc4a7dbeac4209e92d Mon Sep 17 00:00:00 2001 From: Tropical <42101043+Tropix126@users.noreply.github.com> Date: Fri, 26 Jul 2024 23:22:39 -0400 Subject: [PATCH 30/49] remove test code and document filesystem quirks --- library/std/src/sys/pal/vexos/fs.rs | 61 +++++--------------------- library/std/src/sys/pal/vexos/mod.rs | 3 ++ library/std/src/sys/pal/vexos/stdio.rs | 5 ++- 3 files changed, 18 insertions(+), 51 deletions(-) diff --git a/library/std/src/sys/pal/vexos/fs.rs b/library/std/src/sys/pal/vexos/fs.rs index 0d248f3770b28..f5cb0a961cf22 100644 --- a/library/std/src/sys/pal/vexos/fs.rs +++ b/library/std/src/sys/pal/vexos/fs.rs @@ -13,7 +13,6 @@ pub struct File { fd: FileDesc, } -//TODO: We may be able to get some of this info #[derive(Clone)] pub struct FileAttr { size: u64, @@ -72,7 +71,6 @@ impl FileAttr { let file_type = unsafe { vex_sdk::vexFileStatus(c_path.as_ptr()) }; let is_dir = file_type == 3; - println!("{is_dir}"); // We can't get the size if its a directory because we cant open it as a file if is_dir { @@ -342,7 +340,7 @@ impl File { map_fresult(vex_sdk::vexFileSeek(self.fd.0, try_convert_offset(offset)?, SEEK_SET))? }, - // The VEX SDK does not allow seeking with negative offsets. + // vexOS does not allow seeking with negative offsets. // That means we need to calculate the offset from the start for both of these. SeekFrom::End(offset) => unsafe { // If our offset is positive, everything is easy @@ -429,52 +427,15 @@ impl Drop for File { } } -pub fn readdir(p: &Path) -> io::Result { - // getting directory entries does not work with trailing slashes - let p = Path::new( - p.to_str() - .ok_or(io::Error::new( - io::ErrorKind::InvalidInput, - "Path contained invalid characters", - ))? - .trim_end_matches("/"), - ); - - if !stat(p)?.file_type().is_dir() { - return Err(io::Error::new(io::ErrorKind::InvalidInput, "Given directory was not a path")); - } - - let path = CString::new(p.as_os_str().as_encoded_bytes()) - .map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "Path contained a null byte"))?; - - //TODO: Figure out if there is any way to check the number of entries in a directory/the needed length - let mut filenames_buffer = [0u8; 1000]; - unsafe { - vex_sdk::vexFileDirectoryGet( - path.as_ptr(), - filenames_buffer.as_mut_ptr().cast(), - filenames_buffer.len() as _, - ); - } - let filenames_buffer = filenames_buffer.to_vec(); - // stop at null-terminator - let filenames = match filenames_buffer.split(|&e| e == 0).next() { - Some(filenames) => filenames, - None => &filenames_buffer, - }; - let filenames = String::from_utf8(filenames.to_vec()) - .map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "Path contained a null byte"))?; - let paths = filenames - .split('\n') - .map(|filename| { - let mut path = PathBuf::new(); - path.push(p); - path.push(filename); - DirEntry { path } - }) - .collect::>(); - - Ok(ReadDir { entries: paths }) +pub fn readdir(_p: &Path) -> io::Result { + // While there *is* a userspace function for reading file directories, + // the necessary implementation cannot currently be done cleanly, as + // vexOS does not expose directory length to user programs. + // + // This means that we would need to create a large fixed-length buffer + // and hope that the folder's contents didn't exceed that buffer's length, + // which obviously isn't behavior we want to rely on in the standard library. + unsupported() } pub fn unlink(_p: &Path) -> io::Result<()> { @@ -522,7 +483,7 @@ pub fn stat(p: &Path) -> io::Result { } pub fn lstat(p: &Path) -> io::Result { - // Symlinks aren't supported in our filesystem + // Symlinks aren't supported in this filesystem stat(p) } diff --git a/library/std/src/sys/pal/vexos/mod.rs b/library/std/src/sys/pal/vexos/mod.rs index 2469b6fa855ed..ab3d2505ec6f2 100644 --- a/library/std/src/sys/pal/vexos/mod.rs +++ b/library/std/src/sys/pal/vexos/mod.rs @@ -34,8 +34,11 @@ pub unsafe extern "C" fn _start() -> ! { fn main() -> i32; } + // Setup the stack asm!("ldr sp, =__stack_top", options(nostack)); + // vexOS doesn't explicitly clean out .bss, so as a sanity + // check we'll fill it with zeroes. ptr::slice_from_raw_parts_mut( addr_of_mut!(__bss_start), addr_of_mut!(__bss_end).offset_from(addr_of_mut!(__bss_start)) as usize, diff --git a/library/std/src/sys/pal/vexos/stdio.rs b/library/std/src/sys/pal/vexos/stdio.rs index 998592e762434..a9e05e3537f8d 100644 --- a/library/std/src/sys/pal/vexos/stdio.rs +++ b/library/std/src/sys/pal/vexos/stdio.rs @@ -44,7 +44,10 @@ impl io::Write for Stdout { unsafe { vex_sdk::vexSerialWriteBuffer(STDIO_CHANNEL, buf.as_ptr(), buf.len() as u32) }; if written < 0 { - return Err(io::Error::new(io::ErrorKind::Other, "Internal write error occurred.")); + return Err(io::Error::new( + io::ErrorKind::Uncategorized, + "Internal write error occurred.", + )); } Ok(written as usize) From 5723946cb685cd971bcbcb45ce1a933f9bef6403 Mon Sep 17 00:00:00 2001 From: Tropical <42101043+Tropix126@users.noreply.github.com> Date: Sun, 4 Aug 2024 00:50:40 -0400 Subject: [PATCH 31/49] add default code signature, ensure stdout flush --- library/std/src/sys/pal/vexos/mod.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/library/std/src/sys/pal/vexos/mod.rs b/library/std/src/sys/pal/vexos/mod.rs index ab3d2505ec6f2..b2f3361ac66c9 100644 --- a/library/std/src/sys/pal/vexos/mod.rs +++ b/library/std/src/sys/pal/vexos/mod.rs @@ -52,6 +52,16 @@ pub unsafe extern "C" fn _start() -> ! { abort_internal() } +#[link_section = ".code_signature"] +#[linkage = "weak"] +#[used] +static CODE_SIGNATURE: vex_sdk::vcodesig = vex_sdk::vcodesig { + magic: u32::from_le_bytes(*b"XVX5"), + r#type: 2, + owner: 0, + options: 0, +}; + // This function is needed by the panic runtime. The symbol is named in // pre-link args for the target specification, so keep that in sync. #[cfg(not(test))] @@ -61,8 +71,12 @@ pub extern "C" fn __rust_abort() -> ! { abort_internal() } +// SAFETY: must be called only once during runtime initialization. +// NOTE: this is not guaranteed to run, for example when Rust code is called externally. pub unsafe fn init(_argc: isize, _argv: *const *const u8, _sigpipe: u8) {} +// SAFETY: must be called only once during runtime cleanup. +// NOTE: this is not guaranteed to run, for example when the program aborts. pub unsafe fn cleanup() {} pub fn unsupported() -> crate::io::Result { @@ -83,6 +97,7 @@ pub fn decode_error_kind(_code: i32) -> crate::io::ErrorKind { pub fn abort_internal() -> ! { unsafe { + vex_sdk::vexTasksRun(); vex_sdk::vexSystemExitRequest(); } From fd35bdacff98201ef7db54a729837485af053e1a Mon Sep 17 00:00:00 2001 From: Tropical <42101043+Tropix126@users.noreply.github.com> Date: Sun, 4 Aug 2024 00:52:55 -0400 Subject: [PATCH 32/49] add platform docs --- src/doc/rustc/src/platform-support.md | 1 + .../src/platform-support/armv7a-vex-v5.md | 91 +++++++++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 src/doc/rustc/src/platform-support/armv7a-vex-v5.md diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 0ef95ba64a1f5..546c99e9c1b60 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -159,6 +159,7 @@ target | std | notes `armv7-unknown-linux-musleabihf` | ✓ | Armv7-A Linux with musl 1.2.3, hardfloat [`armv7-unknown-linux-ohos`](platform-support/openharmony.md) | ✓ | Armv7-A OpenHarmony [`armv7a-none-eabi`](platform-support/arm-none-eabi.md) | * | Bare Armv7-A +[`armv7a-vex-v5`](platform-support/armv7a-vex-v5.md) | * | Armv7-A Cortex-A9 VEX V5 Brain, vexOS [`armv7r-none-eabi`](platform-support/armv7r-none-eabi.md) | * | Bare Armv7-R [`armv7r-none-eabihf`](platform-support/armv7r-none-eabi.md) | * | Bare Armv7-R, hardfloat `i586-pc-windows-msvc` | * | 32-bit Windows w/o SSE [^x86_32-floats-x87] diff --git a/src/doc/rustc/src/platform-support/armv7a-vex-v5.md b/src/doc/rustc/src/platform-support/armv7a-vex-v5.md new file mode 100644 index 0000000000000..897e884c65508 --- /dev/null +++ b/src/doc/rustc/src/platform-support/armv7a-vex-v5.md @@ -0,0 +1,91 @@ +# `armv7a-vex-v5` + +**Tier: 3** + + +Allows compiling user programs for the [VEX V5 Brain](https://www.vexrobotics.com/276-4810.html), a microcontroller for educational and competitive robotics. + +Rust support for this target is not affiliated with VEX Robotics or IFI, and is not derived from nor used with any official VEX SDK. + +## Target maintainers + +This target is maintained by members of the [vexide](https://github.com/vexide) organization: + +- [@Tropix126](https://github.com/Tropix126) +- [@Gavin-Niederman](https://github.com/Gavin-Niederman) +- [@max-niederman](https://github.com/max-niederman) +- [@doinkythederp](https://github.com/doinkythederp) + +## Requirements + +This target is cross-compiled. Dynamic linking is unsupported. + +`#![no_std]` crates can be built using `build-std` to build `core` and optionally +`alloc`. Unwinding panics are not yet supported. + +`std` is partially implemented, but many modules (such as `thread`, `process`, `net`, etc...) will return errors. An allocator is provided along with partial support for the `time`, `env` and `io` modules. Filesystem operations over SDCard through `std::fs` are partially supported within the restrictions of the user enviornment (e.g. directories cannot be created, filesystem objects cannot be removed). + +This target generates binaries in the ELF format that may uploaded to the brain with external tools. + +## Building the target + +Rust does not ship pre-compiled artifacts for this target. You can use `build-std` feature to build ELF binaries with `std` support. + +`.cargo/config.toml`: + +```toml +[build] +target = "armv7a-vex-v5" + +[unstable] +build-std = ["std", "panic_abort"] +build-std-features = ["compiler-builtins-mem"] +``` + +## Building Rust programs + +The recommended way to build artifacts that can be installed and run on V5 Brain is by using the [cargo-v5](https://github.com/vexide/cargo-v5) tool. This tool wraps the `cargo build` command by supplying arguments necessary to build the target, while also providing uploading functionality. + +To install the tool run: + +```sh +cargo install cargo-v5 +``` + +The following fields in your project's `Cargo.toml` are read by `cargo-v5` to configure upload behavior: + +```toml +[package.metadata.v5] +# Slot number to upload the user program to. This should be from 1-8. +slot = 1 +# Program icon/thumbnail that will be displayed on the dashboard. +icon = "cool-x" +# Use gzip compression when uploading binaries. +compress = true +``` + +To build an uploadable BIN file using the release profile, run: + +```sh +cargo v5 build --release +``` + +Programs can also be directly uploaded to the brain over a USB connection after building: + +```sh +cargo v5 upload --release +``` + +## Testing + +Binaries built for this target can be run in an emulator (such as [vex-v5-qemu](https://github.com/vexide/vex-v5-qemu)), or uploaded to a device over a USB or bluetooth connection. + +The default Rust test runner is not supported. + +The Rust test suite for `library/std` is not yet supported. + +## Cross-compilation toolchains and C code + +This target can be cross-compiled from any host. + +This target does not link to C libraries. OS calls are implemented in rust through the [vex-sdk](https://github.com/vexide/vex-sdk) crate. No `libc` or crt0 implementation is present on this target. \ No newline at end of file From 12742130b35bba6c41a3fa480241d20b2ace0efe Mon Sep 17 00:00:00 2001 From: Tropical <42101043+Tropix126@users.noreply.github.com> Date: Sun, 4 Aug 2024 01:52:16 -0400 Subject: [PATCH 33/49] adjust wording and fix typos in target documentation --- src/doc/rustc/src/platform-support/armv7a-vex-v5.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/doc/rustc/src/platform-support/armv7a-vex-v5.md b/src/doc/rustc/src/platform-support/armv7a-vex-v5.md index 897e884c65508..de009d78cfcb6 100644 --- a/src/doc/rustc/src/platform-support/armv7a-vex-v5.md +++ b/src/doc/rustc/src/platform-support/armv7a-vex-v5.md @@ -5,7 +5,7 @@ Allows compiling user programs for the [VEX V5 Brain](https://www.vexrobotics.com/276-4810.html), a microcontroller for educational and competitive robotics. -Rust support for this target is not affiliated with VEX Robotics or IFI, and is not derived from nor used with any official VEX SDK. +Rust support for this target is not affiliated with VEX Robotics or IFI. ## Target maintainers @@ -29,7 +29,7 @@ This target generates binaries in the ELF format that may uploaded to the brain ## Building the target -Rust does not ship pre-compiled artifacts for this target. You can use `build-std` feature to build ELF binaries with `std` support. +Rust does not ship pre-compiled artifacts for this target. You can use the `build-std` feature to build ELF binaries with `std` support. `.cargo/config.toml`: @@ -44,9 +44,9 @@ build-std-features = ["compiler-builtins-mem"] ## Building Rust programs -The recommended way to build artifacts that can be installed and run on V5 Brain is by using the [cargo-v5](https://github.com/vexide/cargo-v5) tool. This tool wraps the `cargo build` command by supplying arguments necessary to build the target, while also providing uploading functionality. +The recommended way to build artifacts that run on V5 Brain is by using the [cargo-v5](https://github.com/vexide/cargo-v5) tool. This tool wraps the `cargo build` command by supplying arguments necessary to build the target, while also providing functionality for uploading over USB to a V5 Controller or Brain. -To install the tool run: +To install the tool, run: ```sh cargo install cargo-v5 @@ -70,7 +70,7 @@ To build an uploadable BIN file using the release profile, run: cargo v5 build --release ``` -Programs can also be directly uploaded to the brain over a USB connection after building: +Programs can also be directly uploaded to the brain over a USB connection immediately after building: ```sh cargo v5 upload --release @@ -78,7 +78,7 @@ cargo v5 upload --release ## Testing -Binaries built for this target can be run in an emulator (such as [vex-v5-qemu](https://github.com/vexide/vex-v5-qemu)), or uploaded to a device over a USB or bluetooth connection. +Binaries built for this target can be run in an emulator (such as [vex-v5-qemu](https://github.com/vexide/vex-v5-qemu)), or uploaded to a physical device over a serial (USB) connection. The default Rust test runner is not supported. From c65cfdb7aabcc5311b58d8c0c0f07710b2d5b37c Mon Sep 17 00:00:00 2001 From: Tropical <42101043+Tropix126@users.noreply.github.com> Date: Mon, 5 Aug 2024 16:48:15 -0400 Subject: [PATCH 34/49] update PAL and add `check-cfg` override for `target_os` --- Cargo.lock | 62 +++++++++++++++++++++++++++- library/panic_abort/Cargo.toml | 3 ++ library/std/Cargo.toml | 1 + library/std/src/sys/pal/vexos/fs.rs | 6 +-- library/std/src/sys/pal/vexos/mod.rs | 4 +- 5 files changed, 69 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index faca061967379..2f4ff700f90a3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4987,6 +4987,47 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +[[package]] +name = "std" +version = "0.0.0" +dependencies = [ + "addr2line 0.22.0", + "alloc", + "cfg-if", + "compiler_builtins", + "core", + "dlmalloc", + "fortanix-sgx-abi", + "hashbrown", + "hermit-abi 0.4.0", + "libc", + "miniz_oxide", + "object 0.36.0", + "panic_abort", + "panic_unwind", + "profiler_builtins", + "r-efi", + "r-efi-alloc", + "rand", + "rand_xorshift", + "rustc-demangle", + "std_detect", + "unwind", + "vex-sdk", + "wasi", +] + +[[package]] +name = "std_detect" +version = "0.1.5" +dependencies = [ + "cfg-if", + "compiler_builtins", + "libc", + "rustc-std-workspace-alloc", + "rustc-std-workspace-core", +] + [[package]] name = "string_cache" version = "0.8.7" @@ -5723,7 +5764,26 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" name = "version_check" version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "vex-sdk" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f285bbc2b96fc4c7fae42ebe365dd2e9121e7002a58b1a9e0e4b1d14dba4d6d0" +dependencies = [ + "compiler_builtins", + "rustc-std-workspace-core", +] + +[[package]] +name = "wait-timeout" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" +dependencies = [ + "libc", +] [[package]] name = "walkdir" diff --git a/library/panic_abort/Cargo.toml b/library/panic_abort/Cargo.toml index a9d1f53761cbf..4cbc84f3802c1 100644 --- a/library/panic_abort/Cargo.toml +++ b/library/panic_abort/Cargo.toml @@ -19,3 +19,6 @@ compiler_builtins = "0.1.0" [target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies] libc = { version = "0.2", default-features = false } + +[lints.rust] +unexpected_cfgs = { level = "warn", check-cfg = ['cfg(target_os, values("vexos"))'] } \ No newline at end of file diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index c87834eae6daf..15de6f7a69b7e 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -155,4 +155,5 @@ check-cfg = [ 'cfg(feature, values(any()))', # #[cfg(bootstrap)] rtems 'cfg(target_os, values("rtems"))', + 'cfg(target_os, values("vexos"))', ] diff --git a/library/std/src/sys/pal/vexos/fs.rs b/library/std/src/sys/pal/vexos/fs.rs index f5cb0a961cf22..7d8af80fd94d9 100644 --- a/library/std/src/sys/pal/vexos/fs.rs +++ b/library/std/src/sys/pal/vexos/fs.rs @@ -340,7 +340,7 @@ impl File { map_fresult(vex_sdk::vexFileSeek(self.fd.0, try_convert_offset(offset)?, SEEK_SET))? }, - // vexOS does not allow seeking with negative offsets. + // VEXos does not allow seeking with negative offsets. // That means we need to calculate the offset from the start for both of these. SeekFrom::End(offset) => unsafe { // If our offset is positive, everything is easy @@ -430,7 +430,7 @@ impl Drop for File { pub fn readdir(_p: &Path) -> io::Result { // While there *is* a userspace function for reading file directories, // the necessary implementation cannot currently be done cleanly, as - // vexOS does not expose directory length to user programs. + // VEXos does not expose directory length to user programs. // // This means that we would need to create a large fixed-length buffer // and hope that the folder's contents didn't exceed that buffer's length, @@ -458,7 +458,7 @@ pub fn remove_dir_all(_path: &Path) -> io::Result<()> { unsupported() } -pub fn try_exists(path: &Path) -> io::Result { +pub fn exists(path: &Path) -> io::Result { let path = CString::new(path.as_os_str().as_encoded_bytes()) .map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "Path contained a null byte"))?; diff --git a/library/std/src/sys/pal/vexos/mod.rs b/library/std/src/sys/pal/vexos/mod.rs index b2f3361ac66c9..6ca3d23f63556 100644 --- a/library/std/src/sys/pal/vexos/mod.rs +++ b/library/std/src/sys/pal/vexos/mod.rs @@ -16,8 +16,6 @@ pub mod process; pub mod stdio; #[path = "../unsupported/thread.rs"] pub mod thread; -#[path = "../unsupported/thread_local_key.rs"] -pub mod thread_local_key; pub mod time; use crate::{arch::asm, ptr::{self, addr_of_mut}}; @@ -37,7 +35,7 @@ pub unsafe extern "C" fn _start() -> ! { // Setup the stack asm!("ldr sp, =__stack_top", options(nostack)); - // vexOS doesn't explicitly clean out .bss, so as a sanity + // VEXos doesn't explicitly clean out .bss, so as a sanity // check we'll fill it with zeroes. ptr::slice_from_raw_parts_mut( addr_of_mut!(__bss_start), From 876be7331bbcfacc3d25cbf1c915f605202bcd83 Mon Sep 17 00:00:00 2001 From: Tropical <42101043+Tropix126@users.noreply.github.com> Date: Mon, 5 Aug 2024 16:48:30 -0400 Subject: [PATCH 35/49] add additional information to target spec and supporting docs --- .../src/spec/targets/armv7a_vex_v5.rs | 24 ++++++++++--------- src/doc/rustc/src/platform-support.md | 2 +- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_target/src/spec/targets/armv7a_vex_v5.rs b/compiler/rustc_target/src/spec/targets/armv7a_vex_v5.rs index a6a6f542e3103..418bf2a0c5bc8 100644 --- a/compiler/rustc_target/src/spec/targets/armv7a_vex_v5.rs +++ b/compiler/rustc_target/src/spec/targets/armv7a_vex_v5.rs @@ -6,29 +6,31 @@ pub(crate) fn target() -> Target { Target { llvm_target: "armv7a-none-eabihf".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("Armv7-A Cortex-A9 VEX V5 Brain, VEXos".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), arch: "arm".into(), options: TargetOptions { + os: "vexos".into(), + vendor: "vex".into(), + exe_suffix: "elf".into(), cpu: "cortex-a9".into(), abi: "eabihf".into(), - linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), + features: "+v7,+neon,+vfp3,+thumb2,+thumb-mode".into(), linker: Some("rust-lld".into()), + linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), link_script: Some(LINK_SCRIPT.into()), - features: "+v7,+thumb2,+vfp3,+neon".into(), + panic_strategy: PanicStrategy::Abort, relocation_model: RelocModel::Static, - disable_redzone: true, + c_enum_min_bits: Some(8), max_atomic_width: Some(64), - panic_strategy: PanicStrategy::Abort, + disable_redzone: true, emit_debug_gdb_scripts: false, - c_enum_min_bits: Some(8), - os: "vexos".into(), - vendor: "vex".into(), + has_thumb_interworking: true, ..Default::default() }, } diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 546c99e9c1b60..ae02fe2c82ad3 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -159,7 +159,7 @@ target | std | notes `armv7-unknown-linux-musleabihf` | ✓ | Armv7-A Linux with musl 1.2.3, hardfloat [`armv7-unknown-linux-ohos`](platform-support/openharmony.md) | ✓ | Armv7-A OpenHarmony [`armv7a-none-eabi`](platform-support/arm-none-eabi.md) | * | Bare Armv7-A -[`armv7a-vex-v5`](platform-support/armv7a-vex-v5.md) | * | Armv7-A Cortex-A9 VEX V5 Brain, vexOS +[`armv7a-vex-v5`](platform-support/armv7a-vex-v5.md) | * | Armv7-A Cortex-A9 VEX V5 Brain, VEXos [`armv7r-none-eabi`](platform-support/armv7r-none-eabi.md) | * | Bare Armv7-R [`armv7r-none-eabihf`](platform-support/armv7r-none-eabi.md) | * | Bare Armv7-R, hardfloat `i586-pc-windows-msvc` | * | 32-bit Windows w/o SSE [^x86_32-floats-x87] From 23508ab71bbff1c8d1422e42ed13fba98c51d0ce Mon Sep 17 00:00:00 2001 From: Tropical <42101043+Tropix126@users.noreply.github.com> Date: Thu, 8 Aug 2024 23:03:32 -0400 Subject: [PATCH 36/49] fix `EXE_SUFFFIX` to use dot --- compiler/rustc_target/src/spec/targets/armv7a_vex_v5.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_target/src/spec/targets/armv7a_vex_v5.rs b/compiler/rustc_target/src/spec/targets/armv7a_vex_v5.rs index 418bf2a0c5bc8..6a5714b02fc6f 100644 --- a/compiler/rustc_target/src/spec/targets/armv7a_vex_v5.rs +++ b/compiler/rustc_target/src/spec/targets/armv7a_vex_v5.rs @@ -17,7 +17,7 @@ pub(crate) fn target() -> Target { options: TargetOptions { os: "vexos".into(), vendor: "vex".into(), - exe_suffix: "elf".into(), + exe_suffix: ".elf".into(), cpu: "cortex-a9".into(), abi: "eabihf".into(), features: "+v7,+neon,+vfp3,+thumb2,+thumb-mode".into(), From 3ec93ea64ddf5e65c85962eb6bb9a12fce717660 Mon Sep 17 00:00:00 2001 From: Tropical <42101043+Tropix126@users.noreply.github.com> Date: Sat, 17 Aug 2024 00:35:30 -0500 Subject: [PATCH 37/49] fix: use correct code signature default values --- library/std/src/sys/pal/vexos/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/pal/vexos/mod.rs b/library/std/src/sys/pal/vexos/mod.rs index 6ca3d23f63556..9c034252b7f9d 100644 --- a/library/std/src/sys/pal/vexos/mod.rs +++ b/library/std/src/sys/pal/vexos/mod.rs @@ -55,8 +55,8 @@ pub unsafe extern "C" fn _start() -> ! { #[used] static CODE_SIGNATURE: vex_sdk::vcodesig = vex_sdk::vcodesig { magic: u32::from_le_bytes(*b"XVX5"), - r#type: 2, - owner: 0, + r#type: 0, + owner: 2, options: 0, }; From 8ddc5f1ced0581c86e45d3e5f43d52639ed3ba0d Mon Sep 17 00:00:00 2001 From: Tropical <42101043+Tropix126@users.noreply.github.com> Date: Tue, 20 Aug 2024 23:30:13 -0500 Subject: [PATCH 38/49] don't compile with `+thumb-mode` feature for now --- Cargo.lock | 62 +------------------ .../src/spec/targets/armv7a_vex_v5.rs | 2 +- library/Cargo.lock | 11 ++++ 3 files changed, 13 insertions(+), 62 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2f4ff700f90a3..faca061967379 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4987,47 +4987,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" -[[package]] -name = "std" -version = "0.0.0" -dependencies = [ - "addr2line 0.22.0", - "alloc", - "cfg-if", - "compiler_builtins", - "core", - "dlmalloc", - "fortanix-sgx-abi", - "hashbrown", - "hermit-abi 0.4.0", - "libc", - "miniz_oxide", - "object 0.36.0", - "panic_abort", - "panic_unwind", - "profiler_builtins", - "r-efi", - "r-efi-alloc", - "rand", - "rand_xorshift", - "rustc-demangle", - "std_detect", - "unwind", - "vex-sdk", - "wasi", -] - -[[package]] -name = "std_detect" -version = "0.1.5" -dependencies = [ - "cfg-if", - "compiler_builtins", - "libc", - "rustc-std-workspace-alloc", - "rustc-std-workspace-core", -] - [[package]] name = "string_cache" version = "0.8.7" @@ -5764,26 +5723,7 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" name = "version_check" version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "vex-sdk" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f285bbc2b96fc4c7fae42ebe365dd2e9121e7002a58b1a9e0e4b1d14dba4d6d0" -dependencies = [ - "compiler_builtins", - "rustc-std-workspace-core", -] - -[[package]] -name = "wait-timeout" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" -dependencies = [ - "libc", -] +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "walkdir" diff --git a/compiler/rustc_target/src/spec/targets/armv7a_vex_v5.rs b/compiler/rustc_target/src/spec/targets/armv7a_vex_v5.rs index 6a5714b02fc6f..f661a5931e7a6 100644 --- a/compiler/rustc_target/src/spec/targets/armv7a_vex_v5.rs +++ b/compiler/rustc_target/src/spec/targets/armv7a_vex_v5.rs @@ -20,7 +20,7 @@ pub(crate) fn target() -> Target { exe_suffix: ".elf".into(), cpu: "cortex-a9".into(), abi: "eabihf".into(), - features: "+v7,+neon,+vfp3,+thumb2,+thumb-mode".into(), + features: "+v7,+neon,+vfp3,+thumb2".into(), linker: Some("rust-lld".into()), linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), link_script: Some(LINK_SCRIPT.into()), diff --git a/library/Cargo.lock b/library/Cargo.lock index 59b76d8d4427d..3e1cc8d88a9e4 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -348,6 +348,7 @@ dependencies = [ "rustc-demangle", "std_detect", "unwind", + "vex-sdk", "wasi", "windows-targets 0.0.0", ] @@ -415,6 +416,16 @@ dependencies = [ "rustc-std-workspace-core", ] +[[package]] +name = "vex-sdk" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f285bbc2b96fc4c7fae42ebe365dd2e9121e7002a58b1a9e0e4b1d14dba4d6d0" +dependencies = [ + "compiler_builtins", + "rustc-std-workspace-core", +] + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" From 834ab12dabc24ff3d235c30d8f14328967b11dc0 Mon Sep 17 00:00:00 2001 From: Tropical <42101043+Tropix126@users.noreply.github.com> Date: Thu, 5 Sep 2024 21:02:01 -0500 Subject: [PATCH 39/49] properly flush serial on abort --- library/std/src/sys/pal/vexos/mod.rs | 29 ++++++++++++++++---------- library/std/src/sys/pal/vexos/stdio.rs | 4 ++-- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/library/std/src/sys/pal/vexos/mod.rs b/library/std/src/sys/pal/vexos/mod.rs index 9c034252b7f9d..69599d03dc1c5 100644 --- a/library/std/src/sys/pal/vexos/mod.rs +++ b/library/std/src/sys/pal/vexos/mod.rs @@ -18,8 +18,10 @@ pub mod stdio; pub mod thread; pub mod time; -use crate::{arch::asm, ptr::{self, addr_of_mut}}; +use crate::arch::asm; use crate::hash::{DefaultHasher, Hasher}; +use crate::ptr::{self, addr_of_mut}; +use crate::time::{Duration, Instant}; #[cfg(not(test))] #[no_mangle] @@ -53,12 +55,8 @@ pub unsafe extern "C" fn _start() -> ! { #[link_section = ".code_signature"] #[linkage = "weak"] #[used] -static CODE_SIGNATURE: vex_sdk::vcodesig = vex_sdk::vcodesig { - magic: u32::from_le_bytes(*b"XVX5"), - r#type: 0, - owner: 2, - options: 0, -}; +static CODE_SIGNATURE: vex_sdk::vcodesig = + vex_sdk::vcodesig { magic: u32::from_le_bytes(*b"XVX5"), r#type: 0, owner: 2, options: 0 }; // This function is needed by the panic runtime. The symbol is named in // pre-link args for the target specification, so keep that in sync. @@ -94,8 +92,19 @@ pub fn decode_error_kind(_code: i32) -> crate::io::ErrorKind { } pub fn abort_internal() -> ! { + let exit_time = Instant::now(); + const FLUSH_TIMEOUT: Duration = Duration::from_millis(15); + unsafe { - vex_sdk::vexTasksRun(); + // Force the serial buffer to flush + while exit_time.elapsed() < FLUSH_TIMEOUT { + // If the buffer has been fully flushed, exit the loop + if vex_sdk::vexSerialWriteFree(stdio::STDIO_CHANNEL) == (stdio::STDOUT_BUF_SIZE as i32) + { + break; + } + vex_sdk::vexTasksRun(); + } vex_sdk::vexSystemExitRequest(); } @@ -107,9 +116,7 @@ pub fn abort_internal() -> ! { fn hash_time() -> u64 { let mut hasher = DefaultHasher::new(); // The closest we can get to a random number is the time since program start - let time = unsafe { - vex_sdk::vexSystemHighResTimeGet() - }; + let time = unsafe { vex_sdk::vexSystemHighResTimeGet() }; hasher.write_u64(time); hasher.finish() } diff --git a/library/std/src/sys/pal/vexos/stdio.rs b/library/std/src/sys/pal/vexos/stdio.rs index a9e05e3537f8d..57557ead13f63 100644 --- a/library/std/src/sys/pal/vexos/stdio.rs +++ b/library/std/src/sys/pal/vexos/stdio.rs @@ -4,7 +4,7 @@ pub struct Stdin(()); pub struct Stdout(()); pub struct Stderr(()); -const STDIO_CHANNEL: u32 = 1; +pub const STDIO_CHANNEL: u32 = 1; impl Stdin { pub const fn new() -> Stdin { @@ -81,7 +81,7 @@ impl io::Write for Stderr { } pub const STDIN_BUF_SIZE: usize = 4096; -const STDOUT_BUF_SIZE: usize = 2048; +pub const STDOUT_BUF_SIZE: usize = 2048; pub fn is_ebadf(_err: &io::Error) -> bool { true From 3a23f09b8a80d523e1d06ce46fe4ff3ba6da593e Mon Sep 17 00:00:00 2001 From: Tropical <42101043+Tropix126@users.noreply.github.com> Date: Sat, 7 Sep 2024 14:02:24 -0500 Subject: [PATCH 40/49] clarify documentation regarding cargo-v5, adjust `SystemTime` panic message --- compiler/rustc_target/src/spec/targets/armv7a_vex_v5.rs | 1 - library/std/src/sys/pal/vexos/mod.rs | 7 +++++-- library/std/src/sys/pal/vexos/time.rs | 2 +- src/doc/rustc/src/platform-support/armv7a-vex-v5.md | 6 ++++-- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_target/src/spec/targets/armv7a_vex_v5.rs b/compiler/rustc_target/src/spec/targets/armv7a_vex_v5.rs index f661a5931e7a6..d986132e251dd 100644 --- a/compiler/rustc_target/src/spec/targets/armv7a_vex_v5.rs +++ b/compiler/rustc_target/src/spec/targets/armv7a_vex_v5.rs @@ -17,7 +17,6 @@ pub(crate) fn target() -> Target { options: TargetOptions { os: "vexos".into(), vendor: "vex".into(), - exe_suffix: ".elf".into(), cpu: "cortex-a9".into(), abi: "eabihf".into(), features: "+v7,+neon,+vfp3,+thumb2".into(), diff --git a/library/std/src/sys/pal/vexos/mod.rs b/library/std/src/sys/pal/vexos/mod.rs index 69599d03dc1c5..421d4cb2c831a 100644 --- a/library/std/src/sys/pal/vexos/mod.rs +++ b/library/std/src/sys/pal/vexos/mod.rs @@ -37,8 +37,7 @@ pub unsafe extern "C" fn _start() -> ! { // Setup the stack asm!("ldr sp, =__stack_top", options(nostack)); - // VEXos doesn't explicitly clean out .bss, so as a sanity - // check we'll fill it with zeroes. + // VEXos doesn't explicitly clean out .bss. ptr::slice_from_raw_parts_mut( addr_of_mut!(__bss_start), addr_of_mut!(__bss_end).offset_from(addr_of_mut!(__bss_start)) as usize, @@ -52,6 +51,10 @@ pub unsafe extern "C" fn _start() -> ! { abort_internal() } +// The code signature is a 32 byte header at the start of user programs that +// identifies the owner and type of the program, as well as certain flags for +// program behavior dictated by the OS. In the event that the user wants to +// change this header, we use weak linkage so it can be overwritten. #[link_section = ".code_signature"] #[linkage = "weak"] #[used] diff --git a/library/std/src/sys/pal/vexos/time.rs b/library/std/src/sys/pal/vexos/time.rs index 94699d64d2307..60805ea2759d0 100644 --- a/library/std/src/sys/pal/vexos/time.rs +++ b/library/std/src/sys/pal/vexos/time.rs @@ -29,7 +29,7 @@ impl Instant { impl SystemTime { pub fn now() -> SystemTime { - panic!("time not implemented on this platform") + panic!("system time not implemented on this platform") } pub fn sub_time(&self, other: &SystemTime) -> Result { diff --git a/src/doc/rustc/src/platform-support/armv7a-vex-v5.md b/src/doc/rustc/src/platform-support/armv7a-vex-v5.md index de009d78cfcb6..4a0d82126163f 100644 --- a/src/doc/rustc/src/platform-support/armv7a-vex-v5.md +++ b/src/doc/rustc/src/platform-support/armv7a-vex-v5.md @@ -23,7 +23,7 @@ This target is cross-compiled. Dynamic linking is unsupported. `#![no_std]` crates can be built using `build-std` to build `core` and optionally `alloc`. Unwinding panics are not yet supported. -`std` is partially implemented, but many modules (such as `thread`, `process`, `net`, etc...) will return errors. An allocator is provided along with partial support for the `time`, `env` and `io` modules. Filesystem operations over SDCard through `std::fs` are partially supported within the restrictions of the user enviornment (e.g. directories cannot be created, filesystem objects cannot be removed). +`std` is partially implemented, but many modules (such as `thread`, `process`, `net`, etc...) will return errors. An allocator is provided along with partial support for the `time`, `env` and `io` modules. Filesystem operations over SDCard through `std::fs` are partially supported within the restrictions of the user environment (e.g. directories cannot be created, filesystem objects cannot be removed). This target generates binaries in the ELF format that may uploaded to the brain with external tools. @@ -44,7 +44,9 @@ build-std-features = ["compiler-builtins-mem"] ## Building Rust programs -The recommended way to build artifacts that run on V5 Brain is by using the [cargo-v5](https://github.com/vexide/cargo-v5) tool. This tool wraps the `cargo build` command by supplying arguments necessary to build the target, while also providing functionality for uploading over USB to a V5 Controller or Brain. +When the compiler builds a binary, an ELF build artifact will be produced. Additional tools are required for this artifact to be recognizable to VEXos as a user program. + +The [cargo-v5](https://github.com/vexide/cargo-v5) tool is capable of creating binaries that can be uploaded to the V5 brain. This tool wraps the `cargo build` command by supplying arguments necessary to build the target and produce an artifact recognizable to VEXos, while also providing functionality for uploading over USB to a V5 Controller or Brain. To install the tool, run: From 08998e9971eadcd2ee22d80fb8a6976e8321b051 Mon Sep 17 00:00:00 2001 From: Max Niederman Date: Tue, 8 Oct 2024 20:12:00 -0700 Subject: [PATCH 41/49] use aapcs as system abi --- compiler/rustc_target/src/spec/mod.rs | 6 ++++++ compiler/rustc_target/src/spec/targets/armv7a_vex_v5.rs | 1 + library/Cargo.lock | 4 ++-- library/std/Cargo.toml | 2 +- library/std/src/sys/pal/vexos/alloc.rs | 8 +++----- 5 files changed, 13 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index a7ef7ee8e55fd..c1a6de96a8bb9 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -2267,6 +2267,8 @@ pub struct TargetOptions { pub is_like_wasm: bool, /// Whether a target toolchain is like Android, implying a Linux kernel and a Bionic libc pub is_like_android: bool, + /// Whether a target toolchain is like VEXos. + pub is_like_vexos: bool, /// Default supported version of DWARF on this platform. /// Useful because some platforms (osx, bsd) only want up to DWARF2. pub default_dwarf_version: u32, @@ -2622,6 +2624,7 @@ impl Default for TargetOptions { is_like_msvc: false, is_like_wasm: false, is_like_android: false, + is_like_vexos: false, default_dwarf_version: 4, allows_weak_linkage: true, has_rpath: false, @@ -2729,6 +2732,7 @@ impl Target { Abi::System { unwind } if self.is_like_windows && self.arch == "x86" && !c_variadic => { Abi::Stdcall { unwind } } + Abi::System { unwind } if self.is_like_vexos && !c_variadic => Abi::Aapcs { unwind }, Abi::System { unwind } => Abi::C { unwind }, Abi::EfiApi if self.arch == "arm" => Abi::Aapcs { unwind: false }, Abi::EfiApi if self.arch == "x86_64" => Abi::Win64 { unwind: false }, @@ -3382,6 +3386,7 @@ impl Target { key!(is_like_msvc, bool); key!(is_like_wasm, bool); key!(is_like_android, bool); + key!(is_like_vexos, bool); key!(default_dwarf_version, u32); key!(allows_weak_linkage, bool); key!(has_rpath, bool); @@ -3662,6 +3667,7 @@ impl ToJson for Target { target_option_val!(is_like_msvc); target_option_val!(is_like_wasm); target_option_val!(is_like_android); + target_option_val!(is_like_vexos); target_option_val!(default_dwarf_version); target_option_val!(allows_weak_linkage); target_option_val!(has_rpath); diff --git a/compiler/rustc_target/src/spec/targets/armv7a_vex_v5.rs b/compiler/rustc_target/src/spec/targets/armv7a_vex_v5.rs index d986132e251dd..5451c0e12a8e1 100644 --- a/compiler/rustc_target/src/spec/targets/armv7a_vex_v5.rs +++ b/compiler/rustc_target/src/spec/targets/armv7a_vex_v5.rs @@ -16,6 +16,7 @@ pub(crate) fn target() -> Target { arch: "arm".into(), options: TargetOptions { os: "vexos".into(), + is_like_vexos: true, vendor: "vex".into(), cpu: "cortex-a9".into(), abi: "eabihf".into(), diff --git a/library/Cargo.lock b/library/Cargo.lock index 3e1cc8d88a9e4..01404b3cbada5 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -418,9 +418,9 @@ dependencies = [ [[package]] name = "vex-sdk" -version = "0.17.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f285bbc2b96fc4c7fae42ebe365dd2e9121e7002a58b1a9e0e4b1d14dba4d6d0" +checksum = "79ec210898aed247c0fb1ae4834b4648669050ae8275423a1ce5cc3d6f07649a" dependencies = [ "compiler_builtins", "rustc-std-workspace-core", diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 15de6f7a69b7e..d4b48784dd580 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -91,7 +91,7 @@ r-efi = { version = "4.5.0", features = ['rustc-dep-of-std'] } r-efi-alloc = { version = "1.0.0", features = ['rustc-dep-of-std'] } [target.'cfg(target_os = "vexos")'.dependencies] -vex-sdk = { version = "0.17.0", features = ['rustc-dep-of-std'] } +vex-sdk = { version = "0.21.0", features = ['rustc-dep-of-std'] } [features] backtrace = [ diff --git a/library/std/src/sys/pal/vexos/alloc.rs b/library/std/src/sys/pal/vexos/alloc.rs index f760ebef770f9..04d13e00a534d 100644 --- a/library/std/src/sys/pal/vexos/alloc.rs +++ b/library/std/src/sys/pal/vexos/alloc.rs @@ -1,8 +1,6 @@ -use crate::{ - alloc::{GlobalAlloc, Layout, System}, - ptr, - sync::atomic::{AtomicBool, Ordering}, -}; +use crate::alloc::{GlobalAlloc, Layout, System}; +use crate::ptr; +use crate::sync::atomic::{AtomicBool, Ordering}; static mut DLMALLOC: dlmalloc::Dlmalloc = dlmalloc::Dlmalloc::new_with_allocator(Vexos); From 23704a8607cef27b26fb95f03386ce36090f8441 Mon Sep 17 00:00:00 2001 From: Max Niederman Date: Tue, 8 Oct 2024 20:31:43 -0700 Subject: [PATCH 42/49] fix stack corruptions in startup routine --- .../spec/targets/armv7a_vex_v5_linker_script.ld | 8 ++------ library/std/src/sys/pal/vexos/mod.rs | 17 ++++++++++++----- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_target/src/spec/targets/armv7a_vex_v5_linker_script.ld b/compiler/rustc_target/src/spec/targets/armv7a_vex_v5_linker_script.ld index 37fc390401ead..63bca9d44168e 100644 --- a/compiler/rustc_target/src/spec/targets/armv7a_vex_v5_linker_script.ld +++ b/compiler/rustc_target/src/spec/targets/armv7a_vex_v5_linker_script.ld @@ -11,11 +11,7 @@ MEMORY { } __stack_length = 0x400000; -/* -It's currently unclear why subtracting anything is necessary, but it fixes memory permission errors. -0x100 is an arbitrary number that works. -*/ -__heap_end = __user_ram_end - __stack_length - 0x100; +__heap_end = __user_ram_end - __stack_length; SECTIONS { .text : { @@ -55,4 +51,4 @@ SECTIONS { /DISCARD/ : { *(.ARM.exidx) } -} \ No newline at end of file +} diff --git a/library/std/src/sys/pal/vexos/mod.rs b/library/std/src/sys/pal/vexos/mod.rs index 421d4cb2c831a..43275ba02d754 100644 --- a/library/std/src/sys/pal/vexos/mod.rs +++ b/library/std/src/sys/pal/vexos/mod.rs @@ -18,14 +18,24 @@ pub mod stdio; pub mod thread; pub mod time; -use crate::arch::asm; +use crate::arch::global_asm; use crate::hash::{DefaultHasher, Hasher}; use crate::ptr::{self, addr_of_mut}; use crate::time::{Duration, Instant}; +global_asm!( + r#" + .section .boot, "ax" + .global _boot + + _boot: + ldr sp, =__stack_top @ Set up the user stack. + b _start @ Jump to the Rust entrypoint. + "# +); + #[cfg(not(test))] #[no_mangle] -#[link_section = ".boot"] pub unsafe extern "C" fn _start() -> ! { extern "C" { static mut __bss_start: u8; @@ -34,9 +44,6 @@ pub unsafe extern "C" fn _start() -> ! { fn main() -> i32; } - // Setup the stack - asm!("ldr sp, =__stack_top", options(nostack)); - // VEXos doesn't explicitly clean out .bss. ptr::slice_from_raw_parts_mut( addr_of_mut!(__bss_start), From 9e466b693468959b4a44de8b7b3191f50ebf2aeb Mon Sep 17 00:00:00 2001 From: Max Niederman Date: Tue, 8 Oct 2024 21:13:40 -0700 Subject: [PATCH 43/49] fix thread locals --- library/std/src/sys/pal/vexos/mod.rs | 5 +++++ library/std/src/sys/thread_local/mod.rs | 1 + 2 files changed, 6 insertions(+) diff --git a/library/std/src/sys/pal/vexos/mod.rs b/library/std/src/sys/pal/vexos/mod.rs index 43275ba02d754..84f42d5dab7a5 100644 --- a/library/std/src/sys/pal/vexos/mod.rs +++ b/library/std/src/sys/pal/vexos/mod.rs @@ -55,6 +55,11 @@ pub unsafe extern "C" fn _start() -> ! { main(); + unsafe { + crate::sys::thread_local::destructors::run(); + } + crate::rt::thread_cleanup(); + abort_internal() } diff --git a/library/std/src/sys/thread_local/mod.rs b/library/std/src/sys/thread_local/mod.rs index 378296a5260c8..24e49f5ffe3df 100644 --- a/library/std/src/sys/thread_local/mod.rs +++ b/library/std/src/sys/thread_local/mod.rs @@ -90,6 +90,7 @@ pub(crate) mod guard { target_family = "wasm", target_os = "uefi", target_os = "zkvm", + target_os = "vexos", ))] { pub(crate) fn enable() { // FIXME: Right now there is no concept of "thread exit" on From a200a236eb6cb07e3a05e820eb2e1f8696746c8d Mon Sep 17 00:00:00 2001 From: Max Niederman Date: Tue, 8 Oct 2024 22:54:35 -0700 Subject: [PATCH 44/49] implement (shimmed) std::random --- library/std/src/sys/pal/vexos/mod.rs | 21 --------------------- library/std/src/sys/random/mod.rs | 2 ++ 2 files changed, 2 insertions(+), 21 deletions(-) diff --git a/library/std/src/sys/pal/vexos/mod.rs b/library/std/src/sys/pal/vexos/mod.rs index 84f42d5dab7a5..0fc76a8444468 100644 --- a/library/std/src/sys/pal/vexos/mod.rs +++ b/library/std/src/sys/pal/vexos/mod.rs @@ -1,4 +1,3 @@ -pub mod alloc; #[path = "../unsupported/args.rs"] pub mod args; pub mod env; @@ -19,7 +18,6 @@ pub mod thread; pub mod time; use crate::arch::global_asm; -use crate::hash::{DefaultHasher, Hasher}; use crate::ptr::{self, addr_of_mut}; use crate::time::{Duration, Instant}; @@ -55,11 +53,6 @@ pub unsafe extern "C" fn _start() -> ! { main(); - unsafe { - crate::sys::thread_local::destructors::run(); - } - crate::rt::thread_cleanup(); - abort_internal() } @@ -127,17 +120,3 @@ pub fn abort_internal() -> ! { crate::hint::spin_loop() } } - -fn hash_time() -> u64 { - let mut hasher = DefaultHasher::new(); - // The closest we can get to a random number is the time since program start - let time = unsafe { vex_sdk::vexSystemHighResTimeGet() }; - hasher.write_u64(time); - hasher.finish() -} - -pub fn hashmap_random_keys() -> (u64, u64) { - let key1 = hash_time(); - let key2 = hash_time(); - (key1, key2) -} diff --git a/library/std/src/sys/random/mod.rs b/library/std/src/sys/random/mod.rs index d625814d15b39..789f541db6969 100644 --- a/library/std/src/sys/random/mod.rs +++ b/library/std/src/sys/random/mod.rs @@ -73,6 +73,7 @@ cfg_if::cfg_if! { } else if #[cfg(any( all(target_family = "wasm", target_os = "unknown"), target_os = "xous", + target_os = "vexos", ))] { // FIXME: finally remove std support for wasm32-unknown-unknown // FIXME: add random data generation to xous @@ -86,6 +87,7 @@ cfg_if::cfg_if! { target_os = "android", all(target_family = "wasm", target_os = "unknown"), target_os = "xous", + target_os = "vexos", )))] pub fn hashmap_random_keys() -> (u64, u64) { let mut buf = [0; 16]; From 8632a350c1b9379cba8949bc32d02a422a5b0840 Mon Sep 17 00:00:00 2001 From: Max Niederman Date: Tue, 8 Oct 2024 22:54:49 -0700 Subject: [PATCH 45/49] fix allocation --- library/std/src/sys/alloc/mod.rs | 2 ++ library/std/src/sys/{pal/vexos/alloc.rs => alloc/vexos.rs} | 3 +++ 2 files changed, 5 insertions(+) rename library/std/src/sys/{pal/vexos/alloc.rs => alloc/vexos.rs} (97%) diff --git a/library/std/src/sys/alloc/mod.rs b/library/std/src/sys/alloc/mod.rs index 2c0b533a5703f..1a41fa9f3adfc 100644 --- a/library/std/src/sys/alloc/mod.rs +++ b/library/std/src/sys/alloc/mod.rs @@ -90,5 +90,7 @@ cfg_if::cfg_if! { mod xous; } else if #[cfg(target_os = "zkvm")] { mod zkvm; + } else if #[cfg(target_os = "vexos")] { + mod vexos; } } diff --git a/library/std/src/sys/pal/vexos/alloc.rs b/library/std/src/sys/alloc/vexos.rs similarity index 97% rename from library/std/src/sys/pal/vexos/alloc.rs rename to library/std/src/sys/alloc/vexos.rs index 04d13e00a534d..e1033f4a62cfd 100644 --- a/library/std/src/sys/pal/vexos/alloc.rs +++ b/library/std/src/sys/alloc/vexos.rs @@ -1,3 +1,6 @@ +// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +#![allow(static_mut_refs)] + use crate::alloc::{GlobalAlloc, Layout, System}; use crate::ptr; use crate::sync::atomic::{AtomicBool, Ordering}; From ee08567ad23b73a4002bc8043fb9e7edc1f07cc5 Mon Sep 17 00:00:00 2001 From: Tropical <42101043+Tropix126@users.noreply.github.com> Date: Thu, 10 Oct 2024 20:30:49 -0500 Subject: [PATCH 46/49] update linkerscript to include unwinding-related sections --- .../targets/armv7a_vex_v5_linker_script.ld | 54 ++++++++++++++----- 1 file changed, 42 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_target/src/spec/targets/armv7a_vex_v5_linker_script.ld b/compiler/rustc_target/src/spec/targets/armv7a_vex_v5_linker_script.ld index 63bca9d44168e..1a7a8d2e38b75 100644 --- a/compiler/rustc_target/src/spec/targets/armv7a_vex_v5_linker_script.ld +++ b/compiler/rustc_target/src/spec/targets/armv7a_vex_v5_linker_script.ld @@ -1,34 +1,40 @@ OUTPUT_FORMAT("elf32-littlearm") -ENTRY(_start) +ENTRY(_boot) __user_ram_start = 0x03800000; __user_ram_length = 0x04800000; __user_ram_end = __user_ram_start + __user_ram_length; -MEMORY { - USER_RAM : ORIGIN = __user_ram_start, LENGTH = __user_ram_length -} +__code_signature_length = 0x20; __stack_length = 0x400000; __heap_end = __user_ram_end - __stack_length; +__eh_frame_hdr_start = SIZEOF(.eh_frame_hdr) > 0 ? ADDR(.eh_frame_hdr) : 0; +__eh_frame_hdr_end = SIZEOF(.eh_frame_hdr) > 0 ? . : 0; + +MEMORY { + USER_RAM : ORIGIN = __user_ram_start, LENGTH = __user_ram_length +} + SECTIONS { - .text : { - __text_start = .; + .code_signature : { KEEP(*(.code_signature)) - . = __text_start + 0x20; + . = __user_ram_start + __code_signature_length; + } > USER_RAM + + .text : { *(.boot) *(.text .text.*) - } > USER_RAM = 0 + } > USER_RAM - .rodata1 : { - *(.rodata1 .rodata1.*) + .rodata : { + *(.rodata .rodata.*) } > USER_RAM .data : { *(.data .data.*) - *(.data1 .data1.*) } > USER_RAM .bss : { @@ -37,6 +43,30 @@ SECTIONS { __bss_end = .; } > USER_RAM + /* The unwind tables enabled by "default-uwtable" in the target file live here. */ + /* __eh_frame_start and similar symbols are used by libunwind. */ + .eh_frame_hdr : { + KEEP(*(.eh_frame_hdr)) + } > USER_RAM + + .eh_frame : { + __eh_frame_start = .; + KEEP(*(.eh_frame)) + __eh_frame_end = .; + } > USER_RAM + + .ARM.exidx : { + __exidx_start = .; + *(.ARM.exidx*) + __exidx_end = .; + } > USER_RAM + + .ARM.extab : { + __extab_start = .; + *(.ARM.extab*) + __extab_end = .; + } > USER_RAM + .heap (NOLOAD) : ALIGN(4) { __heap_start = .; . = __heap_end; @@ -49,6 +79,6 @@ SECTIONS { } > USER_RAM /DISCARD/ : { - *(.ARM.exidx) + *(.ARM.attributes*) } } From a86a06978f63e1ef9bb11d325ab6d632f961b72b Mon Sep 17 00:00:00 2001 From: Max Niederman Date: Thu, 10 Oct 2024 22:09:42 -0700 Subject: [PATCH 47/49] format target doc and reorder maintainer list --- src/doc/rustc/src/platform-support/armv7a-vex-v5.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/doc/rustc/src/platform-support/armv7a-vex-v5.md b/src/doc/rustc/src/platform-support/armv7a-vex-v5.md index 4a0d82126163f..e20fd539bb55b 100644 --- a/src/doc/rustc/src/platform-support/armv7a-vex-v5.md +++ b/src/doc/rustc/src/platform-support/armv7a-vex-v5.md @@ -2,7 +2,6 @@ **Tier: 3** - Allows compiling user programs for the [VEX V5 Brain](https://www.vexrobotics.com/276-4810.html), a microcontroller for educational and competitive robotics. Rust support for this target is not affiliated with VEX Robotics or IFI. @@ -11,9 +10,9 @@ Rust support for this target is not affiliated with VEX Robotics or IFI. This target is maintained by members of the [vexide](https://github.com/vexide) organization: +- [@max-niederman](https://github.com/max-niederman) - [@Tropix126](https://github.com/Tropix126) - [@Gavin-Niederman](https://github.com/Gavin-Niederman) -- [@max-niederman](https://github.com/max-niederman) - [@doinkythederp](https://github.com/doinkythederp) ## Requirements @@ -90,4 +89,4 @@ The Rust test suite for `library/std` is not yet supported. This target can be cross-compiled from any host. -This target does not link to C libraries. OS calls are implemented in rust through the [vex-sdk](https://github.com/vexide/vex-sdk) crate. No `libc` or crt0 implementation is present on this target. \ No newline at end of file +This target does not link to C libraries. OS calls are implemented in rust through the [vex-sdk](https://github.com/vexide/vex-sdk) crate. No `libc` or crt0 implementation is present on this target. From bc40dcd61a58970a19cd7b2ba1db6fbba55c4e45 Mon Sep 17 00:00:00 2001 From: Max Niederman Date: Thu, 10 Oct 2024 22:11:43 -0700 Subject: [PATCH 48/49] bump vex-sdk version and allow vex-sdk to be a stdlib dep --- library/Cargo.lock | 6 +++--- library/std/Cargo.toml | 2 +- src/tools/tidy/src/deps.rs | 1 + 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/library/Cargo.lock b/library/Cargo.lock index 01404b3cbada5..d7eb0525c30d6 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "addr2line" @@ -418,9 +418,9 @@ dependencies = [ [[package]] name = "vex-sdk" -version = "0.21.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79ec210898aed247c0fb1ae4834b4648669050ae8275423a1ce5cc3d6f07649a" +checksum = "40b1777b4e4a60f9fed09417dafdc4a6a3393a67df1bd02c3b589770d906cff3" dependencies = [ "compiler_builtins", "rustc-std-workspace-core", diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index d4b48784dd580..0b289c6118c4b 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -91,7 +91,7 @@ r-efi = { version = "4.5.0", features = ['rustc-dep-of-std'] } r-efi-alloc = { version = "1.0.0", features = ['rustc-dep-of-std'] } [target.'cfg(target_os = "vexos")'.dependencies] -vex-sdk = { version = "0.21.0", features = ['rustc-dep-of-std'] } +vex-sdk = { version = "0.22.0", features = ['rustc-dep-of-std'] } [features] backtrace = [ diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 5163f039a2329..aab8b0e497341 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -495,6 +495,7 @@ const PERMITTED_STDLIB_DEPENDENCIES: &[&str] = &[ "shlex", "unicode-width", "unwinding", + "vex-sdk", "wasi", "windows-sys", "windows-targets", From 64c05d2f7991a44313302f13794ae333add51e23 Mon Sep 17 00:00:00 2001 From: Max Niederman Date: Thu, 10 Oct 2024 22:14:13 -0700 Subject: [PATCH 49/49] add assembly test for armv7a-vex-v5 --- tests/assembly/targets/targets-elf.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/assembly/targets/targets-elf.rs b/tests/assembly/targets/targets-elf.rs index f26d06a0ecb87..7593db273f84f 100644 --- a/tests/assembly/targets/targets-elf.rs +++ b/tests/assembly/targets/targets-elf.rs @@ -177,6 +177,9 @@ //@ revisions: armv7a_none_eabihf //@ [armv7a_none_eabihf] compile-flags: --target armv7a-none-eabihf //@ [armv7a_none_eabihf] needs-llvm-components: arm +//@ revisions: armv7a_vex_v5 +//@ [armv7a_vex_v5] compile-flags: --target armv7a-vex-v5 +//@ [armv7a_vex_v5] needs-llvm-components: arm //@ revisions: armv7r_none_eabi //@ [armv7r_none_eabi] compile-flags: --target armv7r-none-eabi //@ [armv7r_none_eabi] needs-llvm-components: arm