From 46cdc3714ec8be44dc2cbff614aae4993fd78284 Mon Sep 17 00:00:00 2001 From: Julien THILLARD Date: Tue, 17 Mar 2026 18:29:00 +0100 Subject: [PATCH] Add the rust std as a custom sysroot --- .cargo/config.toml | 3 +- .gitignore | 2 + .gitmodules | 3 + Cargo.toml | 3 +- crates/bffs/src/lib.rs | 1 + crates/kernel-macros/Cargo.toml | 2 +- crates/os-std-macros/Cargo.toml | 12 - crates/os-std-macros/src/lib.rs | 1 - crates/os-std/Cargo.toml | 9 - crates/os-std/src/io.rs | 1 - crates/os-std/src/lib.rs | 62 ---- crates/os-std/src/prelude.rs | 5 - crates/shared/src/fs.rs | 26 +- crates/shared/src/syscall.rs | 43 ++- ilm.ld | 2 +- justfile | 15 +- library/.gitignore | 17 + library/Cargo.toml | 88 +++++ library/backtrace | 1 + library/justfile | 319 +++++++++++++++++++ library/std/.gitignore | 109 +++++++ library/std/Cargo.toml | 177 ++++++++++ library/std/patches/sys/args/mod.sed | 4 + library/std/patches/sys/io/error/mod.sed | 1 + library/std/patches/sys/pal/mod.sed | 6 + library/std/patches/sys/random/mod.sed | 2 + library/std/patches/sys/thread_local/mod.sed | 6 + library/std/riscv64.json | 22 ++ library/std/src/sys/pal/survos.rs | 11 + riscv64.json | 2 +- src/drivers.rs | 2 + src/drivers/keyboard.rs | 67 ++++ src/drivers/mouse.rs | 38 +++ src/fs.rs | 2 +- src/interrupt.rs | 27 +- src/keymap.rs | 2 +- src/main.rs | 125 +------- src/process.rs | 90 ++++-- src/scheduler.rs | 10 +- src/user.rs | 5 +- src/virtio/input.rs | 3 + src/virtual_console.rs | 2 - src/virtual_fs.rs | 8 +- src/virtual_fs/null.rs | 51 +++ sysroot/lib/rustlib/src/rust/library/library | 1 + user.ld | 35 -- user/shell/Cargo.toml | 9 + user/shell/src/main.rs | 9 + user/test_pic/Cargo.toml | 5 +- user/test_pic/src/main.rs | 32 +- 50 files changed, 1158 insertions(+), 320 deletions(-) create mode 100644 .gitmodules delete mode 100644 crates/os-std-macros/Cargo.toml delete mode 100644 crates/os-std-macros/src/lib.rs delete mode 100644 crates/os-std/Cargo.toml delete mode 100644 crates/os-std/src/io.rs delete mode 100644 crates/os-std/src/lib.rs delete mode 100644 crates/os-std/src/prelude.rs create mode 100644 library/.gitignore create mode 100644 library/Cargo.toml create mode 160000 library/backtrace create mode 100644 library/justfile create mode 100644 library/std/.gitignore create mode 100644 library/std/Cargo.toml create mode 100644 library/std/patches/sys/args/mod.sed create mode 100644 library/std/patches/sys/io/error/mod.sed create mode 100644 library/std/patches/sys/pal/mod.sed create mode 100644 library/std/patches/sys/random/mod.sed create mode 100644 library/std/patches/sys/thread_local/mod.sed create mode 100644 library/std/riscv64.json create mode 100644 library/std/src/sys/pal/survos.rs create mode 100644 src/drivers.rs create mode 100644 src/drivers/keyboard.rs create mode 100644 src/drivers/mouse.rs create mode 100644 src/virtual_fs/null.rs create mode 120000 sysroot/lib/rustlib/src/rust/library/library delete mode 100644 user.ld create mode 100644 user/shell/Cargo.toml create mode 100644 user/shell/src/main.rs diff --git a/.cargo/config.toml b/.cargo/config.toml index f072b50..41f20d6 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -3,10 +3,9 @@ target = "riscv64.json" [unstable] json-target-spec = true -build-std = ["core", "compiler_builtins", "alloc"] -build-std-features = ["compiler-builtins-mem"] [target.riscv64] rustflags = [ "-C", "link-arg=-Tilm.ld", + "--sysroot", "sysroot" ] diff --git a/.gitignore b/.gitignore index 55983a2..6ea937b 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,5 @@ disk.img **/*.mem mnt + +sysroot/lib/rustlib/riscv64 diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..22a9e10 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "library/backtrace"] + path = library/backtrace + url = https://github.com/rust-lang/backtrace-rs.git diff --git a/Cargo.toml b/Cargo.toml index 9d2d114..3840326 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,7 @@ [workspace] resolver = "3" -members = ["crates/bytes-struct","crates/io","crates/os-std", "crates/shared", "user/*"] +members = [ "user/*"] +exclude = ["library"] [package] name = "kernel-rust" diff --git a/crates/bffs/src/lib.rs b/crates/bffs/src/lib.rs index ba52fb0..1bd1a59 100644 --- a/crates/bffs/src/lib.rs +++ b/crates/bffs/src/lib.rs @@ -1,4 +1,5 @@ #![feature(iterator_try_collect, iter_order_by)] +#![allow(unused_features)] #![cfg_attr(any(not(feature = "std"), target_arch = "riscv64"), no_std)] use core::cell::RefCell; diff --git a/crates/kernel-macros/Cargo.toml b/crates/kernel-macros/Cargo.toml index 5832c35..ae9e488 100644 --- a/crates/kernel-macros/Cargo.toml +++ b/crates/kernel-macros/Cargo.toml @@ -7,6 +7,6 @@ edition = "2024" proc-macro = true [dependencies] -image = "0.25" +image = { version = "0.25", default-features = false, features = ["png"] } syn = { version = "2", features = ["full"] } zyn = "0.5" diff --git a/crates/os-std-macros/Cargo.toml b/crates/os-std-macros/Cargo.toml deleted file mode 100644 index 77bc004..0000000 --- a/crates/os-std-macros/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name = "os-std-macros" -version = "0.1.0" -edition = "2024" - -[lib] -proc-macro = true - -[dependencies] -proc-macro2 = "1" -quote = "1" -syn = { version = "2", features = ["full"] } diff --git a/crates/os-std-macros/src/lib.rs b/crates/os-std-macros/src/lib.rs deleted file mode 100644 index 8b13789..0000000 --- a/crates/os-std-macros/src/lib.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/crates/os-std/Cargo.toml b/crates/os-std/Cargo.toml deleted file mode 100644 index d2575ec..0000000 --- a/crates/os-std/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "os-std" -version = "0.1.0" -edition = "2024" - -[dependencies] -os-std-macros = { path = "../os-std-macros" } -shared = { path = "../shared", features = ["user"] } -io = { path = "../io", features = ["alloc"] } diff --git a/crates/os-std/src/io.rs b/crates/os-std/src/io.rs deleted file mode 100644 index 079c8bb..0000000 --- a/crates/os-std/src/io.rs +++ /dev/null @@ -1 +0,0 @@ -pub use io::SeekFrom; diff --git a/crates/os-std/src/lib.rs b/crates/os-std/src/lib.rs deleted file mode 100644 index 8797a23..0000000 --- a/crates/os-std/src/lib.rs +++ /dev/null @@ -1,62 +0,0 @@ -#![no_std] - -extern crate alloc; - -pub mod io; -pub mod prelude; - -pub use shared::fs; -pub use shared::syscall; - -#[macro_export] -macro_rules! custom_std_setup { - () => { - use $crate::prelude::*; - - extern crate alloc; - - struct GlobalAllocator; - - #[global_allocator] - static GLOBAL_ALLOCATOR: GlobalAllocator = GlobalAllocator; - - unsafe impl core::alloc::GlobalAlloc for GlobalAllocator { - unsafe fn alloc(&self, layout: core::alloc::Layout) -> *mut u8 { - $crate::syscall::alloc(layout) - } - - unsafe fn dealloc(&self, ptr: *mut u8, layout: core::alloc::Layout) { - $crate::syscall::dealloc(ptr, layout) - } - } - - #[panic_handler] - fn panic(_panic_info: &core::panic::PanicInfo) -> ! { - // TODO print - loop {} - } - - #[unsafe(no_mangle)] - pub extern "C" fn _start() { - main() - } - }; -} - -#[macro_export] -macro_rules! print { - ($($args:expr),*) => { - $crate::syscall::write_string_temp(&format!($($args),*)) - }; -} -#[macro_export] -macro_rules! println { - () => { - $crate::print!(""); - // $crate::print!("\n\r"); - }; - ($($args:expr),*) => { - $crate::print!($($args),*); - // $crate::println!(); - }; -} diff --git a/crates/os-std/src/prelude.rs b/crates/os-std/src/prelude.rs deleted file mode 100644 index 48ffcc0..0000000 --- a/crates/os-std/src/prelude.rs +++ /dev/null @@ -1,5 +0,0 @@ -pub use crate::print; -pub use crate::println; -pub use alloc::format; -pub use alloc::string::String; -pub use alloc::vec; diff --git a/crates/shared/src/fs.rs b/crates/shared/src/fs.rs index b8f3fcc..45b6831 100644 --- a/crates/shared/src/fs.rs +++ b/crates/shared/src/fs.rs @@ -1,3 +1,7 @@ +use io::{IoBase, Read, Write}; + +use crate::syscall; + #[derive(Debug)] pub struct File { fd: u64, @@ -6,7 +10,7 @@ pub struct File { impl File { /// # Safety /// The file descriptor must be valid - pub unsafe fn new(fd: u64) -> Self { + pub unsafe fn from_raw_fd(fd: u64) -> Self { Self { fd } } @@ -14,3 +18,23 @@ impl File { self.fd } } + +impl IoBase for File { + type Error = (); +} + +impl Read for File { + fn read(&mut self, buf: &mut [u8]) -> Result { + Ok(syscall::read(self.as_fd(), buf) as usize) + } +} + +impl Write for File { + fn write(&mut self, buf: &[u8]) -> Result { + Ok(syscall::write(self.as_fd(), buf) as usize) + } + + fn flush(&mut self) -> Result<(), Self::Error> { + todo!() + } +} diff --git a/crates/shared/src/syscall.rs b/crates/shared/src/syscall.rs index cdbdf46..9d02301 100644 --- a/crates/shared/src/syscall.rs +++ b/crates/shared/src/syscall.rs @@ -10,9 +10,12 @@ pub enum SysCall { Read = 0, Write = 1, Open = 2, + Close = 3, Seek = 8, Alloc = 40, Dealloc = 41, + Spawn = 58, + ExecVE = 59, Exit = 60, NanoSleep = 101, WriteIntTemp = 998, @@ -26,9 +29,12 @@ impl From for SysCall { 0 => SysCall::Read, 1 => SysCall::Write, 2 => SysCall::Open, + 3 => SysCall::Close, 8 => SysCall::Seek, 40 => SysCall::Alloc, 41 => SysCall::Dealloc, + 58 => SysCall::Spawn, + 59 => SysCall::ExecVE, 60 => SysCall::Exit, 101 => SysCall::NanoSleep, 998 => SysCall::WriteIntTemp, @@ -143,30 +149,53 @@ pub fn open>(path: P) -> File { let ptr = path_str.as_ptr(); let size = path_str.len(); let (fd, ..) = syscall!(SysCall::Open, ptr as u64, size as u64); - File::new(fd) + File::from_raw_fd(fd) } } -pub fn write(file: &mut File, buf: &[u8]) { +pub fn close(file_descriptor: u64) { + unsafe { + syscall!(SysCall::Close, file_descriptor); + } +} +pub fn write(file_descriptor: u64, buf: &[u8]) -> u64 { unsafe { let ptr = buf.as_ptr(); let size = buf.len(); - syscall!(SysCall::Write, file.as_fd(), ptr as u64, size as u64); + let (len, ..) = syscall!(SysCall::Write, file_descriptor, ptr as u64, size as u64); + len } } -pub fn read(file: &mut File, buf: &mut [u8]) { +pub fn read(file_descriptor: u64, buf: &mut [u8]) -> u64 { unsafe { let ptr = buf.as_ptr(); let size = buf.len(); - syscall!(SysCall::Read, file.as_fd(), ptr as u64, size as u64); + let (len, ..) = syscall!(SysCall::Read, file_descriptor, ptr as u64, size as u64); + len } } -pub fn seek(file: &mut File, seek: SeekFrom) { +pub fn seek(file_descriptor: u64, seek: SeekFrom) { unsafe { let (discriminant, value) = match seek { SeekFrom::Start(v) => (0, v), SeekFrom::End(v) => (1, v as u64), SeekFrom::Current(v) => (2, v as u64), }; - syscall!(SysCall::Seek, file.as_fd(), discriminant, value); + syscall!(SysCall::Seek, file_descriptor, discriminant, value); + } +} +pub fn spawn>(path: P) { + unsafe { + let path_str = path.as_ref().as_str(); + let ptr = path_str.as_ptr(); + let size = path_str.len(); + syscall!(SysCall::Spawn, ptr as u64, size as u64); + } +} +pub fn execve>(path: P) { + unsafe { + let path_str = path.as_ref().as_str(); + let ptr = path_str.as_ptr(); + let size = path_str.len(); + syscall!(SysCall::ExecVE, ptr as u64, size as u64); } } diff --git a/ilm.ld b/ilm.ld index 4ada6b1..5bf4e02 100644 --- a/ilm.ld +++ b/ilm.ld @@ -5,7 +5,7 @@ OUTPUT_ARCH(riscv) ENTRY(_start) MEMORY { - RAM (wxa) : ORIGIN = 0x80000000, LENGTH = 128M + RAM (wxa) : ORIGIN = 0x80000000, LENGTH = 512M } SECTIONS { diff --git a/justfile b/justfile index 8b85fee..c2753dc 100644 --- a/justfile +++ b/justfile @@ -12,13 +12,19 @@ mount_filesystem: sync_filesystem: sync +update-std: + @cd library/std && just update-std + +build-sysroot: + @cd library/std && just build-sysroot + build_user_prog prog: - RUSTFLAGS="-C relocation-model=pic -C link-arg=-Tuser.ld -C link-arg=-pie" cargo b {{ cargo_flags }} --package {{ prog }} + RUSTFLAGS="-C relocation-model=pic -C link-arg=-pie --sysroot {{ justfile_directory() / "sysroot" }}" cargo b {{ cargo_flags }} --package {{ prog }} riscv64-elf-strip {{ bin_path / prog }} cp {{ bin_path / prog }} {{ "mnt/usr/bin" / prog }} build: mount_filesystem (map_dir "user" f"just release=\"{{release}}\" cargo_flags=\"{{cargo_flags}}\" build_user_prog") - cargo b {{ cargo_flags }} + RUSTFLAGS="-Clink-arg=-Tilm.ld --sysroot {{ justfile_directory() / "sysroot" }}" cargo b {{ cargo_flags }} just sync_filesystem run: build (runner f"{{bin_path / "kernel-rust"}}") @@ -34,8 +40,8 @@ qemu := f"qemu-system-riscv64 \ -device bochs-display \ -device virtio-keyboard-pci \ -device virtio-mouse-pci \ - -device loader,file=disk.img,addr=0x90000000 \ - -bios none -m 512M {{qemu_flags}}" + -device loader,file=disk.img,addr=0xA0000000 \ + -bios none -m 1024M {{qemu_flags}}" # -trace \"virtio*\" # -d guest_errors,unimp,int" @@ -53,4 +59,5 @@ runner args: {{ qemu }} -kernel {{ args }} clean: + cd library && just clean cargo clean diff --git a/library/.gitignore b/library/.gitignore new file mode 100644 index 0000000..efc0ca5 --- /dev/null +++ b/library/.gitignore @@ -0,0 +1,17 @@ +portable-simd +core_arch +core +compiler-builtins +alloc +stdarch +unwind +std_detect +panic_abort +panic_unwind +rustc-std-workspace-alloc +rustc-std-workspace-core +rustc-std-workspace-std +windows_link +profiler_builtins +test +proc_macro diff --git a/library/Cargo.toml b/library/Cargo.toml new file mode 100644 index 0000000..ab037e8 --- /dev/null +++ b/library/Cargo.toml @@ -0,0 +1,88 @@ + +cargo-features = ["profile-rustflags"] + +[workspace] +resolver = "1" +members = [ + "std", + # "sysroot", + # "coretests", + # "alloctests", +] + +exclude = [ + # stdarch has its own Cargo workspace + "stdarch", + "windows_link" +] + +[profile.release.package.compiler_builtins] +# For compiler-builtins we always use a high number of codegen units. +# The goal here is to place every single intrinsic into its own object +# file to avoid symbol clashes with the system libgcc if possible. Note +# that this number doesn't actually produce this many object files, we +# just don't create more than this number of object files. +# +# It's a bit of a bummer that we have to pass this here, unfortunately. +# Ideally this would be specified through an env var to Cargo so Cargo +# knows how many CGUs are for this specific crate, but for now +# per-crate configuration isn't specifiable in the environment. +codegen-units = 10000 + +# These dependencies of the standard library implement symbolication for +# backtraces on most platforms. Their debuginfo causes both linking to be slower +# (more data to chew through) and binaries to be larger without really all that +# much benefit. This section turns them all to down to have no debuginfo which +# helps to improve link times a little bit. +[profile.release.package] +addr2line.debug = 0 +addr2line.opt-level = "s" +adler2.debug = 0 +gimli.debug = 0 +gimli.opt-level = "s" +miniz_oxide.debug = 0 +miniz_oxide.opt-level = "s" +# `opt-level = "s"` for `object` led to a size regression when tried previously +object.debug = 0 +rustc-demangle.debug = 0 +rustc-demangle.opt-level = "s" + +# panic_abort must always be compiled with panic=abort, even when the rest of the +# sysroot is panic=unwind. +[profile.dev.package.panic_abort] +rustflags = ["-Cpanic=abort"] + +[profile.release.package.panic_abort] +rustflags = ["-Cpanic=abort"] + +# The "dist" profile is used by bootstrap for prebuilt libstd artifacts +# These settings ensure that the prebuilt artifacts support a variety of features +# in the user's profile. +[profile.dist] +inherits = "release" +codegen-units = 1 +debug = 1 # "limited" +rustflags = [ + # `profile.lto=off` implies `-Cembed-bitcode=no`, but unconditionally embedding + # bitcode is necessary for when users enable LTO. + # Required until Cargo can re-build the standard library based on the value + # of `profile.lto` in the user's profile. + "-Cembed-bitcode=yes", + # Enable frame pointers + "-Zunstable-options", + "-Cforce-frame-pointers=non-leaf", +] + +[profile.dist.package.panic_abort] +rustflags = [ + "-Cpanic=abort", + "-Cembed-bitcode=yes", + "-Zunstable-options", + "-Cforce-frame-pointers=non-leaf", +] + +[patch.crates-io] +# See comments in `library/rustc-std-workspace-core/README.md` for what's going on here +rustc-std-workspace-core = { path = 'rustc-std-workspace-core' } +rustc-std-workspace-alloc = { path = 'rustc-std-workspace-alloc' } +# rustc-std-workspace-std = { path = 'rustc-std-workspace-std' } diff --git a/library/backtrace b/library/backtrace new file mode 160000 index 0000000..28ec93b --- /dev/null +++ b/library/backtrace @@ -0,0 +1 @@ +Subproject commit 28ec93b503bf0410745bc3d571bf3dc1caac3019 diff --git a/library/justfile b/library/justfile new file mode 100644 index 0000000..c0d1165 --- /dev/null +++ b/library/justfile @@ -0,0 +1,319 @@ +SRC_DIR := "std/src" +PATCH_DIR := "std/patches" +RUST_SRC := `rustc --print sysroot` / "lib/rustlib/src/rust/library" + +patch-std: + @echo "Start patching the std..." + @find {{ PATCH_DIR }} -type f | while read -r patch_file; do \ + relative_path="${patch_file#{{ PATCH_DIR }}/}"; \ + target_file="${relative_path%.sed}.rs"; \ + if [ -f "{{ SRC_DIR }}/$target_file" ]; then \ + echo " [SED] $target_file"; \ + sed -i -f "$patch_file" "{{ SRC_DIR }}/$target_file"; \ + else \ + echo "⚠ [WARN] target doesn't exist: $target_file"; \ + fi; \ + done + @echo "✅ Patching done." + +update-std: + @just setup-std + @just patch-std + +cp_std path: + @echo "Linking {{ path }}" + @mkdir {{ "std/src" / parent_directory(path) }} -p + @ln -fs {{ RUST_SRC / "std/src" / path }} {{ "std/src" / parent_directory(path) }} + +real_cp_std path: + @echo "Copying {{ path }}" + @mkdir {{ "std/src" / parent_directory(path) }} -p + @cp {{ RUST_SRC / "std/src" / path }} {{ "std/src" / path }} + +setup-std: + ln -fs {{ RUST_SRC / "std_detect" }} "." + ln -fs {{ RUST_SRC / "panic_abort" }} "." + ln -fs {{ RUST_SRC / "panic_unwind" }} "." + ln -fs {{ RUST_SRC / "windows_link" }} "." + ln -fs {{ RUST_SRC / "unwind" }} "." + ln -fs {{ RUST_SRC / "alloc" }} "." + ln -fs {{ RUST_SRC / "rustc-std-workspace-alloc" }} "." + ln -fs {{ RUST_SRC / "rustc-std-workspace-core" }} "." + ln -fs {{ RUST_SRC / "rustc-std-workspace-std" }} "." + ln -fs {{ RUST_SRC / "compiler-builtins" }} "." + ln -fs {{ RUST_SRC / "core" }} "." + ln -fs {{ RUST_SRC / "stdarch" }} "." + ln -fs {{ RUST_SRC / "portable-simd" }} "." + ln -fs {{ RUST_SRC / "proc_macro" }} "." + ln -fs {{ RUST_SRC / "profiler_builtins" }} "." + ln -fs {{ RUST_SRC / "test" }} "." + + @just cp_std "../build.rs" + @sed -i "59a\ || target_os == \"survos\"" std/build.rs + + @just cp_std "alloc.rs" + @just cp_std "ascii.rs" + @just cp_std "backtrace.rs" + @just cp_std "bstr.rs" + @just cp_std "env.rs" + @just cp_std "error.rs" + @just cp_std "fs.rs" + @just cp_std "keyword_docs.rs" + @just cp_std "lib.rs" + @just cp_std "macros.rs" + @just cp_std "panic.rs" + @just cp_std "panicking.rs" + @just cp_std "pat.rs" + @just cp_std "path.rs" + @just cp_std "process.rs" + @just cp_std "random.rs" + @just cp_std "rt.rs" + @just cp_std "tests_helpers.rs" + @just cp_std "time.rs" + + @just cp_std "backtrace" + + @just cp_std "collections" + + @just cp_std "ffi" + + @just cp_std "fs" + + @just cp_std "hash" + + @just cp_std "io" + + @just cp_std "net" + + @just cp_std "num" + + @just cp_std "os/raw/mod.rs" + @just cp_std "os/raw/tests.rs" + @just cp_std "os/mod.rs" + + @just cp_std "prelude" + + @just cp_std "process" + + @just cp_std "sync" + + @just cp_std "sys/alloc/mod.rs" + + @just real_cp_std "sys/args/mod.rs" + @just cp_std "sys/args/unsupported.rs" + + @just cp_std "sys/env/mod.rs" + @just cp_std "sys/env/common.rs" + @just cp_std "sys/env/unsupported.rs" + + @just cp_std "sys/fd/mod.rs" + + @just cp_std "sys/fs/mod.rs" + @just cp_std "sys/fs/common.rs" + @just cp_std "sys/fs/unsupported.rs" + + @just cp_std "sys/helpers/mod.rs" + @just cp_std "sys/helpers/small_c_string.rs" + @just cp_std "sys/helpers/tests.rs" + @just cp_std "sys/helpers/wstr.rs" + + @just cp_std "sys/io/error/generic.rs" + @just real_cp_std "sys/io/error/mod.rs" + @just cp_std "sys/io/io_slice/unsupported.rs" + @just cp_std "sys/io/is_terminal/unsupported.rs" + @just cp_std "sys/io/kernel_copy/mod.rs" + @just cp_std "sys/io/mod.rs" + + @just cp_std "sys/net/connection/mod.rs" + @just cp_std "sys/net/connection/unsupported.rs" + @just cp_std "sys/net/hostname/mod.rs" + @just cp_std "sys/net/hostname/unsupported.rs" + @just cp_std "sys/net/mod.rs" + + @just cp_std "sys/os_str/bytes/tests.rs" + @just cp_std "sys/os_str/bytes.rs" + @just cp_std "sys/os_str/mod.rs" + + @just real_cp_std "sys/pal/mod.rs" + @just cp_std "sys/pal/unsupported/mod.rs" + @just cp_std "sys/pal/unsupported/common.rs" + @just cp_std "sys/pal/unsupported/os.rs" + + @just cp_std "sys/path/mod.rs" + @just cp_std "sys/path/unix.rs" + + @just cp_std "sys/personality/dwarf/eh.rs" + @just cp_std "sys/personality/dwarf/mod.rs" + @just cp_std "sys/personality/dwarf/tests.rs" + @just cp_std "sys/personality/mod.rs" + + @just cp_std "sys/pipe/mod.rs" + @just cp_std "sys/pipe/unsupported.rs" + + @just cp_std "sys/platform_version/mod.rs" + + @just cp_std "sys/process/mod.rs" + @just cp_std "sys/process/env.rs" + @just cp_std "sys/process/unsupported.rs" + + @just real_cp_std "sys/random/mod.rs" + @just cp_std "sys/random/unsupported.rs" + + @just cp_std "sys/stdio/mod.rs" + @just cp_std "sys/stdio/unsupported.rs" + + @just cp_std "sys/sync/condvar/mod.rs" + @just cp_std "sys/sync/condvar/no_threads.rs" + @just cp_std "sys/sync/mutex/mod.rs" + @just cp_std "sys/sync/mutex/no_threads.rs" + @just cp_std "sys/sync/once/mod.rs" + @just cp_std "sys/sync/once/no_threads.rs" + @just cp_std "sys/sync/rwlock/mod.rs" + @just cp_std "sys/sync/rwlock/no_threads.rs" + @just cp_std "sys/sync/thread_parking/mod.rs" + @just cp_std "sys/sync/thread_parking/unsupported.rs" + @just cp_std "sys/sync/mod.rs" + @just cp_std "sys/sync/once_box.rs" + + @just cp_std "sys/thread/mod.rs" + @just cp_std "sys/thread/unsupported.rs" + + @just real_cp_std "sys/thread_local/mod.rs" + @just cp_std "sys/thread_local/no_threads.rs" + @just cp_std "sys/thread_local/os.rs" + + @just cp_std "sys/time/mod.rs" + @just cp_std "sys/time/unsupported.rs" + + @just cp_std "sys/backtrace.rs" + @just cp_std "sys/cmath.rs" + @just cp_std "sys/configure_builtins.rs" + @just cp_std "sys/env_consts.rs" + @just cp_std "sys/exit.rs" + @just cp_std "sys/mod.rs" + + @just cp_std "thread" + +STD_FILES := "alloc.rs \ +ascii.rs \ +backtrace.rs \ +bstr.rs \ +env.rs \ +error.rs \ +fs.rs \ +keyword_docs.rs \ +lib.rs \ +macros.rs \ +panic.rs \ +panicking.rs \ +pat.rs \ +path.rs \ +process.rs \ +random.rs \ +rt.rs \ +tests_helpers.rs \ +time.rs \ +backtrace \ +collections \ +ffi \ +fs \ +hash \ +io \ +net \ +num \ +os/raw/mod.rs \ +os/raw/tests.rs \ +os/mod.rs \ +prelude \ +process \ +sync \ +sys/alloc/mod.rs \ +sys/args/mod.rs \ +sys/args/unsupported.rs \ +sys/env/mod.rs \ +sys/env/common.rs \ +sys/env/unsupported.rs \ +sys/fd/mod.rs \ +sys/fs/mod.rs \ +sys/fs/common.rs \ +sys/fs/unsupported.rs \ +sys/helpers/mod.rs \ +sys/helpers/small_c_string.rs \ +sys/helpers/tests.rs \ +sys/helpers/wstr.rs \ +sys/io/error/generic.rs \ +sys/io/error/mod.rs \ +sys/io/io_slice/unsupported.rs \ +sys/io/is_terminal/unsupported.rs \ +sys/io/kernel_copy/mod.rs \ +sys/io/mod.rs \ +sys/net/connection/mod.rs \ +sys/net/connection/unsupported.rs \ +sys/net/hostname/mod.rs \ +sys/net/hostname/unsupported.rs \ +sys/net/mod.rs \ +sys/os_str/bytes/tests.rs \ +sys/os_str/bytes.rs \ +sys/os_str/mod.rs \ +sys/pal/mod.rs \ +sys/pal/unsupported/mod.rs \ +sys/pal/unsupported/common.rs \ +sys/pal/unsupported/os.rs \ +sys/path/mod.rs \ +sys/path/unix.rs \ +sys/personality/dwarf/eh.rs \ +sys/personality/dwarf/mod.rs \ +sys/personality/dwarf/tests.rs \ +sys/personality/mod.rs \ +sys/pipe/mod.rs \ +sys/pipe/unsupported.rs \ +sys/platform_version/mod.rs \ +sys/process/mod.rs \ +sys/process/env.rs \ +sys/process/unsupported.rs \ +sys/random/mod.rs \ +sys/random/unsupported.rs \ +sys/stdio/mod.rs \ +sys/stdio/unsupported.rs \ +sys/sync/condvar/mod.rs \ +sys/sync/condvar/no_threads.rs \ +sys/sync/mutex/mod.rs \ +sys/sync/mutex/no_threads.rs \ +sys/sync/once/mod.rs \ +sys/sync/once/no_threads.rs \ +sys/sync/rwlock/mod.rs \ +sys/sync/rwlock/no_threads.rs \ +sys/sync/thread_parking/mod.rs \ +sys/sync/thread_parking/unsupported.rs \ +sys/sync/mod.rs \ +sys/sync/once_box.rs \ +sys/thread/mod.rs \ +sys/thread/unsupported.rs \ +sys/thread_local/mod.rs \ +sys/thread_local/no_threads.rs \ +sys/thread_local/os.rs \ +sys/time/mod.rs \ +sys/time/unsupported.rs \ +sys/backtrace.rs \ +sys/cmath.rs \ +sys/configure_builtins.rs \ +sys/env_consts.rs \ +sys/exit.rs \ +sys/mod.rs \ +thread" + +build-sysroot: update-std + RUSTFLAGS="-Zforce-unstable-if-unmarked -C relocation-model=pic -C link-arg=-pie" cargo build --target ../riscv64.json + mkdir ../sysroot/lib/rustlib/riscv64/lib -p + rm ../sysroot/lib/rustlib/riscv64/lib/* -rf + cp target/riscv64/debug/deps/*.rlib ../sysroot/lib/rustlib/riscv64/lib + +clean: + # cargo clean + rm ../sysroot/lib/rustlib/riscv64/lib/* -rf + + for file in {{ STD_FILES }}; do \ + rm -rf std/src/$file; \ + done + + rm -rf std/build.rs diff --git a/library/std/.gitignore b/library/std/.gitignore new file mode 100644 index 0000000..6abdf1c --- /dev/null +++ b/library/std/.gitignore @@ -0,0 +1,109 @@ +build.rs + +src/alloc.rs +src/ascii.rs +src/backtrace.rs +src/bstr.rs +src/env.rs +src/error.rs +src/fs.rs +src/keyword_docs.rs +src/lib.rs +src/macros.rs +src/panic.rs +src/panicking.rs +src/pat.rs +src/path.rs +src/process.rs +src/random.rs +src/rt.rs +src/tests_helpers.rs +src/time.rs +src/backtrace +src/collections +src/ffi +src/fs +src/hash +src/io +src/net +src/num +src/os/raw/mod.rs +src/os/raw/tests.rs +src/os/mod.rs +src/prelude +src/process +src/sync +src/sys/alloc/mod.rs +src/sys/args/mod.rs +src/sys/args/unsupported.rs +src/sys/env/mod.rs +src/sys/env/common.rs +src/sys/env/unsupported.rs +src/sys/fd/mod.rs +src/sys/fs/mod.rs +src/sys/fs/common.rs +src/sys/fs/unsupported.rs +src/sys/helpers/mod.rs +src/sys/helpers/small_c_string.rs +src/sys/helpers/tests.rs +src/sys/helpers/wstr.rs +src/sys/io/error/generic.rs +src/sys/io/error/mod.rs +src/sys/io/io_slice/unsupported.rs +src/sys/io/is_terminal/unsupported.rs +src/sys/io/kernel_copy/mod.rs +src/sys/io/mod.rs +src/sys/net/connection/mod.rs +src/sys/net/connection/unsupported.rs +src/sys/net/hostname/mod.rs +src/sys/net/hostname/unsupported.rs +src/sys/net/mod.rs +src/sys/os_str/bytes/tests.rs +src/sys/os_str/bytes.rs +src/sys/os_str/mod.rs +src/sys/pal/mod.rs +src/sys/pal/unsupported/mod.rs +src/sys/pal/unsupported/common.rs +src/sys/pal/unsupported/os.rs +src/sys/path/mod.rs +src/sys/path/unix.rs +src/sys/personality/dwarf/eh.rs +src/sys/personality/dwarf/mod.rs +src/sys/personality/dwarf/tests.rs +src/sys/personality/mod.rs +src/sys/pipe/mod.rs +src/sys/pipe/unsupported.rs +src/sys/platform_version/mod.rs +src/sys/process/mod.rs +src/sys/process/env.rs +src/sys/process/unsupported.rs +src/sys/random/mod.rs +src/sys/random/unsupported.rs +src/sys/stdio/mod.rs +src/sys/stdio/unsupported.rs +src/sys/sync/condvar/mod.rs +src/sys/sync/condvar/no_threads.rs +src/sys/sync/mutex/mod.rs +src/sys/sync/mutex/no_threads.rs +src/sys/sync/once/mod.rs +src/sys/sync/once/no_threads.rs +src/sys/sync/rwlock/mod.rs +src/sys/sync/rwlock/no_threads.rs +src/sys/sync/thread_parking/mod.rs +src/sys/sync/thread_parking/unsupported.rs +src/sys/sync/mod.rs +src/sys/sync/once_box.rs +src/sys/thread/mod.rs +src/sys/thread/unsupported.rs +src/sys/thread_local/mod.rs +src/sys/thread_local/no_threads.rs +src/sys/thread_local/os.rs +src/sys/time/mod.rs +src/sys/time/unsupported.rs +src/sys/backtrace.rs +src/sys/cmath.rs +src/sys/configure_builtins.rs +src/sys/env_consts.rs +src/sys/exit.rs +src/sys/mod.rs +src/thread diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml new file mode 100644 index 0000000..388d917 --- /dev/null +++ b/library/std/Cargo.toml @@ -0,0 +1,177 @@ +cargo-features = ["public-dependency"] + +[package] +name = "std" +version = "0.0.0" +license = "MIT OR Apache-2.0" +repository = "https://github.com/rust-lang/rust.git" +description = "The Rust Standard Library" +edition = "2024" +autobenches = false + +[lib] +crate-type = ["dylib", "rlib"] + +[dependencies] +alloc = { path = "../alloc", public = true } +# std no longer uses cfg-if directly, but the included copy of backtrace does. +cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] } +panic_unwind = { path = "../panic_unwind", optional = true } +panic_abort = { path = "../panic_abort" } +core = { path = "../core", public = true } +unwind = { path = "../unwind" } +hashbrown = { version = "0.16.1", default-features = false, features = [ + 'rustc-dep-of-std', +] } +std_detect = { path = "../std_detect", public = true } + +# Dependencies of the `backtrace` crate +rustc-demangle = { version = "0.1.27", features = ['rustc-dep-of-std'] } + +[target.'cfg(not(all(windows, target_env = "msvc", not(target_vendor = "uwp"))))'.dependencies] +miniz_oxide = { version = "0.8.0", optional = true, default-features = false } +addr2line = { version = "0.25.0", optional = true, default-features = false } + +[target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies] +libc = { version = "0.2.178", default-features = false, features = [ + 'rustc-dep-of-std', +], public = true } + +[target.'cfg(all(not(target_os = "aix"), not(all(windows, target_env = "msvc", not(target_vendor = "uwp")))))'.dependencies] +object = { version = "0.37.1", default-features = false, optional = true, features = [ + 'read_core', + 'elf', + 'macho', + 'pe', + 'unaligned', + 'archive', +] } + +[target.'cfg(target_os = "aix")'.dependencies] +object = { version = "0.37.1", default-features = false, optional = true, features = [ + 'read_core', + 'xcoff', + 'unaligned', + 'archive', +] } + +[target.'cfg(any(windows, target_os = "cygwin"))'.dependencies.windows-link] +path = "../windows_link" + +[dev-dependencies] +rand = { version = "0.9.0", default-features = false, features = ["alloc"] } +rand_xorshift = "0.4.0" + +[target.'cfg(any(all(target_family = "wasm", target_os = "unknown"), target_os = "xous", target_os = "vexos", all(target_vendor = "fortanix", target_env = "sgx")))'.dependencies] +dlmalloc = { version = "0.2.10", features = ['rustc-dep-of-std'] } + +[target.x86_64-fortanix-unknown-sgx.dependencies] +fortanix-sgx-abi = { version = "0.6.1", features = [ + 'rustc-dep-of-std', +], public = true } + +[target.'cfg(target_os = "motor")'.dependencies] +moto-rt = { version = "0.16", features = ['rustc-dep-of-std'], public = true } + +[target.'cfg(target_os = "hermit")'.dependencies] +hermit-abi = { version = "0.5.0", features = [ + 'rustc-dep-of-std', +], public = true } + +[target.'cfg(all(target_os = "wasi", target_env = "p1"))'.dependencies] +wasi = { version = "0.11.0", features = [ + 'rustc-dep-of-std', +], default-features = false } + +[target.'cfg(all(target_os = "wasi", target_env = "p2"))'.dependencies] +wasip2 = { version = '0.14.4', features = [ + 'rustc-dep-of-std', +], default-features = false, package = 'wasi' } + +[target.'cfg(all(target_os = "wasi", target_env = "p3"))'.dependencies] +wasip2 = { version = '0.14.4', features = [ + 'rustc-dep-of-std', +], default-features = false, package = 'wasi' } + +[target.'cfg(target_os = "uefi")'.dependencies] +r-efi = { version = "5.2.0", features = ['rustc-dep-of-std'] } +r-efi-alloc = { version = "2.0.0", features = ['rustc-dep-of-std'] } + +[target.'cfg(target_os = "vexos")'.dependencies] +vex-sdk = { version = "0.27.0", features = [ + 'rustc-dep-of-std', +], default-features = false } + +[features] +default = ["compiler-builtins-mem"] +backtrace = [ + 'addr2line/rustc-dep-of-std', + 'object/rustc-dep-of-std', + 'miniz_oxide/rustc-dep-of-std', +] +# Disable symbolization in backtraces. For use with -Zbuild-std. +# FIXME: Ideally this should be an additive backtrace-symbolization feature +backtrace-trace-only = [] + +panic-unwind = ["dep:panic_unwind"] +compiler-builtins-c = ["alloc/compiler-builtins-c"] +compiler-builtins-mem = ["alloc/compiler-builtins-mem"] +llvm-libunwind = ["unwind/llvm-libunwind"] +system-llvm-libunwind = ["unwind/system-llvm-libunwind"] + +# Choose algorithms that are optimized for binary size instead of runtime performance +optimize_for_size = ["core/optimize_for_size", "alloc/optimize_for_size"] + +# Make `RefCell` store additional debugging information, which is printed out when +# a borrow error occurs +debug_refcell = ["core/debug_refcell"] + +llvm_enzyme = ["core/llvm_enzyme"] + +# Enable using raw-dylib for Windows imports. +# This will eventually be the default. +windows_raw_dylib = ["windows-link/windows_raw_dylib"] + +[package.metadata.fortanix-sgx] +# Maximum possible number of threads when testing +threads = 125 +# Maximum heap size +heap_size = 0x8000000 + +[[test]] +name = "pipe-subprocess" +path = "tests/pipe_subprocess.rs" +harness = false + +[[test]] +name = "sync" +path = "tests/sync/lib.rs" + +[[test]] +name = "thread_local" +path = "tests/thread_local/lib.rs" + +[[bench]] +name = "stdbenches" +path = "benches/lib.rs" +test = true + +[lints.rust.unexpected_cfgs] +level = "warn" +check-cfg = [ + # std use #[path] imports to portable-simd `std_float` crate + # and to the `backtrace` crate which messes-up with Cargo list + # of declared features, we therefor expect any feature cfg + 'cfg(feature, values(any()))', + # Internal features aren't marked known config by default, we use these to + # gate tests. + 'cfg(target_has_reliable_f16)', + 'cfg(target_has_reliable_f16_math)', + 'cfg(target_has_reliable_f128)', + 'cfg(target_has_reliable_f128_math)', +] + + + +# shared = { path = "../shared", features = ["user"] } +# io_crate = { package = "io", path = "../io", features = ["alloc_crate"] } diff --git a/library/std/patches/sys/args/mod.sed b/library/std/patches/sys/args/mod.sed new file mode 100644 index 0000000..cd70d7a --- /dev/null +++ b/library/std/patches/sys/args/mod.sed @@ -0,0 +1,4 @@ +# 55a \ target_os = "survos" => { \ +# mod survos; \ +# pub use survos::*; \ +# } diff --git a/library/std/patches/sys/io/error/mod.sed b/library/std/patches/sys/io/error/mod.sed new file mode 100644 index 0000000..3c6f879 --- /dev/null +++ b/library/std/patches/sys/io/error/mod.sed @@ -0,0 +1 @@ +45a \ target_os = "survos", diff --git a/library/std/patches/sys/pal/mod.sed b/library/std/patches/sys/pal/mod.sed new file mode 100644 index 0000000..acd2d76 --- /dev/null +++ b/library/std/patches/sys/pal/mod.sed @@ -0,0 +1,6 @@ +62a \ target_os = "survos" => { \ + mod unsupported; \ + pub use self::unsupported::*; \ + mod survos; \ + pub use self::survos::*; \ + } diff --git a/library/std/patches/sys/random/mod.sed b/library/std/patches/sys/random/mod.sed new file mode 100644 index 0000000..32c4012 --- /dev/null +++ b/library/std/patches/sys/random/mod.sed @@ -0,0 +1,2 @@ +108a \target_os = "survos", +124a \target_os = "survos", diff --git a/library/std/patches/sys/thread_local/mod.sed b/library/std/patches/sys/thread_local/mod.sed new file mode 100644 index 0000000..d436d18 --- /dev/null +++ b/library/std/patches/sys/thread_local/mod.sed @@ -0,0 +1,6 @@ +32a \ target_os = "survos", + +129a \ target_os = "survos" => { \ + // todo \ + pub(crate) fn enable() {} \ + } diff --git a/library/std/riscv64.json b/library/std/riscv64.json new file mode 100644 index 0000000..1801bfe --- /dev/null +++ b/library/std/riscv64.json @@ -0,0 +1,22 @@ +{ + "llvm-target": "riscv64", + "llvm-abiname": "lp64", + "abi": "lp64", + "data-layout": "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128", + "target-endian": "little", + "target-pointer-width": 64, + "arch": "riscv64", + "os": "survos", + "vendor": "unknown", + "env": "", + "features": "+i,+m,+a,+zicsr", + "linker": "ld.lld", + "linker-flavor": "ld", + "executables": true, + "panic-strategy": "abort", + "relocation-model": "static", + "disable-redzone": true, + "emit-debug-gdb-scripts": false, + "eh-frame-header": false, + "code-model": "medium" +} diff --git a/library/std/src/sys/pal/survos.rs b/library/std/src/sys/pal/survos.rs new file mode 100644 index 0000000..e68ea1d --- /dev/null +++ b/library/std/src/sys/pal/survos.rs @@ -0,0 +1,11 @@ +/// # Safety +/// `argc` and `argv` are passed by the kernel +#[unsafe(no_mangle)] +#[stable(feature = "rust1", since = "1.0.0")] +pub unsafe extern "C" fn _start(argc: isize, argv: *const *const u8) -> isize { + unsafe extern "C" { + fn main(argc: isize, argv: *const *const u8) -> isize; + } + + unsafe { main(argc, argv) } +} diff --git a/riscv64.json b/riscv64.json index 7d21f3a..1801bfe 100644 --- a/riscv64.json +++ b/riscv64.json @@ -6,7 +6,7 @@ "target-endian": "little", "target-pointer-width": 64, "arch": "riscv64", - "os": "none", + "os": "survos", "vendor": "unknown", "env": "", "features": "+i,+m,+a,+zicsr", diff --git a/src/drivers.rs b/src/drivers.rs new file mode 100644 index 0000000..73cdf76 --- /dev/null +++ b/src/drivers.rs @@ -0,0 +1,2 @@ +pub mod keyboard; +pub mod mouse; diff --git a/src/drivers/keyboard.rs b/src/drivers/keyboard.rs new file mode 100644 index 0000000..051b9fb --- /dev/null +++ b/src/drivers/keyboard.rs @@ -0,0 +1,67 @@ +use crate::{ + keymap::{KeyType, ModifierType, map_keycode}, + tty::TTY0, + virtio::{ + Virtqueue, + input::{EventCodeValue, VirtioInputEvent, VirtioPciDriver}, + }, + virtual_fs::{FILE_SYSTEM, VirtualFileSystem}, +}; + +#[derive(Debug, Clone, Copy, Default)] +pub struct KeyboardState { + // ctrl_modifier: bool, + pub shift_modifier: bool, + pub alt_gr_modifier: bool, +} + +impl KeyboardState { + pub const fn new() -> Self { + Self { + // ctrl_modifier: false, + shift_modifier: false, + alt_gr_modifier: false, + } + } +} + +static mut KBD_QUEUE: Virtqueue = unsafe { core::mem::zeroed() }; +pub static mut KBD_DRIVER: VirtioPciDriver = unsafe { + VirtioPciDriver::new( + |state, event| { + let mut kbd_buffer = FILE_SYSTEM.open("/dev/input/keyboard".as_ref()).unwrap(); + kbd_buffer + .write(core::mem::transmute::< + &VirtioInputEvent, + &[u8; size_of::()], + >(event)) + .unwrap(); + + if event.is_key() { + let event = event.as_key_event(); + #[allow(clippy::single_match)] + match map_keycode(event.code, state) { + KeyType::Ascii(c) if event.value == EventCodeValue::Pressed => { + let mut buf = [0; 4]; + let to_send = c.encode_utf8(&mut buf); + for c in to_send.as_bytes() { + TTY0.buffer.borrow_mut().push(*c); + } + } + KeyType::Modifier(ModifierType::Shift) => { + state.shift_modifier = !state.shift_modifier; + } + KeyType::Modifier(ModifierType::AltGr) => { + state.alt_gr_modifier = !state.alt_gr_modifier; + } + _ => {} + } + // println!("event: {:#?}", event); + } else { + // println!("key pressed, {:#?}", event); + } + }, + KeyboardState::new(), + &mut KBD_QUEUE, + ) +}; diff --git a/src/drivers/mouse.rs b/src/drivers/mouse.rs new file mode 100644 index 0000000..c531d8e --- /dev/null +++ b/src/drivers/mouse.rs @@ -0,0 +1,38 @@ +use crate::{ + cursor::{clear_cursor, draw_cursor}, + vga::Vga, + virtio::{self, Virtqueue, input::VirtioPciDriver}, +}; + +pub static mut MOUSE_POSITION: (u16, u16) = (0, 0); + +static mut MOUSE_QUEUE: Virtqueue = unsafe { core::mem::zeroed() }; +pub static mut MOUSE_DRIVER: VirtioPciDriver<()> = unsafe { + VirtioPciDriver::new( + |_, event| { + if event.is_relative() { + let event = event.as_relative_event(); + + clear_cursor(&mut Vga, MOUSE_POSITION.0, MOUSE_POSITION.1); + + match event.code { + virtio::input::EventCodeRelative::X => { + MOUSE_POSITION.0 = (MOUSE_POSITION.0 as i32 + event.value) as u16 + } + virtio::input::EventCodeRelative::Y => { + MOUSE_POSITION.1 = (MOUSE_POSITION.1 as i32 + event.value) as u16 + } + _ => {} + } + + draw_cursor(&mut Vga, MOUSE_POSITION.0, MOUSE_POSITION.1); + + // println!("mouse moved relatively, {:#?}", event); + } else { + // println!("mouse moved, {:#?}", event); + } + }, + (), + &mut MOUSE_QUEUE, + ) +}; diff --git a/src/fs.rs b/src/fs.rs index 58c7afb..af509f2 100644 --- a/src/fs.rs +++ b/src/fs.rs @@ -12,7 +12,7 @@ use io::{IoBase, Read, Seek, Write}; use crate::virtual_fs::{VirtualFileSystem, VirtualNode}; -const DISK_ADDR: *const u8 = 0x9000_0000 as *const _; +const DISK_ADDR: *const u8 = 0xA000_0000 as *const _; #[derive(Debug)] /// Simple disk backend that reads from a fixed memory region. diff --git a/src/interrupt.rs b/src/interrupt.rs index e1e08b4..cef3b13 100644 --- a/src/interrupt.rs +++ b/src/interrupt.rs @@ -9,9 +9,9 @@ use log::info; use shared::syscall::SysCall; use crate::{ - KBD_DRIVER, MOUSE_DRIVER, boot::sbi::{ExtensionID, TimerFunctionID}, clear_csr, + drivers::{keyboard::KBD_DRIVER, mouse::MOUSE_DRIVER}, process::{ExecutionContext, exit_process, sleep}, read_csr, riscv::{disable_interrupt, dump_cpu}, @@ -160,6 +160,15 @@ unsafe extern "C" fn supervisor_trap_handler( unsafe { (*interrupt_state).a[0] = fd as u64 }; } + SysCall::Close => { + let fd = a1; + + let mut scheduler = SCHEDULER.lock(); + let current_process = scheduler.get_current_process(); + let mut vnode = current_process.fd_table[fd as usize].take().unwrap(); + + vnode.close(); + } SysCall::Write => { let fd = a1; let buf = @@ -168,7 +177,8 @@ unsafe extern "C" fn supervisor_trap_handler( let mut scheduler = SCHEDULER.lock(); let current_process = scheduler.get_current_process(); let vnode = current_process.fd_table[fd as usize].as_mut().unwrap(); - vnode.write(buf).unwrap(); + let res = vnode.write(buf).unwrap(); + unsafe { (*interrupt_state).a[0] = res as u64 }; } SysCall::Read => { let fd = a1; @@ -182,6 +192,8 @@ unsafe extern "C" fn supervisor_trap_handler( if res == 0 && !buf.is_empty() { loop_syscall(interrupt_state); scheduler.schedule(&mut interrupt_state); + } else { + unsafe { (*interrupt_state).a[0] = res as u64 }; } } SysCall::Seek => { @@ -197,6 +209,17 @@ unsafe extern "C" fn supervisor_trap_handler( let vnode = current_process.fd_table[fd as usize].as_mut().unwrap(); vnode.seek(seek).unwrap(); } + SysCall::Spawn => { + let path = unsafe { str::from_raw_parts(a1 as *const u8, a2 as usize) }; + let mut scheduler = SCHEDULER.lock(); + scheduler.create_process_from_file(path, 0, core::ptr::null()); + } + SysCall::ExecVE => { + // let path = unsafe { str::from_raw_parts(a1 as *const u8, a2 as usize) }; + // let mut scheduler = SCHEDULER.lock(); + // scheduler.create_process_from_file(path, &[]); + unimplemented!("ExecVE is not implemented") + } SysCall::Alloc => { let layout = Layout::from_size_align(a1 as usize, a2 as usize).unwrap(); // Allocate memory and put the pointer in a0 diff --git a/src/keymap.rs b/src/keymap.rs index 8b4af0e..91d5d0d 100644 --- a/src/keymap.rs +++ b/src/keymap.rs @@ -1,4 +1,4 @@ -use crate::KeyboardState; +use crate::drivers::keyboard::KeyboardState; #[derive(Debug, Clone, Copy)] #[derive_const(PartialEq, Eq)] diff --git a/src/main.rs b/src/main.rs index 5b63d6b..b932234 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,7 +12,8 @@ arbitrary_self_types_pointers, derive_const, const_cmp, - const_trait_impl + const_trait_impl, + trait_alias )] use core::sync::atomic::AtomicBool; @@ -22,20 +23,15 @@ use embedded_alloc::LlffHeap as Heap; use log::info; use crate::{ - cursor::{clear_cursor, draw_cursor}, + drivers::{keyboard::KBD_DRIVER, mouse::MOUSE_DRIVER}, io::init_log, - keymap::{KeyType, ModifierType, map_keycode}, - pci::{PciDeviceIterator, scan_virtio_devices}, + pci::scan_virtio_devices, riscv::enable_supervisor_interrupt, scheduler::{SCHEDULER, idle}, - tty::TTY0, user::{proc2, test}, vga::Vga, - virtio::{ - Virtqueue, - input::{EventCodeValue, VirtioInputEvent, VirtioPciDriver, init_plic_pci}, - }, - virtual_fs::{FILE_SYSTEM, VirtualFileSystem, init_file_system}, + virtio::input::init_plic_pci, + virtual_fs::init_file_system, }; extern crate alloc; @@ -44,6 +40,7 @@ mod critical_section; mod cursor; mod data_structures; mod draw; +mod drivers; mod fs; mod interrupt; mod io; @@ -75,97 +72,6 @@ const _: () = assert!(core::mem::size_of::() == core::mem::size_of:: #[cfg(not(target_endian = "little"))] compile_error! {"This kernel implementation assume endianness is little-endian. Some memory access like PCI could not work in big-endian."} -#[derive(Debug, Clone, Copy, Default)] -pub struct KeyboardState { - // ctrl_modifier: bool, - pub shift_modifier: bool, - pub alt_gr_modifier: bool, -} - -impl KeyboardState { - pub const fn new() -> Self { - Self { - // ctrl_modifier: false, - shift_modifier: false, - alt_gr_modifier: false, - } - } -} - -static mut KBD_QUEUE: Virtqueue = unsafe { core::mem::zeroed() }; -pub static mut KBD_DRIVER: VirtioPciDriver = unsafe { - VirtioPciDriver::new( - |state, event| { - let mut kbd_buffer = FILE_SYSTEM.open("/dev/input/keyboard".as_ref()).unwrap(); - kbd_buffer - .write(core::mem::transmute::< - &VirtioInputEvent, - &[u8; size_of::()], - >(event)) - .unwrap(); - - if event.is_key() { - let event = event.as_key_event(); - #[allow(clippy::single_match)] - match map_keycode(event.code, state) { - KeyType::Ascii(c) if event.value == EventCodeValue::Pressed => { - let mut buf = [0; 4]; - let to_send = c.encode_utf8(&mut buf); - for c in to_send.as_bytes() { - TTY0.buffer.borrow_mut().push(*c); - } - } - KeyType::Modifier(ModifierType::Shift) => { - state.shift_modifier = !state.shift_modifier; - } - KeyType::Modifier(ModifierType::AltGr) => { - state.alt_gr_modifier = !state.alt_gr_modifier; - } - _ => {} - } - println!("event: {:#?}", event); - } else { - // println!("key pressed, {:#?}", event); - } - }, - KeyboardState::new(), - &mut KBD_QUEUE, - ) -}; - -pub static mut MOUSE_POSITION: (u16, u16) = (0, 0); - -static mut MOUSE_QUEUE: Virtqueue = unsafe { core::mem::zeroed() }; -pub static mut MOUSE_DRIVER: VirtioPciDriver<()> = unsafe { - VirtioPciDriver::new( - |_, event| { - if event.is_relative() { - let event = event.as_relative_event(); - - clear_cursor(&mut Vga, MOUSE_POSITION.0, MOUSE_POSITION.1); - - match event.code { - virtio::input::EventCodeRelative::X => { - MOUSE_POSITION.0 = (MOUSE_POSITION.0 as i32 + event.value) as u16 - } - virtio::input::EventCodeRelative::Y => { - MOUSE_POSITION.1 = (MOUSE_POSITION.1 as i32 + event.value) as u16 - } - _ => {} - } - - draw_cursor(&mut Vga, MOUSE_POSITION.0, MOUSE_POSITION.1); - - // println!("mouse moved relatively, {:#?}", event); - } else { - // println!("mouse moved, {:#?}", event); - } - }, - (), - &mut MOUSE_QUEUE, - ) -}; - #[unsafe(no_mangle)] pub extern "C" fn supervisor_mode_entry() { unsafe { @@ -180,19 +86,20 @@ pub extern "C" fn supervisor_mode_entry() { info!("Hello World !"); // unsafe { Vga.draw_string(10, 10, "Hello World !", Color::WHITE, Color::BLACK) }; - SCHEDULER.lock().create_process(Box::new(test), "proc1"); - SCHEDULER.lock().create_process(Box::new(proc2), "proc2"); + // let binding = Box::leak(Box::new(["coucou".as_bytes()])); + SCHEDULER + .lock() + .create_process(Box::new(test), "proc1", 0, core::ptr::null()); + SCHEDULER + .lock() + .create_process(Box::new(proc2), "proc2", 0, core::ptr::null()); SCHEDULER .lock() - .create_process_from_file("/usr/bin/test_pic"); + .create_process_from_file("/usr/bin/test_pic", 0, core::ptr::null()); enable_supervisor_interrupt(); - for pci in PciDeviceIterator::new() { - println!("{:x?}", pci.vendor_and_device_id()) - } - unsafe { let (pci_keyboard, pci_mouse) = scan_virtio_devices(); let (pci_keyboard, pci_mouse) = (pci_keyboard.unwrap(), pci_mouse.unwrap()); @@ -214,5 +121,5 @@ pub extern "C" fn supervisor_mode_entry() { init_plic_pci(pci_keyboard.irq); init_plic_pci(pci_mouse.irq); } - idle(); + idle(0, core::ptr::null()); } diff --git a/src/process.rs b/src/process.rs index 485a68f..6d6b4e0 100644 --- a/src/process.rs +++ b/src/process.rs @@ -19,7 +19,6 @@ use crate::{ riscv::SStatus, scheduler::{ACTIVE_PID, SCHEDULER, Scheduler}, time::elapsed_time_since_startup, - tty::TTY0, virtual_fs::{FILE_SYSTEM, VirtualFileSystem, VirtualNode}, }; @@ -66,6 +65,9 @@ pub struct ExecutionContext { pub mstatus: u64, } +pub trait ProcessEntryTrait = Fn(isize, *const *const u8); +pub type ProcessEntry = dyn ProcessEntryTrait; + /// Represents a process in the system. /// /// Each process has its own execution context, stack, @@ -78,13 +80,13 @@ pub struct Process { /// Current state of the process. pub state: ProcessState, /// Optional entry point for the process code. - pub entry: Option>, + pub entry: Option>, /// Wake time for sleeping processes. pub wake_time: Duration, /// Saved execution context. pub ctx: ExecutionContext, /// Process stack. - pub stack: [u64; STACK_SIZE], + pub stack: Box<[u64; STACK_SIZE]>, /// File descriptor table. pub fd_table: Vec>>, } @@ -109,7 +111,7 @@ impl Default for Process { mepc: core::ptr::null(), mstatus: 0, }, - stack: [0; _], + stack: unsafe { Box::new_zeroed().assume_init() }, entry: None, fd_table: Vec::new(), } @@ -150,7 +152,12 @@ impl Scheduler { /// Attempts to open `path`, load its contents into memory and create a new /// kernel process that will execute the loaded binary. Returns the PID of the /// created process, or -1 on failure. - pub fn create_process_from_file>(&mut self, path: T) -> i64 { + pub fn create_process_from_file>( + &mut self, + path: T, + argc: isize, + argv: *const *const u8, + ) -> i64 { let path = path.as_ref(); let name = path.as_str(); @@ -231,25 +238,30 @@ impl Scheduler { // Entry point let entry_va = gelf.entry; let entry_addr = unsafe { base.add((entry_va - min_vaddr) as usize) } as *const u8; - let entry_fn = - unsafe { core::mem::transmute::<*const u8, extern "C" fn()>(entry_addr) }; - let wrapper = Box::new(move || { - entry_fn(); - }); + let entry_fn = unsafe { + core::mem::transmute::<*const u8, extern "C" fn(isize, *const *const u8)>( + entry_addr, + ) + }; + let wrapper = move |argc, argv| { + entry_fn(argc, argv); + }; println!("Program loaded at : {:x?}", entry_addr); - return self.create_process(wrapper, name); + return self.create_process(wrapper, name, argc, argv); } } // Fallback: treat the file as a raw binary blob and execute in-place let entry_point = unsafe { - core::mem::transmute::<*const u8, extern "C" fn()>(Vec::leak(content).as_ptr()) + core::mem::transmute::<*const u8, extern "C" fn(isize, *const *const u8)>( + Vec::leak(content).as_ptr(), + ) + }; + let wrapper = move |argc, argv| { + entry_point(argc, argv); }; - let wrapper = Box::new(move || { - entry_point(); - }); - self.create_process(wrapper, name) + self.create_process(wrapper, name, argc, argv) } /// Creates a new process with the specified code and name. @@ -271,39 +283,48 @@ impl Scheduler { /// /// The provided `code` function will be executed when the process is first /// scheduled. Returns the new PID, or -1 if the process table is full. - pub fn create_process, F: Fn() + 'static + Send>( + pub fn create_process, F: ProcessEntryTrait + 'static + Send>( &mut self, - code: Box, + code: F, name: T, + argc: isize, + argv: *const *const u8, ) -> i64 { // SAFETY: Initializing process in the global table. // Access is safe because we verified bounds and found a Dead slot. unsafe { - self.process_table - .insert(self.next_pid, Box::new(Process::default())); + self.process_table.insert(self.next_pid, Process::default()); let process = self.process_table.get_mut(&self.next_pid).unwrap(); // Configure process metadata process.pid = self.next_pid as i64; process.name = name.into(); process.state = ProcessState::Activable; - process.entry = Some(code); + process.entry = Some(Box::new(code)); process.fd_table = Vec::new(); - FILE_SYSTEM.mount( - format!("/proc/{}/0", process.pid).into(), - Box::new(TTY0.clone()), - ); + // FILE_SYSTEM.mount( + // format!("/proc/{}/0", process.pid).into(), + // Box::new(TTY0.clone()), + // ); // FD 0 - process.fd_table.push(Some( - FILE_SYSTEM - .open(format!("/proc/{}/0", process.pid).as_ref()) - .unwrap(), - )); + process + .fd_table + .push(Some(FILE_SYSTEM.open("/dev/null".as_ref()).unwrap())); + // FD 1 + process + .fd_table + .push(Some(FILE_SYSTEM.open("/dev/null".as_ref()).unwrap())); + // FD 2 + process + .fd_table + .push(Some(FILE_SYSTEM.open("/dev/null".as_ref()).unwrap())); // Configure execution context // a0 contains the pointer to the function to execute process.ctx.a[0] = &raw const *process.entry.as_ref().unwrap_unchecked() as u64; + process.ctx.a[1] = argc as u64; + process.ctx.a[2] = argv as u64; // mepc points to process_launcher which will call the function process.ctx.mepc = process_launcher as *const _; @@ -338,10 +359,15 @@ impl Scheduler { /// This function is installed into the process `mepc` so that when the new /// process is scheduled it will run this launcher which calls the user /// function and ensures the process exits cleanly. -extern "C" fn process_launcher(code: *const Box) { +#[allow(improper_ctypes_definitions)] +extern "C" fn process_launcher( + code: *const Box, + argc: isize, + argv: *const *const u8, +) { // SAFETY: The code pointer was initialized in create_process // and points to a valid function. - unsafe { (*code)() }; + unsafe { (*code)(argc, argv) }; // If user code didn't exit explicitly, call exit() to clean up the process exit(); diff --git a/src/scheduler.rs b/src/scheduler.rs index 9c9c6cc..7dd58b3 100644 --- a/src/scheduler.rs +++ b/src/scheduler.rs @@ -17,7 +17,7 @@ use crate::{ #[derive(Debug)] pub struct Scheduler { pub next_pid: u64, - pub process_table: BTreeMap>, + pub process_table: BTreeMap, } pub static ACTIVE_PID: AtomicU64 = AtomicU64::new(0); @@ -30,7 +30,7 @@ pub static SCHEDULER: Mutex> = Mutex::new(LazyCell::new(|| S /// Idle loop executed when there is no runnable process. /// /// Uses the `wfi` instruction to yield the CPU while waiting for interrupts. -pub fn idle() { +pub fn idle(_argc: isize, _argv: *const *const u8) { loop { // write_string_temp("idle"); // info!("idle"); @@ -47,7 +47,7 @@ impl Scheduler { /// it as the active process. pub fn init(&mut self) { info!("scheduler init"); - self.create_process(Box::new(idle), "idle"); + self.create_process(Box::new(idle), "idle", 0, core::ptr::null()); self.process_table.get_mut(&0).unwrap().state = ProcessState::Active; } @@ -69,9 +69,7 @@ impl Scheduler { } } - let mut current_process_iter = self - .process_table - .range_mut((Bound::Excluded(prev_pid), Bound::Unbounded)); + let mut current_process_iter = self.process_table.range_mut(prev_pid + 1..); ACTIVE_PID.store( loop { diff --git a/src/user.rs b/src/user.rs index 0e0e3f3..8b003b7 100644 --- a/src/user.rs +++ b/src/user.rs @@ -6,14 +6,15 @@ use core::time::Duration; use shared::syscall::{sleep, write_string_temp}; -pub fn test() { +pub fn test(_argc: isize, _argv: *const *const u8) { loop { + // write_string_temp(str::from_utf8(_args[0]).unwrap()); write_string_temp("test"); sleep(Duration::new(2, 0)); } } -pub fn proc2() { +pub fn proc2(_argc: isize, _argv: *const *const u8) { loop { write_string_temp("proc2"); sleep(Duration::new(3, 0)); diff --git a/src/virtio/input.rs b/src/virtio/input.rs index ef9c519..c2a83e2 100644 --- a/src/virtio/input.rs +++ b/src/virtio/input.rs @@ -22,6 +22,7 @@ pub struct VirtioPciDriver { diff --git a/src/virtual_fs.rs b/src/virtual_fs.rs index b026e8f..2ff5bd0 100644 --- a/src/virtual_fs.rs +++ b/src/virtual_fs.rs @@ -9,6 +9,7 @@ use hashbrown::HashMap; use io::{IoBase, Read, Seek, Write}; pub mod keyboard; +pub mod null; pub mod stdin; pub mod virtual_stdin; @@ -16,10 +17,12 @@ use crate::{ fs::Disk, tty::TTY0, vga::Vga, - virtual_fs::{keyboard::KeyboardBuffer, virtual_stdin::VirtualStdin}, + virtual_fs::{keyboard::KeyboardBuffer, null::Null, virtual_stdin::VirtualStdin}, }; -pub trait VirtualNode: IoBase + Read + Write + Seek + Debug {} +pub trait VirtualNode: IoBase + Read + Write + Seek + Debug { + fn close(&mut self) {} +} pub trait VirtualFileSystem: Debug { fn open(&mut self, path: &Path) -> Result, ()>; @@ -62,6 +65,7 @@ pub unsafe fn init_file_system() { unsafe { FILE_SYSTEM.mount("/dev/fb0".into(), Box::new(VGAFileSystem)); FILE_SYSTEM.mount("/dev/tty0".into(), Box::new(TTY0.clone())); + FILE_SYSTEM.mount("/dev/null".into(), Box::new(Null)); FILE_SYSTEM.mount( "/dev/input/keyboard".into(), Box::new(KeyboardBuffer::new()), diff --git a/src/virtual_fs/null.rs b/src/virtual_fs/null.rs new file mode 100644 index 0000000..d5667d5 --- /dev/null +++ b/src/virtual_fs/null.rs @@ -0,0 +1,51 @@ +use alloc::boxed::Box; +use io::{IoBase, Read, Seek, Write}; + +use crate::virtual_fs::{VirtualFileSystem, VirtualNode}; + +#[derive(Debug)] +pub struct Null; + +#[derive(Debug)] +pub struct NullNode; + +impl VirtualFileSystem for Null { + fn open( + &mut self, + path: &bffs::path::Path, + ) -> Result, ()> { + if !path.is_empty() { + Err(()) + } else { + Ok(Box::new(NullNode)) + } + } +} + +impl IoBase for NullNode { + type Error = (); +} + +impl Read for NullNode { + fn read(&mut self, _buf: &mut [u8]) -> Result { + Ok(0) + } +} + +impl Seek for NullNode { + fn seek(&mut self, _pos: io::SeekFrom) -> Result { + todo!() + } +} + +impl Write for NullNode { + fn write(&mut self, _buf: &[u8]) -> Result { + todo!() + } + + fn flush(&mut self) -> Result<(), Self::Error> { + todo!() + } +} + +impl VirtualNode for NullNode {} diff --git a/sysroot/lib/rustlib/src/rust/library/library b/sysroot/lib/rustlib/src/rust/library/library new file mode 120000 index 0000000..7036b83 --- /dev/null +++ b/sysroot/lib/rustlib/src/rust/library/library @@ -0,0 +1 @@ +../../../../../../library \ No newline at end of file diff --git a/user.ld b/user.ld deleted file mode 100644 index f1e4581..0000000 --- a/user.ld +++ /dev/null @@ -1,35 +0,0 @@ -/* - * ld directives the for barmetal RISCV - */ -OUTPUT_ARCH(riscv) -ENTRY(_start) - -MEMORY { - RAM (wxa) : ORIGIN = 0x0, LENGTH = 128M -} - -SECTIONS { - . = 0x0; - .text : { - KEEP(*(.text._start)) - - *(.text .text.*) - } > RAM - - .rodata : { - *(.rodata .rodata.*) - } > RAM - - .data : { - *(.data .data.*) - } > RAM - - .bss : ALIGN(8) { - __bss_start = .; - *(.bss .bss.*) - __bss_end = .; - } > RAM - - _heap_start = ALIGN(8); - _heap_end = ORIGIN(RAM) + LENGTH(RAM); -} diff --git a/user/shell/Cargo.toml b/user/shell/Cargo.toml new file mode 100644 index 0000000..6b3a444 --- /dev/null +++ b/user/shell/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "shell" +version = "0.1.0" +edition = "2024" + +[dependencies] +# std = { path = "../../crates/std" } +# shared = { path = "../../crates/shared", features = ["user"] } +# core = { path = "../../crates/std/crates/core" } diff --git a/user/shell/src/main.rs b/user/shell/src/main.rs new file mode 100644 index 0000000..f0784f1 --- /dev/null +++ b/user/shell/src/main.rs @@ -0,0 +1,9 @@ +fn main() { + let a = std::env::args(); + for a in a { + println!("Argument: {}", a); + } + println!( + "Hello from PIC program loaded dynamically with custom std and a better justfile, and syscalls ! " + ); +} diff --git a/user/test_pic/Cargo.toml b/user/test_pic/Cargo.toml index c94477f..4ccb322 100644 --- a/user/test_pic/Cargo.toml +++ b/user/test_pic/Cargo.toml @@ -4,4 +4,7 @@ version = "0.1.0" edition = "2024" [dependencies] -os-std = { path = "../../crates/os-std" } +# std = { path = "../../crates/std" } +shared = { path = "../../crates/shared", features = ["user"] } +io = { path = "../../crates/io" } +bffs = { path = "../../crates/bffs" } diff --git a/user/test_pic/src/main.rs b/user/test_pic/src/main.rs index 984f10e..e7f321c 100644 --- a/user/test_pic/src/main.rs +++ b/user/test_pic/src/main.rs @@ -1,30 +1,24 @@ -#![no_std] -#![no_main] +#![allow(unused)] -// use core::time::Duration; - -use os_std::syscall; -os_std::custom_std_setup! {} +use io::{Read, Write}; +use std::io::{Stdin, stdin}; +use shared::syscall; fn main() { - // let mut input = String::new(); + let mut input = String::new(); + input.push('a'); // let mut file = syscall::open("/dev/fb0"); // syscall::seek(&mut file, SeekFrom::End(-3)); // syscall::write(&mut file, &[255; 6400 * 50]); // syscall::sleep(Duration::from_secs_f64(2.0)); - let mut stdin = syscall::open("/dev/tty0"); - let mut file = syscall::open("/dev/tty0"); + syscall::close(0); + let mut tty = syscall::open("/dev/tty0"); + tty.write(input.as_bytes()).unwrap(); + syscall::spawn("/usr/bin/shell"); loop { let mut test = [0; 2]; - syscall::read(&mut stdin, &mut test); - let len = *test.iter().find(|x| **x == 0).unwrap_or(&1) + 1; - syscall::write( - &mut file, - str::from_utf8(&test[..len as usize]).unwrap().as_bytes(), - ); + let len = tty.read(&mut test).unwrap(); + tty.write(str::from_utf8(&test[..len as usize]).unwrap().as_bytes()) + .unwrap(); } - // println!( - // "Hello from PIC program loaded dynamically with custom std and a better justfile, and syscalls ! {:?}", - // str::from_utf8(&test) - // ); }