From 8cf293cb6c10e61000f7cc8a7ba0f325cdf09ab3 Mon Sep 17 00:00:00 2001 From: zhanghx0905 <731931282@qq.com> Date: Fri, 19 Nov 2021 21:35:57 +0800 Subject: [PATCH] update user module to 2021autumn version --- .gitignore | 17 +--- os/Makefile | 8 +- os/src/config.rs | 2 +- os/src/syscall/mod.rs | 4 +- os/src/syscall/process.rs | 20 +++- os/src/timer.rs | 6 +- user/Cargo.toml | 4 +- user/Makefile | 29 ++++-- user/src/bin/test_exit0.rs | 17 ++++ user/src/bin/test_exit1.rs | 17 ++++ user/src/bin/test_file0.rs | 31 ++++++ user/src/bin/test_file1.rs | 26 +++++ user/src/bin/test_file2.rs | 46 +++++++++ user/src/bin/test_getpid.rs | 18 ++++ user/src/bin/test_mail0.rs | 27 +++++ user/src/bin/test_mail1.rs | 28 ++++++ user/src/bin/test_mail2.rs | 60 +++++++++++ user/src/bin/test_mail3.rs | 34 +++++++ user/src/bin/test_mmap0.rs | 33 ++++++ user/src/bin/test_mmap1.rs | 25 +++++ user/src/bin/test_mmap2.rs | 26 +++++ user/src/bin/test_mmap3.rs | 25 +++++ user/src/bin/test_sleep.rs | 24 +++++ user/src/bin/test_sleep1.rs | 22 ++++ user/src/bin/test_spawn0.rs | 29 ++++++ user/src/bin/test_spawn1.rs | 35 +++++++ user/src/bin/test_unmap.rs | 36 +++++++ user/src/bin/test_unmap2.rs | 23 +++++ user/src/bin/test_usertest.rs | 51 ++++++++++ user/src/bin/test_write1.rs | 31 ++++++ user/src/bin/user_shell.rs | 60 +++++------ user/src/bin/usertests.rs | 19 +++- user/src/console.rs | 51 ++++++++-- user/src/lang_items.rs | 9 +- user/src/lib.rs | 182 +++++++++++++++++++++++++++++----- user/src/syscall.rs | 156 +++++++++++++++++++++++------ 36 files changed, 1101 insertions(+), 130 deletions(-) create mode 100644 user/src/bin/test_exit0.rs create mode 100644 user/src/bin/test_exit1.rs create mode 100644 user/src/bin/test_file0.rs create mode 100644 user/src/bin/test_file1.rs create mode 100644 user/src/bin/test_file2.rs create mode 100644 user/src/bin/test_getpid.rs create mode 100644 user/src/bin/test_mail0.rs create mode 100644 user/src/bin/test_mail1.rs create mode 100644 user/src/bin/test_mail2.rs create mode 100644 user/src/bin/test_mail3.rs create mode 100644 user/src/bin/test_mmap0.rs create mode 100644 user/src/bin/test_mmap1.rs create mode 100644 user/src/bin/test_mmap2.rs create mode 100644 user/src/bin/test_mmap3.rs create mode 100644 user/src/bin/test_sleep.rs create mode 100644 user/src/bin/test_sleep1.rs create mode 100644 user/src/bin/test_spawn0.rs create mode 100644 user/src/bin/test_spawn1.rs create mode 100644 user/src/bin/test_unmap.rs create mode 100644 user/src/bin/test_unmap2.rs create mode 100644 user/src/bin/test_usertest.rs create mode 100644 user/src/bin/test_write1.rs diff --git a/.gitignore b/.gitignore index 489e9b75..850a4907 100644 --- a/.gitignore +++ b/.gitignore @@ -1,14 +1,7 @@ -.idea/* -os/target/* -os/.idea/* +.idea +Cargo.lock +target os/src/link_app.S os/last-* -os/Cargo.lock -user/target/* -user/.idea/* -user/Cargo.lock -easy-fs/Cargo.lock -easy-fs/target/* -easy-fs-fuse/Cargo.lock -easy-fs-fuse/target/* -tools/ +user/build +tools diff --git a/os/Makefile b/os/Makefile index e3434de3..3120db44 100644 --- a/os/Makefile +++ b/os/Makefile @@ -32,7 +32,9 @@ OBJCOPY := rust-objcopy --binary-architecture=riscv64 # Disassembly DISASM ?= -x -build: env switch-check $(KERNEL_BIN) fs-img +TEST ?= 0 + +build: env switch-check $(KERNEL_BIN) fs-img switch-check: ifeq ($(BOARD), qemu) @@ -56,9 +58,9 @@ $(KERNEL_BIN): kernel @$(OBJCOPY) $(KERNEL_ELF) --strip-all -O binary $@ fs-img: $(APPS) - @cd ../user && make build + @cd ../user && make build TEST=$(TEST) @rm $(FS_IMG) -f - @cd ../easy-fs-fuse && cargo run --release -- -s ../user/src/bin/ -t ../user/target/riscv64gc-unknown-none-elf/release/ + @cd ../easy-fs-fuse && cargo run --release -- -s ../user/build/app/ -t ../user/target/riscv64gc-unknown-none-elf/release/ $(APPS): diff --git a/os/src/config.rs b/os/src/config.rs index dce95ec4..2cff167c 100644 --- a/os/src/config.rs +++ b/os/src/config.rs @@ -3,7 +3,7 @@ pub const USER_STACK_SIZE: usize = 4096 * 2; pub const KERNEL_STACK_SIZE: usize = 4096 * 2; pub const KERNEL_HEAP_SIZE: usize = 0x20_0000; -pub const MEMORY_END: usize = 0x80800000; +pub const MEMORY_END: usize = 0x80f00000; pub const PAGE_SIZE: usize = 0x1000; pub const PAGE_SIZE_BITS: usize = 0xc; diff --git a/os/src/syscall/mod.rs b/os/src/syscall/mod.rs index 4683d055..097be0b2 100644 --- a/os/src/syscall/mod.rs +++ b/os/src/syscall/mod.rs @@ -21,14 +21,14 @@ use process::*; pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize { match syscall_id { SYSCALL_DUP=> sys_dup(args[0]), - SYSCALL_OPEN => sys_open(args[0] as *const u8, args[1] as u32), + SYSCALL_OPEN => sys_open(args[1] as *const u8, args[2] as u32), SYSCALL_CLOSE => sys_close(args[0]), SYSCALL_PIPE => sys_pipe(args[0] as *mut usize), SYSCALL_READ => sys_read(args[0], args[1] as *const u8, args[2]), SYSCALL_WRITE => sys_write(args[0], args[1] as *const u8, args[2]), SYSCALL_EXIT => sys_exit(args[0] as i32), SYSCALL_YIELD => sys_yield(), - SYSCALL_GET_TIME => sys_get_time(), + SYSCALL_GET_TIME => sys_get_time(args[0] as *mut TimeVal, args[1]), SYSCALL_GETPID => sys_getpid(), SYSCALL_FORK => sys_fork(), SYSCALL_EXEC => sys_exec(args[0] as *const u8, args[1] as *const usize), diff --git a/os/src/syscall/process.rs b/os/src/syscall/process.rs index cf3cbcb4..83b89d28 100644 --- a/os/src/syscall/process.rs +++ b/os/src/syscall/process.rs @@ -5,7 +5,7 @@ use crate::task::{ current_user_token, add_task, }; -use crate::timer::get_time_ms; +use crate::timer::get_time_us; use crate::mm::{ translated_str, translated_refmut, @@ -19,6 +19,13 @@ use alloc::sync::Arc; use alloc::vec::Vec; use alloc::string::String; +#[repr(C)] +#[derive(Debug)] +pub struct TimeVal { + pub sec: usize, + pub usec: usize, +} + pub fn sys_exit(exit_code: i32) -> ! { exit_current_and_run_next(exit_code); panic!("Unreachable in sys_exit!"); @@ -29,8 +36,15 @@ pub fn sys_yield() -> isize { 0 } -pub fn sys_get_time() -> isize { - get_time_ms() as isize +pub fn sys_get_time(_ts: *mut TimeVal, _tz: usize) -> isize { + let _us = get_time_us(); + // unsafe { + // *ts = TimeVal { + // sec: us / 1_000_000, + // usec: us % 1_000_000, + // }; + // } + 0 } pub fn sys_getpid() -> isize { diff --git a/os/src/timer.rs b/os/src/timer.rs index 92d50e3a..c8b2afe3 100644 --- a/os/src/timer.rs +++ b/os/src/timer.rs @@ -3,14 +3,14 @@ use crate::sbi::set_timer; use crate::config::CLOCK_FREQ; const TICKS_PER_SEC: usize = 100; -const MSEC_PER_SEC: usize = 1000; +const MICRO_PER_SEC: usize = 1_000_000; pub fn get_time() -> usize { time::read() } -pub fn get_time_ms() -> usize { - time::read() / (CLOCK_FREQ / MSEC_PER_SEC) +pub fn get_time_us() -> usize { + time::read() / (CLOCK_FREQ / MICRO_PER_SEC) } pub fn set_next_trigger() { diff --git a/user/Cargo.toml b/user/Cargo.toml index d50a0ba0..01b75c29 100644 --- a/user/Cargo.toml +++ b/user/Cargo.toml @@ -8,4 +8,6 @@ edition = "2018" [dependencies] buddy_system_allocator = "0.6" -bitflags = "1.2.1" \ No newline at end of file +bitflags = "1.2.1" +spin = "0.9" +lazy_static = { version = "1.4.0", features = ["spin_no_std"] } diff --git a/user/Makefile b/user/Makefile index e2eaf994..61dc2435 100644 --- a/user/Makefile +++ b/user/Makefile @@ -2,22 +2,39 @@ TARGET := riscv64gc-unknown-none-elf MODE := release APP_DIR := src/bin TARGET_DIR := target/$(TARGET)/$(MODE) -APPS := $(wildcard $(APP_DIR)/*.rs) -ELFS := $(patsubst $(APP_DIR)/%.rs, $(TARGET_DIR)/%, $(APPS)) -BINS := $(patsubst $(APP_DIR)/%.rs, $(TARGET_DIR)/%.bin, $(APPS)) - +BUILD_DIR := build OBJDUMP := rust-objdump --arch-name=riscv64 OBJCOPY := rust-objcopy --binary-architecture=riscv64 +PY := python3 + +TEST ?= 0 +ifeq ($(TEST), 0) + APPS := $(filter-out $(wildcard $(APP_DIR)/test*.rs), $(wildcard $(APP_DIR)/*.rs)) +else + APPS := $(wildcard $(APP_DIR)/test*.rs) $(APP_DIR)/initproc.rs $(APP_DIR)/user_shell.rs +endif +ELFS := $(patsubst $(APP_DIR)/%.rs, $(TARGET_DIR)/%, $(APPS)) elf: $(APPS) @cargo build --release binary: elf - $(foreach elf, $(ELFS), $(OBJCOPY) $(elf) --strip-all -O binary $(patsubst $(TARGET_DIR)/%, $(TARGET_DIR)/%.bin, $(elf));) + @$(foreach elf, $(ELFS), \ + $(OBJCOPY) $(elf) --strip-all -O binary $(patsubst $(TARGET_DIR)/%, $(TARGET_DIR)/%.bin, $(elf)); \ + cp $(elf) $(patsubst $(TARGET_DIR)/%, $(TARGET_DIR)/%.elf, $(elf));) -build: binary +pre: + @mkdir -p $(BUILD_DIR)/bin/ + @mkdir -p $(BUILD_DIR)/elf/ + @mkdir -p $(BUILD_DIR)/app/ + @$(foreach t, $(APPS), cp $(t) $(BUILD_DIR)/app/;) + +build: clean pre binary + @$(foreach t, $(ELFS), cp $(t).bin $(BUILD_DIR)/bin/;) + @$(foreach t, $(ELFS), cp $(t).elf $(BUILD_DIR)/elf/;) clean: @cargo clean + @rm -rf $(BUILD_DIR) .PHONY: elf binary build clean diff --git a/user/src/bin/test_exit0.rs b/user/src/bin/test_exit0.rs new file mode 100644 index 00000000..3bae851f --- /dev/null +++ b/user/src/bin/test_exit0.rs @@ -0,0 +1,17 @@ +#![no_std] +#![no_main] + +extern crate user_lib; +use user_lib::exit; + +/* +辅助测例,正常退出,不输出 FAIL 即可。 +*/ + +#[allow(unreachable_code)] +#[no_mangle] +pub fn main() -> i32 { + exit(66778); + panic!("FAIL: T.T\n"); + 0 +} diff --git a/user/src/bin/test_exit1.rs b/user/src/bin/test_exit1.rs new file mode 100644 index 00000000..47c09cb5 --- /dev/null +++ b/user/src/bin/test_exit1.rs @@ -0,0 +1,17 @@ +#![no_std] +#![no_main] + +extern crate user_lib; +use user_lib::exit; + +/* +辅助测例,正常退出,不输出 FAIL 即可。 +*/ + +#[allow(unreachable_code)] +#[no_mangle] +pub fn main() -> i32 { + exit(-233); + panic!("FAIL: T.T\n"); + 0 +} diff --git a/user/src/bin/test_file0.rs b/user/src/bin/test_file0.rs new file mode 100644 index 00000000..0b61fc92 --- /dev/null +++ b/user/src/bin/test_file0.rs @@ -0,0 +1,31 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +use user_lib::{close, open, read, write, OpenFlags}; + +/// 测试文件基本读写,输出 Test file0 OK! 就算正确。 + +#[no_mangle] +pub fn main() -> i32 { + let test_str = "Hello, world!"; + let fname = "fname\0"; + let fd = open(fname, OpenFlags::CREATE | OpenFlags::WRONLY); + assert!(fd > 0); + let fd = fd as usize; + write(fd, test_str.as_bytes()); + close(fd); + + let fd = open(fname, OpenFlags::RDONLY); + assert!(fd > 0); + let fd = fd as usize; + let mut buffer = [0u8; 100]; + let read_len = read(fd, &mut buffer) as usize; + close(fd); + + assert_eq!(test_str, core::str::from_utf8(&buffer[..read_len]).unwrap(),); + println!("Test file0 OK!"); + 0 +} diff --git a/user/src/bin/test_file1.rs b/user/src/bin/test_file1.rs new file mode 100644 index 00000000..6565121a --- /dev/null +++ b/user/src/bin/test_file1.rs @@ -0,0 +1,26 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; +use user_lib::{close, fstat, open, OpenFlags, Stat, StatMode}; + +/// 测试 fstat,输出 Test fstat OK! 就算正确。 + +#[no_mangle] +pub fn main() -> i32 { + let fname = "fname1\0"; + let fd = open(fname, OpenFlags::CREATE | OpenFlags::WRONLY); + assert!(fd > 0); + let fd = fd as usize; + let stat: Stat = Stat::new(); + let ret = fstat(fd, &stat); + assert_eq!(ret, 0); + assert_eq!(stat.mode, StatMode::FILE); + assert_eq!(stat.nlink, 1); + close(fd); + // unlink(fname); + // It's recommended to rebuild the disk image. This program will not clean the file "fname1". + println!("Test fstat OK!"); + 0 +} diff --git a/user/src/bin/test_file2.rs b/user/src/bin/test_file2.rs new file mode 100644 index 00000000..c6463141 --- /dev/null +++ b/user/src/bin/test_file2.rs @@ -0,0 +1,46 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; +use user_lib::{close, fstat, link, open, read, unlink, write, OpenFlags, Stat}; + +/// 测试 link/unlink,输出 Test link OK! 就算正确。 + +#[no_mangle] +pub fn main() -> i32 { + let test_str = "Hello, world!"; + let fname = "fname2\0"; + let (lname0, lname1, lname2) = ("linkname0\0", "linkname1\0", "linkname2\0"); + let fd = open(fname, OpenFlags::CREATE | OpenFlags::WRONLY) as usize; + link(fname, lname0); + let stat = Stat::new(); + fstat(fd, &stat); + assert_eq!(stat.nlink, 2); + link(fname, lname1); + link(fname, lname2); + fstat(fd, &stat); + assert_eq!(stat.nlink, 4); + write(fd, test_str.as_bytes()); + close(fd); + + unlink(fname); + let fd = open(lname0, OpenFlags::RDONLY) as usize; + let stat2 = Stat::new(); + let mut buf = [0u8; 100]; + let read_len = read(fd, &mut buf) as usize; + assert_eq!(test_str, core::str::from_utf8(&buf[..read_len]).unwrap(),); + fstat(fd, &stat2); + assert_eq!(stat2.dev, stat.dev); + assert_eq!(stat2.ino, stat.ino); + assert_eq!(stat2.nlink, 3); + unlink(lname1); + unlink(lname2); + fstat(fd, &stat2); + assert_eq!(stat2.nlink, 1); + close(fd); + unlink(lname0); + // It's Ok if you don't delete the inode and data blocks. + println!("Test link OK!"); + 0 +} diff --git a/user/src/bin/test_getpid.rs b/user/src/bin/test_getpid.rs new file mode 100644 index 00000000..66ee7323 --- /dev/null +++ b/user/src/bin/test_getpid.rs @@ -0,0 +1,18 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +use user_lib::getpid; + +/* +辅助测例 打印子进程 pid +*/ + +#[no_mangle] +pub fn main() -> i32 { + let pid = getpid(); + println!("Test getpid OK! pid = {}", pid); + 0 +} diff --git a/user/src/bin/test_mail0.rs b/user/src/bin/test_mail0.rs new file mode 100644 index 00000000..420f285b --- /dev/null +++ b/user/src/bin/test_mail0.rs @@ -0,0 +1,27 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +use user_lib::{getpid, mail_read, mail_write}; + +const BUF_LEN: usize = 256; + +/// 测试邮箱基本功能,输出 mail0 test OK! 就算正确。 + +#[no_mangle] +fn main() -> i32 { + let pid = getpid(); + let buffer0 = ['a' as u8; 27]; + assert_eq!(mail_write(pid as usize, &buffer0), 27); + let buffer1 = ['b' as u8; BUF_LEN + 1]; + assert_eq!(mail_write(pid as usize, &buffer1), BUF_LEN as isize); + let mut buf = [0u8; BUF_LEN]; + assert_eq!(mail_read(&mut buf), 27); + assert_eq!(buf[..27], buffer0); + assert_eq!(mail_read(&mut buf[..27]), 27); + assert_eq!(buf[..27], buffer1[..27]); + println!("mail0 test OK!"); + 0 +} diff --git a/user/src/bin/test_mail1.rs b/user/src/bin/test_mail1.rs new file mode 100644 index 00000000..3e02ba92 --- /dev/null +++ b/user/src/bin/test_mail1.rs @@ -0,0 +1,28 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +use user_lib::{getpid, mail_read, mail_write}; + +const BUF_LEN: usize = 256; +const MAIL_MAX: usize = 16; + +/// 测试邮箱容量,输出 mail1 test OK! 就算正确。 + +#[no_mangle] +fn main() -> i32 { + let pid = getpid(); + let buffer0 = ['a' as u8; BUF_LEN]; + for _ in 0..MAIL_MAX { + assert_eq!(mail_write(pid as usize, &buffer0), BUF_LEN as isize); + } + assert_eq!(mail_write(pid as usize, &buffer0), -1); + let mut buf = [0u8; BUF_LEN]; + assert_eq!(mail_read(&mut buf), BUF_LEN as isize); + assert_eq!(mail_write(pid as usize, &buffer0), BUF_LEN as isize); + assert_eq!(mail_write(pid as usize, &buffer0), -1); + println!("mail1 test OK!"); + 0 +} diff --git a/user/src/bin/test_mail2.rs b/user/src/bin/test_mail2.rs new file mode 100644 index 00000000..4a51193a --- /dev/null +++ b/user/src/bin/test_mail2.rs @@ -0,0 +1,60 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +use user_lib::{exit, fork, mail_read, mail_write, sleep, wait}; + +const BUF_LEN: usize = 256; + +// 双进程邮箱测试,最终输出 mail2 test OK! 就算正确。 + +#[no_mangle] +fn main() -> i32 { + let pid = fork(); + if pid == 0 { + println!("I am child"); + let mut buffer = [0u8; BUF_LEN]; + assert_eq!(mail_read(&mut buffer), -1); + println!("child read 1 mail fail"); + println!("child sleep 2s"); + sleep(2000 as usize); + for i in 0..16 { + let mut buffer = [0u8; BUF_LEN]; + assert_eq!(mail_read(&mut buffer), BUF_LEN as isize); + assert_eq!(buffer, [i as u8; BUF_LEN]); + } + println!("child read 16 mails succeed"); + assert_eq!(mail_read(&mut buffer), -1); + println!("child read 1 mail fail"); + println!("child sleep 1s"); + sleep(1000 as usize); + assert_eq!(mail_read(&mut buffer), BUF_LEN as isize); + assert_eq!(buffer, [16 as u8; BUF_LEN]); + println!("child read 1 mail succeed"); + println!("child exit"); + exit(0); + } + println!("I am father"); + println!("father sleep 1s"); + sleep(1000 as usize); + for i in 0..16 { + let buffer = [i as u8; BUF_LEN]; + assert_eq!(mail_write(pid as usize, &buffer), BUF_LEN as isize); + } + println!("father wirte 16 mails succeed"); + let buffer = [16 as u8; BUF_LEN]; + assert_eq!(mail_write(pid as usize, &buffer), -1); + println!("father wirte 1 mail fail"); + println!("father sleep 1.5s"); + sleep(1500 as usize); + assert_eq!(mail_write(pid as usize, &buffer), BUF_LEN as isize); + println!("father wirte 1 mail succeed"); + + let mut xstate: i32 = -100; + assert!(wait(&mut xstate) > 0); + assert_eq!(xstate, 0); + println!("mail2 test OK!"); + 0 +} diff --git a/user/src/bin/test_mail3.rs b/user/src/bin/test_mail3.rs new file mode 100644 index 00000000..b8a7979e --- /dev/null +++ b/user/src/bin/test_mail3.rs @@ -0,0 +1,34 @@ +#![no_std] +#![no_main] + +extern crate core; +#[macro_use] +extern crate user_lib; + +use core::slice; +use user_lib::{getpid, mail_read, mail_write}; + +const BUF_LEN: usize = 256; +const MAIL_MAX: usize = 16; +const BAD_ADDRESS: usize = 0x90000000; + +/// 邮箱错误参数测试,输出 mail3 test OK! 就算正确。 + +#[no_mangle] +fn main() -> i32 { + let pid = getpid(); + let null = unsafe { slice::from_raw_parts(BAD_ADDRESS as *const _, 10) }; + assert_eq!(mail_write(pid as usize, &null), -1); + let mut empty = ['a' as u8; 0]; + assert_eq!(mail_write(pid as usize, &empty), 0); + assert_eq!(mail_read(&mut empty), -1); + let buffer0 = ['a' as u8; BUF_LEN]; + for _ in 0..MAIL_MAX { + assert_eq!(mail_write(pid as usize, &buffer0), BUF_LEN as isize); + } + assert_eq!(mail_write(pid as usize, &empty), -1); + assert_eq!(mail_read(&mut empty), 0); + assert_eq!(mail_write(pid as usize, &empty), -1); + println!("mail3 test OK!"); + 0 +} diff --git a/user/src/bin/test_mmap0.rs b/user/src/bin/test_mmap0.rs new file mode 100644 index 00000000..5247eec2 --- /dev/null +++ b/user/src/bin/test_mmap0.rs @@ -0,0 +1,33 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +use user_lib::mmap; + +/* +理想结果:输出 Test 04_1 OK! +*/ + +#[no_mangle] +fn main() -> i32 { + let start: usize = 0x10000000; + let len: usize = 4096; + let prot: usize = 3; + assert_eq!(0, mmap(start, len, prot)); + for i in start..(start + len) { + let addr: *mut u8 = i as *mut u8; + unsafe { + *addr = i as u8; + } + } + for i in start..(start + len) { + let addr: *mut u8 = i as *mut u8; + unsafe { + assert_eq!(*addr, i as u8); + } + } + println!("Test 04_1 OK!"); + 0 +} diff --git a/user/src/bin/test_mmap1.rs b/user/src/bin/test_mmap1.rs new file mode 100644 index 00000000..63d6411d --- /dev/null +++ b/user/src/bin/test_mmap1.rs @@ -0,0 +1,25 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +use user_lib::mmap; + +/* +理想结果:程序触发访存异常,被杀死。不输出 error 就算过。 +*/ + +#[no_mangle] +fn main() -> i32 { + let start: usize = 0x10000000; + let len: usize = 4096; + let prot: usize = 1; + assert_eq!(0, mmap(start, len, prot)); + let addr: *mut u8 = start as *mut u8; + unsafe { + *addr = start as u8; + } + println!("Should cause error, Test 04_2 fail!"); + 0 +} diff --git a/user/src/bin/test_mmap2.rs b/user/src/bin/test_mmap2.rs new file mode 100644 index 00000000..2489fa64 --- /dev/null +++ b/user/src/bin/test_mmap2.rs @@ -0,0 +1,26 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +use user_lib::mmap; + +/* +理想结果:程序触发访存异常,被杀死。不输出 error 就算过。 +*/ + +#[no_mangle] +fn main() -> i32 { + let start: usize = 0x10000000; + let len: usize = 4096; + let prot: usize = 2; + assert_eq!(0, mmap(start, len, prot)); + let addr: *mut u8 = start as *mut u8; + unsafe { + // *addr = start as u8; // can't write, R == 0 && W == 1 is illegal in riscv + assert!(*addr != 0); + } + println!("Should cause error, Test 04_2 fail!"); + 0 +} diff --git a/user/src/bin/test_mmap3.rs b/user/src/bin/test_mmap3.rs new file mode 100644 index 00000000..d9d04b61 --- /dev/null +++ b/user/src/bin/test_mmap3.rs @@ -0,0 +1,25 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +use user_lib::mmap; + +/* +理想结果:对于错误的 mmap 返回 -1,最终输出 Test 04_4 test OK! +*/ + +#[no_mangle] +fn main() -> i32 { + let start: usize = 0x10000000; + let len: usize = 4096; + let prot: usize = 3; + assert_eq!(0, mmap(start, len, prot)); + assert_eq!(mmap(start - len, len + 1, prot), -1); + assert_eq!(mmap(start + len + 1, len, prot), -1); + assert_eq!(mmap(start + len, len, 0), -1); + assert_eq!(mmap(start + len, len, prot | 8), -1); + println!("Test 04_4 test OK!"); + 0 +} diff --git a/user/src/bin/test_sleep.rs b/user/src/bin/test_sleep.rs new file mode 100644 index 00000000..1312f6c3 --- /dev/null +++ b/user/src/bin/test_sleep.rs @@ -0,0 +1,24 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +use user_lib::{get_time, yield_}; + +/// 正确输出:(无报错信息) +/// get_time OK! {...} +/// Test sleep OK! + +#[no_mangle] +fn main() -> i32 { + let current_time = get_time(); + assert!(current_time > 0); + println!("get_time OK! {}", current_time); + let wait_for = current_time + 3000; + while get_time() < wait_for { + yield_(); + } + println!("Test sleep OK!"); + 0 +} diff --git a/user/src/bin/test_sleep1.rs b/user/src/bin/test_sleep1.rs new file mode 100644 index 00000000..da0cae32 --- /dev/null +++ b/user/src/bin/test_sleep1.rs @@ -0,0 +1,22 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +use user_lib::{get_time, sleep}; + +#[no_mangle] +pub fn main() -> i32 { + let start = get_time(); + println!("current time_msec = {}", start); + sleep(100); + let end = get_time(); + println!( + "time_msec = {} after sleeping 100 ticks, delta = {}ms!", + end, + end - start + ); + println!("Test sleep1 passed!"); + 0 +} diff --git a/user/src/bin/test_spawn0.rs b/user/src/bin/test_spawn0.rs new file mode 100644 index 00000000..2d09fc0d --- /dev/null +++ b/user/src/bin/test_spawn0.rs @@ -0,0 +1,29 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +use user_lib::{spawn, wait}; +const MAX_CHILD: usize = 40; + +/* +理想结果:生成 MAX_CHILD 个 getpid 的子进程,全部结束后,输出 Test spawn0 OK! +*/ + +#[no_mangle] +pub fn main() -> i32 { + for _ in 0..MAX_CHILD { + let cpid = spawn("test_getpid\0"); + assert!(cpid >= 0, "child pid invalid"); + println!("new child {}", cpid); + } + let mut exit_code: i32 = 0; + for _ in 0..MAX_CHILD { + assert!(wait(&mut exit_code) > 0, "wait stopped early"); + assert_eq!(exit_code, 0, "error exit ocde {}", exit_code); + } + assert!(wait(&mut exit_code) <= 0, "wait got too many"); + println!("Test spawn0 OK!"); + 0 +} diff --git a/user/src/bin/test_spawn1.rs b/user/src/bin/test_spawn1.rs new file mode 100644 index 00000000..99352cba --- /dev/null +++ b/user/src/bin/test_spawn1.rs @@ -0,0 +1,35 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +use user_lib::{spawn, wait, waitpid}; + +/// 程序行为:先后产生 3 个有特定返回值的程序,检查 waitpid 能够获取正确返回值。 + +/// 理想输出: +/// new child i +/// Test wait OK! +/// Test waitpid OK! + +#[no_mangle] +pub fn main() -> i32 { + let cpid = spawn("test_exit0\0"); + assert!(cpid >= 0, "child pid invalid"); + println!("new child {}", cpid); + let mut exit_code: i32 = 0; + let exit_pid = wait(&mut exit_code); + assert_eq!(exit_pid, cpid, "error exit pid"); + assert_eq!(exit_code, 66778, "error exit code"); + println!("Test wait OK!"); + let (cpid0, cpid1) = (spawn("test_exit0\0"), spawn("test_exit1\0")); + let exit_pid = waitpid(cpid1 as usize, &mut exit_code); + assert_eq!(exit_pid, cpid1, "error exit pid"); + assert_eq!(exit_code, -233, "error exit code"); + let exit_pid = wait(&mut exit_code); + assert_eq!(exit_pid, cpid0, "error exit pid"); + assert_eq!(exit_code, 66778, "error exit code"); + println!("Test waitpid OK!"); + 0 +} diff --git a/user/src/bin/test_unmap.rs b/user/src/bin/test_unmap.rs new file mode 100644 index 00000000..b64f862f --- /dev/null +++ b/user/src/bin/test_unmap.rs @@ -0,0 +1,36 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +use user_lib::{mmap, munmap}; + +/* +理想结果:输出 Test 04_5 ummap OK! +*/ + +#[no_mangle] +fn main() -> i32 { + let start: usize = 0x10000000; + let len: usize = 4096; + let prot: usize = 3; + assert_eq!(0, mmap(start, len, prot)); + assert_eq!(mmap(start + len, len * 2, prot), 0); + assert_eq!(munmap(start, len), 0); + assert_eq!(mmap(start - len, len + 1, prot), 0); + for i in (start - len)..(start + len * 3) { + let addr: *mut u8 = i as *mut u8; + unsafe { + *addr = i as u8; + } + } + for i in (start - len)..(start + len * 3) { + let addr: *mut u8 = i as *mut u8; + unsafe { + assert_eq!(*addr, i as u8); + } + } + println!("Test 04_5 ummap OK!"); + 0 +} diff --git a/user/src/bin/test_unmap2.rs b/user/src/bin/test_unmap2.rs new file mode 100644 index 00000000..85ddb750 --- /dev/null +++ b/user/src/bin/test_unmap2.rs @@ -0,0 +1,23 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +use user_lib::{mmap, munmap}; + +/* +理想结果:输出 Test 04_6 ummap2 OK! +*/ + +#[no_mangle] +fn main() -> i32 { + let start: usize = 0x10000000; + let len: usize = 4096; + let prot: usize = 3; + assert_eq!(0, mmap(start, len, prot)); + assert_eq!(munmap(start, len + 1), -1); + assert_eq!(munmap(start + 1, len - 1), -1); + println!("Test 04_6 ummap2 OK!"); + 0 +} diff --git a/user/src/bin/test_usertest.rs b/user/src/bin/test_usertest.rs new file mode 100644 index 00000000..91fb3655 --- /dev/null +++ b/user/src/bin/test_usertest.rs @@ -0,0 +1,51 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +static TESTS: &[&str] = &[ + "test_sleep\0", + "test_sleep1\0", + "test_mmap0\0", + "test_mmap1\0", + "test_mmap2\0", + "test_mmap3\0", + "test_unmap\0", + "test_unmap2\0", + "test_spawn0\0", + "test_spawn1\0", + "test_mail0\0", + "test_mail1\0", + "test_mail2\0", + "test_mail3\0", + "test_file0\0", + "test_file1\0", + "test_file2\0", +]; + +use user_lib::{exec, fork, waitpid}; + +/// 辅助测例,运行所有其他测例。 + +#[no_mangle] +pub fn main() -> i32 { + for test in TESTS { + println!("Usertests: Running {}", test); + let pid = fork(); + if pid == 0 { + exec(*test, &[0 as *const u8]); + panic!("unreachable!"); + } else { + let mut exit_code: i32 = Default::default(); + let wait_pid = waitpid(pid as usize, &mut exit_code); + assert_eq!(pid, wait_pid); + println!( + "\x1b[32mUsertests: Test {} in Process {} exited with code {}\x1b[0m", + test, pid, exit_code + ); + } + } + println!("ch7 Usertests passed!"); + 0 +} diff --git a/user/src/bin/test_write1.rs b/user/src/bin/test_write1.rs new file mode 100644 index 00000000..6d1c8358 --- /dev/null +++ b/user/src/bin/test_write1.rs @@ -0,0 +1,31 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; +use user_lib::{write, STDOUT}; +const DATA_STRING: &'static str = "string from data section\n"; + +/// 正确输出: +/// string from data section +/// strinstring from stack section +/// strin +/// Test write1 OK! + +#[no_mangle] +pub fn main() -> i32 { + assert_eq!(write(1234, DATA_STRING.as_bytes()), -1); + assert_eq!( + write(STDOUT, DATA_STRING.as_bytes()), + DATA_STRING.len() as isize + ); + assert_eq!(write(STDOUT, &DATA_STRING.as_bytes()[..5]), 5); + let stack_string = "string from stack section\n"; + assert_eq!( + write(STDOUT, stack_string.as_bytes()), + stack_string.len() as isize + ); + assert_eq!(write(STDOUT, &stack_string.as_bytes()[..5]), 5); + println!("\nTest write1 OK!"); + 0 +} diff --git a/user/src/bin/user_shell.rs b/user/src/bin/user_shell.rs index b2c33f2d..23dbb1e1 100644 --- a/user/src/bin/user_shell.rs +++ b/user/src/bin/user_shell.rs @@ -13,22 +13,15 @@ const BS: u8 = 0x08u8; use alloc::string::String; use alloc::vec::Vec; -use user_lib::{ - fork, - exec, - waitpid, - open, - OpenFlags, - close, - dup, -}; use user_lib::console::getchar; +use user_lib::{close, dup, exec, flush, fork, open, waitpid, OpenFlags}; #[no_mangle] pub fn main() -> i32 { println!("Rust user shell"); let mut line: String = String::new(); print!(">> "); + flush(); loop { let c = getchar(); match c { @@ -37,26 +30,25 @@ pub fn main() -> i32 { if !line.is_empty() { let args: Vec<_> = line.as_str().split(' ').collect(); let mut args_copy: Vec = args - .iter() - .map(|&arg| { - let mut string = String::new(); - string.push_str(arg); - string - }) - .collect(); + .iter() + .map(|&arg| { + let mut string = String::new(); + string.push_str(arg); + string + }) + .collect(); - args_copy - .iter_mut() - .for_each(|string| { + args_copy.iter_mut().for_each(|string| { string.push('\0'); }); // redirect input let mut input = String::new(); if let Some((idx, _)) = args_copy - .iter() - .enumerate() - .find(|(_, arg)| arg.as_str() == "<\0") { + .iter() + .enumerate() + .find(|(_, arg)| arg.as_str() == "<\0") + { input = args_copy[idx + 1].clone(); args_copy.drain(idx..=idx + 1); } @@ -64,17 +56,16 @@ pub fn main() -> i32 { // redirect output let mut output = String::new(); if let Some((idx, _)) = args_copy - .iter() - .enumerate() - .find(|(_, arg)| arg.as_str() == ">\0") { + .iter() + .enumerate() + .find(|(_, arg)| arg.as_str() == ">\0") + { output = args_copy[idx + 1].clone(); args_copy.drain(idx..=idx + 1); } - let mut args_addr: Vec<*const u8> = args_copy - .iter() - .map(|arg| arg.as_ptr()) - .collect(); + let mut args_addr: Vec<*const u8> = + args_copy.iter().map(|arg| arg.as_ptr()).collect(); args_addr.push(0 as *const u8); let pid = fork(); if pid == 0 { @@ -92,10 +83,8 @@ pub fn main() -> i32 { } // output redirection if !output.is_empty() { - let output_fd = open( - output.as_str(), - OpenFlags::CREATE | OpenFlags::WRONLY - ); + let output_fd = + open(output.as_str(), OpenFlags::CREATE | OpenFlags::WRONLY); if output_fd == -1 { println!("Error when opening file {}", output); return -4; @@ -120,19 +109,22 @@ pub fn main() -> i32 { line.clear(); } print!(">> "); + flush(); } BS | DL => { if !line.is_empty() { print!("{}", BS as char); print!(" "); print!("{}", BS as char); + flush(); line.pop(); } } _ => { print!("{}", c as char); + flush(); line.push(c as char); } } } -} \ No newline at end of file +} diff --git a/user/src/bin/usertests.rs b/user/src/bin/usertests.rs index e8be6c45..7ae471f0 100644 --- a/user/src/bin/usertests.rs +++ b/user/src/bin/usertests.rs @@ -8,14 +8,20 @@ static TESTS: &[&str] = &[ "exit\0", "fantastic_text\0", "forktest\0", - "forktest2\0", "forktest_simple\0", "hello_world\0", "matrix\0", - "sleep\0", - "sleep_simple\0", "stack_overflow\0", "yield\0", + "pipetest\0", + "filetest_simple\0", + // 正确实现 sys_get_time 后这些程序才能运行 + // "pipe_large_test\0", + // "forktest2\0", + // "sleep\0", + // "sleep_simple\0", + // "forktree\0", + // "huge_write\0", ]; use user_lib::{exec, fork, waitpid}; @@ -32,9 +38,12 @@ pub fn main() -> i32 { let mut exit_code: i32 = Default::default(); let wait_pid = waitpid(pid as usize, &mut exit_code); assert_eq!(pid, wait_pid); - println!("\x1b[32mUsertests: Test {} in Process {} exited with code {}\x1b[0m", test, pid, exit_code); + println!( + "\x1b[32mUsertests: Test {} in Process {} exited with code {}\x1b[0m", + test, pid, exit_code + ); } } println!("Usertests passed!"); 0 -} \ No newline at end of file +} diff --git a/user/src/console.rs b/user/src/console.rs index 810ebba1..d47c8264 100644 --- a/user/src/console.rs +++ b/user/src/console.rs @@ -1,21 +1,52 @@ +use alloc::collections::vec_deque::VecDeque; +use alloc::sync::Arc; use core::fmt::{self, Write}; +use spin::mutex::Mutex; -const STDIN: usize = 0; -const STDOUT: usize = 1; +pub const STDIN: usize = 0; +pub const STDOUT: usize = 1; + +const CONSOLE_BUFFER_SIZE: usize = 256 * 10; use super::{read, write}; +use lazy_static::*; + +struct ConsoleBuffer(VecDeque); + +lazy_static! { + static ref CONSOLE_BUFFER: Arc> = { + let buffer = VecDeque::::with_capacity(CONSOLE_BUFFER_SIZE); + Arc::new(Mutex::new(ConsoleBuffer(buffer))) + }; +} -struct Stdout; +impl ConsoleBuffer { + fn flush(&mut self) -> isize { + let s: &[u8] = self.0.make_contiguous(); + let ret = write(STDOUT, s); + self.0.clear(); + ret + } +} -impl Write for Stdout { +impl Write for ConsoleBuffer { fn write_str(&mut self, s: &str) -> fmt::Result { - write(STDOUT, s.as_bytes()); + for c in s.as_bytes().iter() { + self.0.push_back(*c); + if (*c == b'\n' || self.0.len() == CONSOLE_BUFFER_SIZE) && -1 == self.flush() { + return Err(fmt::Error); + } + } Ok(()) } } +#[allow(unused)] pub fn print(args: fmt::Arguments) { - Stdout.write_fmt(args).unwrap(); + let mut buf = CONSOLE_BUFFER.lock(); + // buf.write_fmt(args).unwrap(); + // BUG FIX: 关闭 stdout 后,本函数不能触发 panic,否则会造成死锁 + buf.write_fmt(args); } #[macro_export] @@ -27,6 +58,9 @@ macro_rules! print { #[macro_export] macro_rules! println { + () => { + $crate::console::print(format_args!("\n")); + }; ($fmt: literal $(, $($arg: tt)+)?) => { $crate::console::print(format_args!(concat!($fmt, "\n") $(, $($arg)+)?)); } @@ -37,3 +71,8 @@ pub fn getchar() -> u8 { read(STDIN, &mut c); c[0] } + +pub fn flush() { + let mut buf = CONSOLE_BUFFER.lock(); + buf.flush(); +} diff --git a/user/src/lang_items.rs b/user/src/lang_items.rs index b5b98e08..c65aa421 100644 --- a/user/src/lang_items.rs +++ b/user/src/lang_items.rs @@ -4,9 +4,14 @@ use super::exit; fn panic_handler(panic_info: &core::panic::PanicInfo) -> ! { let err = panic_info.message().unwrap(); if let Some(location) = panic_info.location() { - println!("Panicked at {}:{}, {}", location.file(), location.line(), err); + println!( + "Panicked at {}:{}, {}", + location.file(), + location.line(), + err + ); } else { println!("Panicked: {}", err); } exit(-1); -} \ No newline at end of file +} diff --git a/user/src/lib.rs b/user/src/lib.rs index d7f51cf2..e495447a 100644 --- a/user/src/lib.rs +++ b/user/src/lib.rs @@ -6,16 +6,18 @@ #[macro_use] pub mod console; -mod syscall; mod lang_items; +mod syscall; extern crate alloc; +extern crate core; #[macro_use] extern crate bitflags; -use syscall::*; use buddy_system_allocator::LockedHeap; use alloc::vec::Vec; +pub use console::{flush, STDIN, STDOUT}; +pub use syscall::*; const USER_HEAP_SIZE: usize = 32768; @@ -69,24 +71,139 @@ bitflags! { } } -pub fn dup(fd: usize) -> isize { sys_dup(fd) } -pub fn open(path: &str, flags: OpenFlags) -> isize { sys_open(path, flags.bits) } -pub fn close(fd: usize) -> isize { sys_close(fd) } -pub fn pipe(pipe_fd: &mut [usize]) -> isize { sys_pipe(pipe_fd) } -pub fn read(fd: usize, buf: &mut [u8]) -> isize { sys_read(fd, buf) } -pub fn write(fd: usize, buf: &[u8]) -> isize { sys_write(fd, buf) } -pub fn exit(exit_code: i32) -> ! { sys_exit(exit_code); } -pub fn yield_() -> isize { sys_yield() } -pub fn get_time() -> isize { sys_get_time() } -pub fn getpid() -> isize { sys_getpid() } -pub fn fork() -> isize { sys_fork() } -pub fn exec(path: &str, args: &[*const u8]) -> isize { sys_exec(path, args) } +#[repr(C)] +#[derive(Debug)] +pub struct TimeVal { + pub sec: usize, + pub usec: usize, +} + +impl TimeVal { + pub fn new() -> Self { + TimeVal { sec: 0, usec: 0 } + } +} + +#[repr(C)] +#[derive(Debug)] +pub struct Stat { + /// ID of device containing file + pub dev: u64, + /// inode number + pub ino: u64, + /// file type and mode + pub mode: StatMode, + /// number of hard links + pub nlink: u32, + /// unused pad + pad: [u64; 7], +} + +impl Stat { + pub fn new() -> Self { + Stat { + dev: 0, + ino: 0, + mode: StatMode::NULL, + nlink: 0, + pad: [0; 7], + } + } +} + +bitflags! { + pub struct StatMode: u32 { + const NULL = 0; + /// directory + const DIR = 0o040000; + /// ordinary regular file + const FILE = 0o100000; + } +} + +const AT_FDCWD: isize = -100; + +pub fn open(path: &str, flags: OpenFlags) -> isize { + sys_openat(AT_FDCWD as usize, path, flags.bits, OpenFlags::RDWR.bits) +} + +pub fn close(fd: usize) -> isize { + if fd == STDOUT { + console::flush(); + } + sys_close(fd) +} + +pub fn read(fd: usize, buf: &mut [u8]) -> isize { + sys_read(fd, buf) +} + +pub fn write(fd: usize, buf: &[u8]) -> isize { + sys_write(fd, buf) +} + +pub fn link(old_path: &str, new_path: &str) -> isize { + sys_linkat(AT_FDCWD as usize, old_path, AT_FDCWD as usize, new_path, 0) +} + +pub fn unlink(path: &str) -> isize { + sys_unlinkat(AT_FDCWD as usize, path, 0) +} + +pub fn fstat(fd: usize, st: &Stat) -> isize { + sys_fstat(fd, st) +} + +pub fn mail_read(buf: &mut [u8]) -> isize { + sys_mail_read(buf) +} + +pub fn mail_write(pid: usize, buf: &[u8]) -> isize { + sys_mail_write(pid, buf) +} + +pub fn exit(exit_code: i32) -> ! { + console::flush(); + sys_exit(exit_code); +} + +pub fn yield_() -> isize { + sys_yield() +} + +pub fn get_time() -> isize { + let time = TimeVal::new(); + match sys_get_time(&time, 0) { + 0 => ((time.sec & 0xffff) * 1000 + time.usec / 1000) as isize, + _ => -1, + } +} + +pub fn getpid() -> isize { + sys_getpid() +} + +pub fn fork() -> isize { + sys_fork() +} + +pub fn exec(path: &str, args: &[*const u8]) -> isize { + sys_exec(path, args) +} + +pub fn set_priority(prio: isize) -> isize { + sys_set_priority(prio) +} + pub fn wait(exit_code: &mut i32) -> isize { loop { match sys_waitpid(-1, exit_code as *mut _) { - -2 => { yield_(); } - // -1 or a real pid - exit_pid => return exit_pid, + -2 => { + sys_yield(); + } + n => { + return n; + } } } } @@ -94,15 +211,34 @@ pub fn wait(exit_code: &mut i32) -> isize { pub fn waitpid(pid: usize, exit_code: &mut i32) -> isize { loop { match sys_waitpid(pid as isize, exit_code as *mut _) { - -2 => { yield_(); } - // -1 or a real pid - exit_pid => return exit_pid, + -2 => { + sys_yield(); + } + n => { + return n; + } } } } + pub fn sleep(period_ms: usize) { - let start = sys_get_time(); - while sys_get_time() < start + period_ms as isize { + let start = get_time(); + while get_time() < start + period_ms as isize { sys_yield(); } -} \ No newline at end of file +} + +pub fn mmap(start: usize, len: usize, prot: usize) -> isize { + sys_mmap(start, len, prot) +} + +pub fn munmap(start: usize, len: usize) -> isize { + sys_munmap(start, len) +} + +pub fn spawn(path: &str) -> isize { + sys_spawn(path) +} + +pub fn dup(fd: usize) -> isize { sys_dup(fd) } +pub fn pipe(pipe_fd: &mut [usize]) -> isize { sys_pipe(pipe_fd) } diff --git a/user/src/syscall.rs b/user/src/syscall.rs index 4863bd3d..b2ae62e7 100644 --- a/user/src/syscall.rs +++ b/user/src/syscall.rs @@ -1,18 +1,29 @@ -const SYSCALL_DUP: usize = 24; -const SYSCALL_OPEN: usize = 56; -const SYSCALL_CLOSE: usize = 57; -const SYSCALL_PIPE: usize = 59; -const SYSCALL_READ: usize = 63; -const SYSCALL_WRITE: usize = 64; -const SYSCALL_EXIT: usize = 93; -const SYSCALL_YIELD: usize = 124; -const SYSCALL_GET_TIME: usize = 169; -const SYSCALL_GETPID: usize = 172; -const SYSCALL_FORK: usize = 220; -const SYSCALL_EXEC: usize = 221; -const SYSCALL_WAITPID: usize = 260; - -fn syscall(id: usize, args: [usize; 3]) -> isize { +use super::{Stat, TimeVal}; + +pub const SYSCALL_OPENAT: usize = 56; +pub const SYSCALL_CLOSE: usize = 57; +pub const SYSCALL_READ: usize = 63; +pub const SYSCALL_WRITE: usize = 64; +pub const SYSCALL_UNLINKAT: usize = 35; +pub const SYSCALL_LINKAT: usize = 37; +pub const SYSCALL_FSTAT: usize = 80; +pub const SYSCALL_EXIT: usize = 93; +pub const SYSCALL_YIELD: usize = 124; +pub const SYSCALL_GETTIMEOFDAY: usize = 169; +pub const SYSCALL_GETPID: usize = 172; +pub const SYSCALL_FORK: usize = 220; +pub const SYSCALL_EXEC: usize = 221; +pub const SYSCALL_WAITPID: usize = 260; +pub const SYSCALL_SET_PRIORITY: usize = 140; +pub const SYSCALL_MUNMAP: usize = 215; +pub const SYSCALL_MMAP: usize = 222; +pub const SYSCALL_SPAWN: usize = 400; +pub const SYSCALL_MAIL_READ: usize = 401; +pub const SYSCALL_MAIL_WRITE: usize = 402; +pub const SYSCALL_DUP: usize = 24; +pub const SYSCALL_PIPE: usize = 59; + +pub fn syscall(id: usize, args: [usize; 3]) -> isize { let mut ret: isize; unsafe { asm!( @@ -26,30 +37,93 @@ fn syscall(id: usize, args: [usize; 3]) -> isize { ret } -pub fn sys_dup(fd: usize) -> isize { - syscall(SYSCALL_DUP, [fd, 0, 0]) +pub fn syscall6(id: usize, args: [usize; 6]) -> isize { + let mut ret: isize; + unsafe { + asm!("ecall", + inlateout("x10") args[0] => ret, + in("x11") args[1], + in("x12") args[2], + in("x13") args[3], + in("x14") args[4], + in("x15") args[5], + in("x17") id + ); + } + ret } -pub fn sys_open(path: &str, flags: u32) -> isize { - syscall(SYSCALL_OPEN, [path.as_ptr() as usize, flags as usize, 0]) +pub fn sys_openat(dirfd: usize, path: &str, flags: u32, mode: u32) -> isize { + syscall6( + SYSCALL_OPENAT, + [ + dirfd, + path.as_ptr() as usize, + flags as usize, + mode as usize, + 0, + 0, + ], + ) } pub fn sys_close(fd: usize) -> isize { syscall(SYSCALL_CLOSE, [fd, 0, 0]) } -pub fn sys_pipe(pipe: &mut [usize]) -> isize { - syscall(SYSCALL_PIPE, [pipe.as_mut_ptr() as usize, 0, 0]) -} - pub fn sys_read(fd: usize, buffer: &mut [u8]) -> isize { - syscall(SYSCALL_READ, [fd, buffer.as_mut_ptr() as usize, buffer.len()]) + syscall( + SYSCALL_READ, + [fd, buffer.as_mut_ptr() as usize, buffer.len()], + ) } pub fn sys_write(fd: usize, buffer: &[u8]) -> isize { syscall(SYSCALL_WRITE, [fd, buffer.as_ptr() as usize, buffer.len()]) } +pub fn sys_linkat( + old_dirfd: usize, + old_path: &str, + new_dirfd: usize, + new_path: &str, + flags: usize, +) -> isize { + syscall6( + SYSCALL_LINKAT, + [ + old_dirfd, + old_path.as_ptr() as usize, + new_dirfd, + new_path.as_ptr() as usize, + flags, + 0, + ], + ) +} + +pub fn sys_unlinkat(dirfd: usize, path: &str, flags: usize) -> isize { + syscall(SYSCALL_UNLINKAT, [dirfd, path.as_ptr() as usize, flags]) +} + +pub fn sys_fstat(fd: usize, st: &Stat) -> isize { + syscall(SYSCALL_FSTAT, [fd, st as *const _ as usize, 0]) +} + +pub fn sys_mail_read(buffer: &mut [u8]) -> isize { + syscall( + SYSCALL_MAIL_READ, + [buffer.as_ptr() as usize, buffer.len(), 0], + ) +} + +pub fn sys_mail_write(pid: usize, buffer: &[u8]) -> isize { + syscall( + SYSCALL_MAIL_WRITE, + [pid, buffer.as_ptr() as usize, buffer.len()], + ) +} + pub fn sys_exit(exit_code: i32) -> ! { syscall(SYSCALL_EXIT, [exit_code as usize, 0, 0]); panic!("sys_exit never returns!"); @@ -59,8 +133,8 @@ pub fn sys_yield() -> isize { syscall(SYSCALL_YIELD, [0, 0, 0]) } -pub fn sys_get_time() -> isize { - syscall(SYSCALL_GET_TIME, [0, 0, 0]) +pub fn sys_get_time(time: &TimeVal, tz: usize) -> isize { + syscall(SYSCALL_GETTIMEOFDAY, [time as *const _ as usize, tz, 0]) } pub fn sys_getpid() -> isize { @@ -75,6 +149,30 @@ pub fn sys_exec(path: &str, args: &[*const u8]) -> isize { syscall(SYSCALL_EXEC, [path.as_ptr() as usize, args.as_ptr() as usize, 0]) } -pub fn sys_waitpid(pid: isize, exit_code: *mut i32) -> isize { - syscall(SYSCALL_WAITPID, [pid as usize, exit_code as usize, 0]) -} \ No newline at end of file +pub fn sys_waitpid(pid: isize, xstatus: *mut i32) -> isize { + syscall(SYSCALL_WAITPID, [pid as usize, xstatus as usize, 0]) +} + +pub fn sys_set_priority(prio: isize) -> isize { + syscall(SYSCALL_SET_PRIORITY, [prio as usize, 0, 0]) +} + +pub fn sys_mmap(start: usize, len: usize, prot: usize) -> isize { + syscall(SYSCALL_MMAP, [start, len, prot]) +} + +pub fn sys_munmap(start: usize, len: usize) -> isize { + syscall(SYSCALL_MUNMAP, [start, len, 0]) +} + +pub fn sys_spawn(path: &str) -> isize { + syscall(SYSCALL_SPAWN, [path.as_ptr() as usize, 0, 0]) +} + +pub fn sys_dup(fd: usize) -> isize { + syscall(SYSCALL_DUP, [fd, 0, 0]) +} + +pub fn sys_pipe(pipe: &mut [usize]) -> isize { + syscall(SYSCALL_PIPE, [pipe.as_mut_ptr() as usize, 0, 0]) +}