From fadecc7c954f02ecfae24bf341da180908a7e291 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 | 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 | 22 +++ library/justfile | 108 ++++++++++++++ library/std/.gitignore | 146 +++++++++++++++++++ library/std/patches/sys/alloc/mod.sed | 3 + 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/src/sys/alloc/survos.rs | 104 +++++++++++++ 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 ++-- 47 files changed, 806 insertions(+), 320 deletions(-) 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/justfile create mode 100644 library/std/.gitignore create mode 100644 library/std/patches/sys/alloc/mod.sed 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/src/sys/alloc/survos.rs 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..6a5a4a4 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,6 @@ disk.img **/*.mem mnt + +sysroot/lib/rustlib/riscv64 +library/alloc 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..18f713d --- /dev/null +++ b/library/.gitignore @@ -0,0 +1,22 @@ +Cargo.lock +Cargo.toml +alloctests +backtrace +compiler-builtins +core +coretests +panic_abort +panic_unwind +portable-simd +proc_macro +profiler_builtins +rustc-std-workspace-alloc +rustc-std-workspace-core +rustc-std-workspace-std +std_detect +stdarch +sysroot +target +test +unwind +windows_link diff --git a/library/justfile b/library/justfile new file mode 100644 index 0000000..300ad76 --- /dev/null +++ b/library/justfile @@ -0,0 +1,108 @@ +SRC_DIR := "std/src" +PATCH_DIR := "std/patches" +RUST_SRC := `rustc --print sysroot` / "lib/rustlib/src/rust/library" +ROOT_LINKS := "\ + Cargo.toml backtrace std_detect panic_abort panic_unwind \ + windows_link unwind alloc rustc-std-workspace-alloc \ + rustc-std-workspace-core rustc-std-workspace-std \ + compiler-builtins core stdarch portable-simd proc_macro \ + profiler_builtins test coretests alloctests sysroot" +REAL_CP_FILES := "\ + sys/args/mod.rs \ + sys/io/error/mod.rs \ + sys/pal/mod.rs \ + sys/random/mod.rs \ + sys/thread_local/mod.rs" +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/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/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/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/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/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" +KEEP_FILES := "sys sys/pal sys/pal/survos.rs sys/alloc sys/alloc/survos.rs" + +setup-std: + @echo "🔗 Linking root directories..." + @for dir in {{ ROOT_LINKS }}; do ln -fs {{ RUST_SRC }}/$dir "."; done + + @echo "📂 Processing std/src files..." + @for f in {{ STD_FILES }}; do {{ just_executable() }} cp_std $f; done + @for f in {{ REAL_CP_FILES }}; do {{ just_executable() }} real_cp_std $f; done + + @{{ just_executable() }} cp_std "../build.rs" + @{{ just_executable() }} cp_std "../Cargo.toml" + @sed -i '59a\ || target_os == "survos"' std/src/../build.rs + +update-std: setup-std patch-std + +patch-std: + @echo "🛠️ Patching the std..." + @find {{ PATCH_DIR }} -type f -name "*.sed" | while read -r patch_file; do \ + rel="${patch_file#{{ PATCH_DIR }}/}"; \ + target="{{ SRC_DIR }}/${rel%.sed}.rs"; \ + if [ -f "$target" ]; then \ + echo " [SED] ${rel%.sed}.rs"; \ + sed -i -f "$patch_file" "$target"; \ + else \ + echo "⚠ [WARN] target missing: $target"; \ + fi; \ + done + +build-sysroot: + RUSTFLAGS="-Zforce-unstable-if-unmarked -C relocation-model=pic -C link-arg=-pie" \ + cargo build --package std --target ../riscv64.json --features compiler-builtins-mem + mkdir -p ../sysroot/lib/rustlib/riscv64/lib + rm -rf ../sysroot/lib/rustlib/riscv64/lib/* + cp target/riscv64/debug/deps/*.rlib ../sysroot/lib/rustlib/riscv64/lib + +clean: + cargo clean + rm -rf ../sysroot/lib/rustlib/riscv64/lib/* + @for item in $(find library/std/src); do \ + basename_item=$(basename "$item"); \ + keep=0; \ + for protected in {{ KEEP_FILES }}; do \ + echo $basename_item = $protected; \ + if [ "$basename_item" = "$protected" ]; then keep=1; break; fi; \ + done; \ + if [ "$keep" -eq 0 ]; then \ + rm -rf "$item"; \ + fi; \ + done + rm -f std/build.rs std/Cargo.toml Cargo.toml + @for item in {{ ROOT_LINKS }}; do rm -rf $item; done + +# --- Helpers --- + +cp_std path: + @mkdir -p {{ SRC_DIR / parent_directory(path) }} + @ln -fs {{ RUST_SRC / "std/src" / path }} {{ parent_directory(SRC_DIR / path) }} + +real_cp_std path: + @mkdir -p {{ SRC_DIR / parent_directory(path) }} + @cp -r {{ RUST_SRC / "std/src" / path }} {{ SRC_DIR / path }} diff --git a/library/std/.gitignore b/library/std/.gitignore new file mode 100644 index 0000000..16ddd3e --- /dev/null +++ b/library/std/.gitignore @@ -0,0 +1,146 @@ +Cargo.lock +Cargo.toml +build.rs +target +src/random.rs +src/num +src/prelude +src/sync +src/fs.rs +src/alloc.rs +src/process +src/backtrace.rs +src/ascii.rs +src/bstr.rs +src/thread +src/keyword_docs.rs +src/tests_helpers.rs +src/error.rs +src/net +src/rt.rs +src/sys/args +src/sys/args/mod.rs +src/sys/args/unsupported.rs +src/sys/thread_local +src/sys/thread_local/os.rs +src/sys/thread_local/no_threads.rs +src/sys/thread_local/mod.rs +src/sys/platform_version +src/sys/platform_version/mod.rs +src/sys/personality +src/sys/personality/dwarf +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/pal/mod.rs +src/sys/pal/unsupported +src/sys/pal/unsupported/os.rs +src/sys/pal/unsupported/mod.rs +src/sys/pal/unsupported/common.rs +src/sys/sync +src/sys/sync/condvar +src/sys/sync/condvar/no_threads.rs +src/sys/sync/condvar/mod.rs +src/sys/sync/mutex +src/sys/sync/mutex/no_threads.rs +src/sys/sync/mutex/mod.rs +src/sys/sync/once_box.rs +src/sys/sync/rwlock +src/sys/sync/rwlock/no_threads.rs +src/sys/sync/rwlock/mod.rs +src/sys/sync/mod.rs +src/sys/sync/thread_parking +src/sys/sync/thread_parking/mod.rs +src/sys/sync/thread_parking/unsupported.rs +src/sys/sync/once +src/sys/sync/once/no_threads.rs +src/sys/sync/once/mod.rs +src/sys/fd +src/sys/fd/mod.rs +src/sys/process +src/sys/process/mod.rs +src/sys/process/env.rs +src/sys/process/unsupported.rs +src/sys/pipe +src/sys/pipe/mod.rs +src/sys/pipe/unsupported.rs +src/sys/env_consts.rs +src/sys/backtrace.rs +src/sys/exit.rs +src/sys/thread +src/sys/thread/mod.rs +src/sys/thread/unsupported.rs +src/sys/env +src/sys/env/mod.rs +src/sys/env/common.rs +src/sys/env/unsupported.rs +src/sys/net +src/sys/net/hostname +src/sys/net/hostname/mod.rs +src/sys/net/hostname/unsupported.rs +src/sys/net/mod.rs +src/sys/net/connection +src/sys/net/connection/mod.rs +src/sys/net/connection/unsupported.rs +src/sys/path +src/sys/path/mod.rs +src/sys/path/unix.rs +src/sys/configure_builtins.rs +src/sys/mod.rs +src/sys/time +src/sys/time/mod.rs +src/sys/time/unsupported.rs +src/sys/stdio +src/sys/stdio/mod.rs +src/sys/stdio/unsupported.rs +src/sys/cmath.rs +src/sys/alloc/mod.rs +src/sys/helpers +src/sys/helpers/mod.rs +src/sys/helpers/wstr.rs +src/sys/helpers/tests.rs +src/sys/helpers/small_c_string.rs +src/sys/fs +src/sys/fs/mod.rs +src/sys/fs/common.rs +src/sys/fs/unsupported.rs +src/sys/random +src/sys/random/mod.rs +src/sys/random/unsupported.rs +src/sys/io +src/sys/io/is_terminal +src/sys/io/is_terminal/unsupported.rs +src/sys/io/mod.rs +src/sys/io/io_slice +src/sys/io/io_slice/unsupported.rs +src/sys/io/error +src/sys/io/error/mod.rs +src/sys/io/error/generic.rs +src/sys/io/kernel_copy +src/sys/io/kernel_copy/mod.rs +src/sys/os_str +src/sys/os_str/mod.rs +src/sys/os_str/bytes +src/sys/os_str/bytes/tests.rs +src/sys/os_str/bytes.rs +src/macros.rs +src/os +src/os/mod.rs +src/os/raw +src/os/raw/mod.rs +src/os/raw/tests.rs +src/backtrace +src/path.rs +src/lib.rs +src/process.rs +src/ffi +src/env.rs +src/pat.rs +src/fs +src/panic.rs +src/collections +src/panicking.rs +src/time.rs +src/io +src/hash diff --git a/library/std/patches/sys/alloc/mod.sed b/library/std/patches/sys/alloc/mod.sed new file mode 100644 index 0000000..22d2e31 --- /dev/null +++ b/library/std/patches/sys/alloc/mod.sed @@ -0,0 +1,3 @@ +109a \ target_os = "survos" => { \ + mod survos; \ + } 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/src/sys/alloc/survos.rs b/library/std/src/sys/alloc/survos.rs new file mode 100644 index 0000000..6b92ca8 --- /dev/null +++ b/library/std/src/sys/alloc/survos.rs @@ -0,0 +1,104 @@ +#![allow(fuzzy_provenance_casts)] + +use crate::alloc::{GlobalAlloc, Layout, System}; + +#[stable(feature = "alloc_system_type", since = "1.28.0")] +unsafe impl GlobalAlloc for System { + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + alloc(layout) + } + + unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { + dealloc(ptr, layout) + } +} + +#[repr(u64)] +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, + WriteTemp = 999, + Unimplemented = 1 << 31, +} + +#[allow(clippy::too_many_arguments)] +unsafe fn _syscall( + syscall: SysCall, + mut a1: u64, + mut a2: u64, + mut a3: u64, + mut a4: u64, + mut a5: u64, + mut a6: u64, + mut a7: u64, +) -> (u64, u64, u64, u64, u64, u64, u64, u64) { + let mut a0 = syscall as u64; + unsafe { + core::arch::asm!( + "ecall", + inlateout("a0") a0, + inlateout("a1") a1, + inlateout("a2") a2, + inlateout("a3") a3, + inlateout("a4") a4, + inlateout("a5") a5, + inlateout("a6") a6, + inlateout("a7") a7, + clobber_abi("system") + ); + } + (a0, a1, a2, a3, a4, a5, a6, a7) +} + +macro_rules! syscall { + ($syscall:expr, $a1:expr, $a2:expr, $a3:expr, $a4:expr, $a5:expr, $a6:expr, $a7:expr) => { + _syscall($syscall, $a1, $a2, $a3, $a4, $a5, $a6, $a7) + }; + ($syscall:expr, $a1:expr, $a2:expr, $a3:expr, $a4:expr, $a5:expr, $a6:expr) => { + syscall!($syscall, $a1, $a2, $a3, $a4, $a5, $a6, 0) + }; + ($syscall:expr, $a1:expr, $a2:expr, $a3:expr, $a4:expr, $a5:expr) => { + syscall!($syscall, $a1, $a2, $a3, $a4, $a5, 0) + }; + ($syscall:expr, $a1:expr, $a2:expr, $a3:expr, $a4:expr) => { + syscall!($syscall, $a1, $a2, $a3, $a4, 0) + }; + ($syscall:expr, $a1:expr, $a2:expr, $a3:expr) => { + syscall!($syscall, $a1, $a2, $a3, 0) + }; + ($syscall:expr, $a1:expr, $a2:expr) => { + syscall!($syscall, $a1, $a2, 0) + }; + ($syscall:expr, $a1:expr) => { + syscall!($syscall, $a1, 0) + }; + ($syscall:expr) => { + syscall!($syscall, 0) + }; +} + +fn alloc(layout: Layout) -> *mut u8 { + unsafe { + let size = layout.size(); + let align = layout.align(); + let (ptr, ..) = syscall!(SysCall::Alloc, size as u64, align as u64); + ptr as *mut u8 + } +} +fn dealloc(ptr: *mut u8, layout: core::alloc::Layout) { + unsafe { + let size = layout.size(); + let align = layout.align(); + syscall!(SysCall::Dealloc, ptr as u64, size as u64, align as u64); + } +} 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) - // ); }