From d42fc79c255906766daa5fdc324c3cd22bcb6e84 Mon Sep 17 00:00:00 2001 From: Karina Date: Wed, 15 Apr 2026 14:44:10 +0400 Subject: [PATCH] WIP: Rust std for termos's userspace --- .gitignore | 3 +- CMakeLists.txt | 20 +++----- Runtime/rust/.cargo/config.toml | 20 +++++--- Runtime/rust/CMakeLists.txt | 48 +++++++------------ Runtime/rust/Cargo.lock | 42 ++++++++++++++-- Runtime/rust/Cargo.toml | 5 +- Runtime/rust/apps/rtest/Cargo.toml | 5 +- Runtime/rust/apps/rtest/src/lib.rs | 19 -------- Runtime/rust/apps/rtest/src/main.rs | 4 ++ Runtime/rust/rterm/src/lib.rs | 36 -------------- Runtime/rust/rust-toolchain.toml | 2 + Runtime/rust/{rterm => std}/Cargo.toml | 3 +- Runtime/rust/std/src/allocator.rs | 14 ++++++ Runtime/rust/std/src/io.rs | 30 ++++++++++++ Runtime/rust/std/src/lib.rs | 49 +++++++++++++++++++ Runtime/rust/std/src/panic.rs | 9 ++++ Runtime/rust/std/src/syscall.rs | 66 ++++++++++++++++++++++++++ Runtime/rust/x86_64-termos.json | 15 ++++++ System/CMakeLists.txt | 1 + 19 files changed, 273 insertions(+), 118 deletions(-) delete mode 100644 Runtime/rust/apps/rtest/src/lib.rs create mode 100644 Runtime/rust/apps/rtest/src/main.rs delete mode 100644 Runtime/rust/rterm/src/lib.rs create mode 100644 Runtime/rust/rust-toolchain.toml rename Runtime/rust/{rterm => std}/Cargo.toml (57%) create mode 100644 Runtime/rust/std/src/allocator.rs create mode 100644 Runtime/rust/std/src/io.rs create mode 100644 Runtime/rust/std/src/lib.rs create mode 100644 Runtime/rust/std/src/panic.rs create mode 100644 Runtime/rust/std/src/syscall.rs create mode 100644 Runtime/rust/x86_64-termos.json diff --git a/.gitignore b/.gitignore index a9af418..55c28a3 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,5 @@ build* initrd/image.cpio initramfs/* -target \ No newline at end of file +target +Cargo.lock \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index fd48f54..55f0f40 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -42,30 +42,22 @@ set(INITRAMFS_CPIO_FILE "${CMAKE_BINARY_DIR}/StartupVolume.cpio") set(IMG_FILE "${CMAKE_BINARY_DIR}/termOS.img") if(MCOPY_EXE AND MKFS_EXE AND CPIO_EXE) -add_custom_command( - OUTPUT ${INITRAMFS_CPIO_FILE} + add_custom_target(image ALL COMMAND ${CMAKE_COMMAND} -E make_directory ${VOLUME_ROOT} COMMAND sh -c "find . -mindepth 1 ! -name '*.cpio' -print0 | ${CPIO_EXE} --null -ov -H newc > \"${INITRAMFS_CPIO_FILE}\"" - WORKING_DIRECTORY ${VOLUME_ROOT} - DEPENDS ${SYSTEM_SERVICES} - VERBATIM - COMMENT "Packing StartupVolume to cpio..." - ) - - add_custom_command( - OUTPUT ${IMG_FILE} + COMMAND dd if=/dev/zero of=${IMG_FILE} bs=1M count=64 status=none COMMAND ${MKFS_EXE} -F 32 ${IMG_FILE} COMMAND mmd -i ${IMG_FILE} ::/EFI ::/EFI/BOOT COMMAND ${MCOPY_EXE} -i ${IMG_FILE} $ ::/EFI/BOOT/BOOTX64.EFI COMMAND ${MCOPY_EXE} -i ${IMG_FILE} ${CMAKE_BINARY_DIR}/bin/kernel.bin ::/kernel.bin COMMAND ${MCOPY_EXE} -i ${IMG_FILE} ${INITRAMFS_CPIO_FILE} ::/StartupVolume.cpio - DEPENDS BOOTX64 kernel ${INITRAMFS_CPIO_FILE} + + WORKING_DIRECTORY ${VOLUME_ROOT} + DEPENDS BOOTX64 kernel ${SYSTEM_SERVICES} VERBATIM - COMMENT "Generating bootable image: ${IMG_FILE}" + COMMENT "Packing initramfs and generating bootable image: ${IMG_FILE}" ) - - add_custom_target(image ALL DEPENDS ${IMG_FILE}) endif() if(QEMU_EXE) diff --git a/Runtime/rust/.cargo/config.toml b/Runtime/rust/.cargo/config.toml index a4c35ca..b5dda58 100644 --- a/Runtime/rust/.cargo/config.toml +++ b/Runtime/rust/.cargo/config.toml @@ -1,9 +1,15 @@ -[build] -target = "x86_64-unknown-none" +[env] +RUST_TARGET_PATH = { value = ".", relative = true } -[target.x86_64-unknown-none] -rustflags = [ - "-C", "code-model=small", - "-C", "relocation-model=static", - "-C", "no-redzone=y", +[build] +target = "x86_64-termos" + +[unstable] +build-std =["core", "alloc", "compiler_builtins"] +build-std-features = ["compiler-builtins-mem"] + +[target.x86_64-termos] +rustflags =[ + "-Z", "unstable-options", + "-C", "link-arg=-Tlinker.ld" ] \ No newline at end of file diff --git a/Runtime/rust/CMakeLists.txt b/Runtime/rust/CMakeLists.txt index c19fe16..59747e8 100644 --- a/Runtime/rust/CMakeLists.txt +++ b/Runtime/rust/CMakeLists.txt @@ -1,40 +1,26 @@ cmake_minimum_required(VERSION 3.16) -project(rustApps LANGUAGES C ASM_NASM) +project(rustApps NONE) function(add_rust_app NAME) - set(RUST_LIB_FILE "${CMAKE_CURRENT_SOURCE_DIR}/target/x86_64-unknown-none/release/lib${NAME}.a") - - add_custom_target(cargo_build_${NAME} ALL - COMMAND cargo build --package ${NAME} --release - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - BYPRODUCTS ${RUST_LIB_FILE} - COMMENT "Cargo: Building bare-metal Rust app '${NAME}'..." - ) - - add_library(rust_lib_${NAME} STATIC IMPORTED) - set_target_properties(rust_lib_${NAME} PROPERTIES IMPORTED_LOCATION ${RUST_LIB_FILE}) - add_dependencies(rust_lib_${NAME} cargo_build_${NAME}) - add_executable(${NAME} $) - set_target_properties(${NAME} PROPERTIES LINKER_LANGUAGE C) - target_link_libraries(${NAME} PRIVATE rust_lib_${NAME} term) - - target_link_options(${NAME} PRIVATE - -T ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld - -nostdlib - -static - -mno-red-zone - ) - - set(ELF2HOT_DIR "${CMAKE_SOURCE_DIR}/tools/elf2hot") - set(STARTUP_VOLUME_DIR "${CMAKE_BINARY_DIR}/StartupVolume/System/CoreServices") - file(MAKE_DIRECTORY "${STARTUP_VOLUME_DIR}") + set(RUST_TARGET "x86_64-termos") + set(RUST_ELF_FILE "${CMAKE_CURRENT_SOURCE_DIR}/target/${RUST_TARGET}/release/${NAME}") + set(STARTUP_VOLUME_DIR "${CMAKE_BINARY_DIR}/StartupVolume/System/CoreServices") set(FINAL_HOT_PATH "${STARTUP_VOLUME_DIR}/${NAME}") + set(STRIPPED_ELF "${CMAKE_CURRENT_BINARY_DIR}/${NAME}.stripped") + set(ELF2HOT_DIR "${CMAKE_SOURCE_DIR}/tools/elf2hot") - add_custom_command(TARGET ${NAME} POST_BUILD - COMMAND cargo run --release --quiet -- $ ${FINAL_HOT_PATH} - WORKING_DIRECTORY ${ELF2HOT_DIR} - COMMENT "elf2hot: Converting ${NAME} to HOT! format..." + file(MAKE_DIRECTORY "${STARTUP_VOLUME_DIR}") + + add_custom_target(${NAME} ALL + COMMAND cargo build --package ${NAME} --release --target ${RUST_TARGET} + + COMMAND objcopy --strip-all ${RUST_ELF_FILE} ${STRIPPED_ELF} + + COMMAND ${CMAKE_COMMAND} -E chdir ${ELF2HOT_DIR} cargo run --release --quiet -- ${STRIPPED_ELF} ${FINAL_HOT_PATH} + + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + COMMENT "Building, stripping and packing ${NAME} to initramfs..." VERBATIM ) endfunction() diff --git a/Runtime/rust/Cargo.lock b/Runtime/rust/Cargo.lock index 5d0533a..45eaf4b 100644 --- a/Runtime/rust/Cargo.lock +++ b/Runtime/rust/Cargo.lock @@ -3,12 +3,48 @@ version = 4 [[package]] -name = "rterm" -version = "0.1.0" +name = "linked_list_allocator" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b23ac50abb8261cb38c6e2a7192d3302e0836dac1628f6a93b82b4fad185897" +dependencies = [ + "spinning_top", +] + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] [[package]] name = "rtest" version = "0.1.0" dependencies = [ - "rterm", + "std", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "spinning_top" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b9eb1a2f4c41445a3a0ff9abc5221c5fcd28e1f13cd7c0397706f9ac938ddb0" +dependencies = [ + "lock_api", +] + +[[package]] +name = "std" +version = "0.1.0" +dependencies = [ + "linked_list_allocator", ] diff --git a/Runtime/rust/Cargo.toml b/Runtime/rust/Cargo.toml index 0dda78d..ec2f81d 100644 --- a/Runtime/rust/Cargo.toml +++ b/Runtime/rust/Cargo.toml @@ -1,4 +1,5 @@ [workspace] -members = ["rterm", "apps/rtest"] +members = ["std", "apps/rtest"] -resolver = "2" +[profile.release] +strip = true diff --git a/Runtime/rust/apps/rtest/Cargo.toml b/Runtime/rust/apps/rtest/Cargo.toml index dbd8979..7d369e2 100644 --- a/Runtime/rust/apps/rtest/Cargo.toml +++ b/Runtime/rust/apps/rtest/Cargo.toml @@ -3,8 +3,5 @@ name = "rtest" version = "0.1.0" edition = "2024" -[lib] -crate-type = ["staticlib"] - [dependencies] -rterm = { path = "../../rterm" } \ No newline at end of file +std = { path = "../../std" } \ No newline at end of file diff --git a/Runtime/rust/apps/rtest/src/lib.rs b/Runtime/rust/apps/rtest/src/lib.rs deleted file mode 100644 index b89f75a..0000000 --- a/Runtime/rust/apps/rtest/src/lib.rs +++ /dev/null @@ -1,19 +0,0 @@ -#![no_std] - -extern crate alloc; -use alloc::string::String; -use alloc::vec::Vec; - -extern crate rterm; - -#[unsafe(no_mangle)] -pub unsafe extern "C" fn main() -> i32 { - let mut my_vec = Vec::new(); - my_vec.push(1); - my_vec.push(2); - - let text = String::from("Hello from zalupa!"); - rterm::print_str(&text); - - 0 -} diff --git a/Runtime/rust/apps/rtest/src/main.rs b/Runtime/rust/apps/rtest/src/main.rs new file mode 100644 index 0000000..52ea6ff --- /dev/null +++ b/Runtime/rust/apps/rtest/src/main.rs @@ -0,0 +1,4 @@ +fn main() { + let anus = "jopa"; + println!("meow"); +} \ No newline at end of file diff --git a/Runtime/rust/rterm/src/lib.rs b/Runtime/rust/rterm/src/lib.rs deleted file mode 100644 index d32179a..0000000 --- a/Runtime/rust/rterm/src/lib.rs +++ /dev/null @@ -1,36 +0,0 @@ -#![no_std] - -extern crate alloc; - -use core::panic::PanicInfo; -use core::alloc::{GlobalAlloc, Layout}; - -unsafe extern "C" { - fn MemoryAllocate(size: usize) -> *mut u8; - fn MemoryFree(ptr: *mut u8); - fn ConsolePrintString(s: *const u8); -} - -struct TermosAllocator; - -unsafe impl GlobalAlloc for TermosAllocator { - unsafe fn alloc(&self, layout: Layout) -> *mut u8 { - MemoryAllocate(layout.size()) - } - - unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) { - MemoryFree(ptr); - } -} - -#[global_allocator] -static ALLOCATOR: TermosAllocator = TermosAllocator; - -#[panic_handler] -fn panic(_info: &PanicInfo) -> ! { - loop {} -} - -pub unsafe fn print_str(s: &str) { - ConsolePrintString(s.as_ptr()); -} \ No newline at end of file diff --git a/Runtime/rust/rust-toolchain.toml b/Runtime/rust/rust-toolchain.toml new file mode 100644 index 0000000..271800c --- /dev/null +++ b/Runtime/rust/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "nightly" \ No newline at end of file diff --git a/Runtime/rust/rterm/Cargo.toml b/Runtime/rust/std/Cargo.toml similarity index 57% rename from Runtime/rust/rterm/Cargo.toml rename to Runtime/rust/std/Cargo.toml index d654d5c..f3d0911 100644 --- a/Runtime/rust/rterm/Cargo.toml +++ b/Runtime/rust/std/Cargo.toml @@ -1,6 +1,7 @@ [package] -name = "rterm" +name = "std" version = "0.1.0" edition = "2024" [dependencies] +linked_list_allocator = "0.10.6" diff --git a/Runtime/rust/std/src/allocator.rs b/Runtime/rust/std/src/allocator.rs new file mode 100644 index 0000000..99ab718 --- /dev/null +++ b/Runtime/rust/std/src/allocator.rs @@ -0,0 +1,14 @@ +extern crate alloc; + +use core::alloc::{GlobalAlloc, Layout}; +use linked_list_allocator::LockedHeap; + +#[global_allocator] +static ALLOCATOR: LockedHeap = LockedHeap::empty(); + +pub unsafe fn init_heap() { + let heap_size = 1024 * 1024; + let heap_start = crate::syscall::memory_allocate(heap_size); + + ALLOCATOR.lock().init(heap_start as *mut u8, heap_size); +} \ No newline at end of file diff --git a/Runtime/rust/std/src/io.rs b/Runtime/rust/std/src/io.rs new file mode 100644 index 0000000..c9fd515 --- /dev/null +++ b/Runtime/rust/std/src/io.rs @@ -0,0 +1,30 @@ +use core::fmt::{self, Write}; + +pub struct Stdout; + +impl Write for Stdout { + fn write_str(&mut self, s: &str) -> fmt::Result { + crate::syscall::io_write(1, s.as_ptr(), s.len()); + Ok(()) + } +} + +#[doc(hidden)] +pub fn _print(args: core::fmt::Arguments) { + let mut stdout = crate::io::Stdout; + let _ = core::fmt::Write::write_fmt(&mut stdout, args); +} + +#[macro_export] +macro_rules! print { + ($($arg:tt)*) => ($crate::io::_print(core::format_args!($($arg)*))); +} + +#[macro_export] +macro_rules! println { + () => ($crate::print!("\n")); + ($($arg:tt)*) => { + $crate::print!($($arg)*); + $crate::print!("\n"); + }; +} \ No newline at end of file diff --git a/Runtime/rust/std/src/lib.rs b/Runtime/rust/std/src/lib.rs new file mode 100644 index 0000000..38c1cf1 --- /dev/null +++ b/Runtime/rust/std/src/lib.rs @@ -0,0 +1,49 @@ +#![no_std] +#![feature(lang_items)] + +pub use core::*; +extern crate alloc; +pub use alloc::*; + +pub mod allocator; +pub mod io; +pub mod panic; +pub mod syscall; + + +pub mod prelude { + pub mod rust_2024 { + pub use core::prelude::rust_2024::*; + pub use alloc::string::{String, ToString}; + pub use alloc::vec::Vec; + pub use alloc::vec; + pub use alloc::format; + pub use crate::{print, println}; + } +} + +core::arch::global_asm!( + ".global _start", + "_start:", + "and rsp, ~0xF", + "xor rdi, rdi", + "xor rsi, rsi", + "call main", + "mov rdi, rax", + "mov rax, 0", + "syscall" +); + +#[lang = "start"] +fn lang_start( + user_main: fn() -> T, + _argc: isize, + _argv: *const *const u8, + _sigpipe: u8, +) -> isize { + unsafe { crate::allocator::init_heap() }; + + user_main(); + + crate::syscall::process_exit(0); +} \ No newline at end of file diff --git a/Runtime/rust/std/src/panic.rs b/Runtime/rust/std/src/panic.rs new file mode 100644 index 0000000..65b3dda --- /dev/null +++ b/Runtime/rust/std/src/panic.rs @@ -0,0 +1,9 @@ +use core::panic::PanicInfo; +use crate::println; + +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { + println!("{}", info); + + crate::syscall::process_exit(1); +} \ No newline at end of file diff --git a/Runtime/rust/std/src/syscall.rs b/Runtime/rust/std/src/syscall.rs new file mode 100644 index 0000000..1293b41 --- /dev/null +++ b/Runtime/rust/std/src/syscall.rs @@ -0,0 +1,66 @@ +use core::arch::asm; + +pub const SYS_EXIT: usize = 0; +pub const SYS_SPAWN: usize = 1; +pub const SYS_ALLOC: usize = 2; +pub const SYS_WRITE: usize = 3; +pub const SYS_READ: usize = 4; +pub const SYS_WAIT: usize = 5; + +#[inline(always)] +unsafe fn syscall1(num: usize, arg1: usize) -> usize { + let ret: usize; + unsafe { + asm!( + "syscall", + inout("rax") num => ret, + in("rdi") arg1, + out("rcx") _, + out("r11") _, + options(nostack, preserves_flags) + ); + } + ret +} + +#[inline(always)] +unsafe fn syscall3(num: usize, arg1: usize, arg2: usize, arg3: usize) -> usize { + let ret: usize; + core::arch::asm!( + "syscall", + in("rax") num, + in("rdi") arg1, + in("rsi") arg2, + in("rdx") arg3, + lateout("rax") ret, + out("rcx") _, + out("r11") _, + options(nostack) + ); + ret +} + +pub fn process_exit(code: usize) -> ! { + unsafe { syscall1(SYS_EXIT, code) }; + loop {} +} + +pub fn process_spawn(path: usize) -> usize { + unsafe { syscall1(SYS_SPAWN, path) } +} + +pub fn process_wait(pid: usize) -> usize { + unsafe { syscall1(SYS_WAIT, pid) } +} + +pub fn memory_allocate(size: usize) -> usize { + unsafe { syscall1(SYS_ALLOC, size) } +} + +pub fn io_write(fd: usize, buf: *const u8, len: usize) -> usize { + unsafe { syscall3(SYS_WRITE, fd, buf as usize, len) } +} + +pub fn io_read(fd: usize, buf: *const u8, len: usize) -> usize { + unsafe { syscall3(SYS_READ, fd, buf as usize, len) } +} \ No newline at end of file diff --git a/Runtime/rust/x86_64-termos.json b/Runtime/rust/x86_64-termos.json new file mode 100644 index 0000000..185f7ff --- /dev/null +++ b/Runtime/rust/x86_64-termos.json @@ -0,0 +1,15 @@ +{ + "llvm-target": "x86_64-unknown-none", + "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128", + "arch": "x86_64", + "target-endian": "little", + "target-pointer-width": 64, + "target-c-int-width": 32, + "os": "termos", + "executables": true, + "linker-flavor": "ld.lld", + "linker": "rust-lld", + "panic-strategy": "abort", + "position-independent-executables": true, + "relocation-model": "pic" +} \ No newline at end of file diff --git a/System/CMakeLists.txt b/System/CMakeLists.txt index 3635de8..b3d896a 100644 --- a/System/CMakeLists.txt +++ b/System/CMakeLists.txt @@ -47,6 +47,7 @@ target_compile_options(kernel PRIVATE -Wall -Wextra -mcmodel=kernel -g + -mno-sse -mno-sse2 -msoft-float > )