Compare commits

...

6 Commits

8
.gitignore vendored

@ -1,9 +1,10 @@
.idea/*
os/target/*
os/.idea/*
.idea
Cargo.lock
target
os/src/link_app.S
os/last-*
os/Cargo.lock
user/build
user/target/*
user/.idea/*
user/Cargo.lock
@ -12,3 +13,4 @@ easy-fs/target/*
easy-fs-fuse/Cargo.lock
easy-fs-fuse/target/*
tools/
pushall.sh

@ -1,16 +1,67 @@
# rCore-Tutorial-v3
rCore-Tutorial version 3.x
rCore-Tutorial version 3.5. See the [Documentation in Chinese](https://rcore-os.github.io/rCore-Tutorial-Book-v3/).
## Dependency
## news
- 2021.11.20: Now we are updating our labs. Please checkout chX-dev Branches for our current new labs. (Notice: please see the [Dependency] section in the end of this doc)
### Binaries
## Overview
* rustc 1.56.0-nightly (08095fc1f 2021-07-26)
This project aims to show how to write an **Unix-like OS** running on **RISC-V** platforms **from scratch** in **[Rust](https://www.rust-lang.org/)** for **beginners** without any background knowledge about **computer architectures, assembly languages or operating systems**.
* qemu: 5.0.0
## Features
* rustsbi-lib: 0.2.0-alpha.4
* Platform supported: `qemu-system-riscv64` simulator or dev boards based on [Kendryte K210 SoC](https://canaan.io/product/kendryteai) such as [Maix Dock](https://www.seeedstudio.com/Sipeed-MAIX-Dock-p-4815.html)
* OS
* concurrency of multiple processes
* preemptive scheduling(Round-Robin algorithm)
* dynamic memory management in kernel
* virtual memory
* a simple file system with a block cache
* an interactive shell in the userspace
* **only 4K+ LoC**
* [A detailed documentation in Chinese](https://rcore-os.github.io/rCore-Tutorial-Book-v3/) in spite of the lack of comments in the code(English version is not available at present)
rustsbi-qemu: d4968dd2
## Run our project
rustsbi-k210: b689314e
TODO:
## Working in progress
Now we are still updating our project, you can find latest changes on branches `chX-dev` such as `ch1-dev`. We are intended to publish first release 3.5.0 after completing most of the tasks mentioned below.
Overall progress: ch7
### Completed
* [x] automatically clean up and rebuild before running our project on a different platform
* [x] fix `power` series application in early chapters, now you can find modulus in the output
* [x] use `UPSafeCell` instead of `RefCell` or `spin::Mutex` in order to access static data structures and adjust its API so that it cannot be borrowed twice at a time(mention `& .exclusive_access().task[0]` in `run_first_task`)
* [x] move `TaskContext` into `TaskControlBlock` instead of restoring it in place on kernel stack(since ch3), eliminating annoying `task_cx_ptr2`
* [x] replace `llvm_asm!` with `asm!`
* [x] expand the fs image size generated by `rcore-fs-fuse` to 128MiB
* [x] add a new test named `huge_write` which evaluates the fs performance(qemu\~500KiB/s k210\~50KiB/s)
* [x] flush all block cache to disk after a fs transaction which involves write operation
* [x] replace `spin::Mutex` with `UPSafeCell` before SMP chapter
* [x] add codes for a new chapter about synchronization & mutual exclusion(uniprocessor only)
### Todo(High priority)
* [ ] support Allwinner's RISC-V D1 chip
* [ ] bug fix: we should call `find_pte` rather than `find_pte_create` in `PageTable::unmap`
* [ ] bug fix: check validity of level-3 pte in `find_pte` instead of checking it outside this function
* [ ] use old fs image optionally, do not always rebuild the image
* [ ] add new system calls: getdents64/fstat
* [ ] shell functionality improvement(to be continued...)
* [ ] give every non-zero process exit code an unique and clear error type
* [ ] effective error handling of mm module
### Todo(Low priority)
* [ ] rewrite practice doc and remove some inproper questions
* [ ] provide smooth debug experience at a Rust source code level
* [ ] format the code using official tools
### Crates
We will add them later.

@ -0,0 +1,18 @@
# rCore-Tutorial-v3
rCore-Tutorial version 3.x
## Dependency
### Binaries
* rustc: 1.57.0-nightly (e1e9319d9 2021-10-14)
* cargo-binutils: 0.3.3
* qemu: 5.0.0
* rustsbi-lib: 0.2.0-alpha.4
rustsbi-qemu: d4968dd2
rustsbi-k210: b689314e

@ -56,13 +56,13 @@ fn easy_fs_pack() -> std::io::Result<()> {
.write(true)
.create(true)
.open(format!("{}{}", target_path, "fs.img"))?;
f.set_len(128 * 2048 * 512).unwrap();
f.set_len(16 * 2048 * 512).unwrap();
f
})));
// 128MiB, at most 4095 files
// 16MiB, at most 4095 files
let efs = EasyFileSystem::create(
block_file.clone(),
128 * 2048,
16 * 2048,
1,
);
let root_inode = Arc::new(EasyFileSystem::root_inode(&efs));

@ -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)
@ -43,22 +45,22 @@ endif
env:
(rustup target list | grep "riscv64gc-unknown-none-elf (installed)") || rustup target add $(TARGET)
cargo install cargo-binutils --vers ~0.2
cargo install cargo-binutils --vers =0.3.3
rustup component add rust-src
rustup component add llvm-tools-preview
sdcard: fs-img
@echo "Are you sure write to $(SDCARD) ? [y/N] " && read ans && [ $${ans:-N} = y ]
@sudo dd if=/dev/zero of=$(SDCARD) bs=1048576 count=256
@sudo dd if=/dev/zero of=$(SDCARD) bs=1048576 count=32
@sudo dd if=$(FS_IMG) of=$(SDCARD)
$(KERNEL_BIN): kernel
@$(OBJCOPY) $(KERNEL_ELF) --strip-all -O binary $@
fs-img: $(APPS)
@cd ../user && make build
@rm $(FS_IMG)
@cd ../easy-fs-fuse && cargo run --release -- -s ../user/src/bin/ -t ../user/target/riscv64gc-unknown-none-elf/release/
@cd ../user && make build TEST=$(TEST)
@rm $(FS_IMG) -f
@cd ../easy-fs-fuse && cargo run --release -- -s ../user/build/app/ -t ../user/target/riscv64gc-unknown-none-elf/release/
$(APPS):

@ -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;

@ -65,7 +65,7 @@ pub fn list_apps() {
for app in ROOT_INODE.ls() {
println!("{}", app);
}
println!("**************/")
println!("**************/");
}
bitflags! {
@ -156,4 +156,4 @@ impl File for OSInode {
}
total_write_size
}
}
}

@ -2,6 +2,11 @@ use crate::config::{PAGE_SIZE, PAGE_SIZE_BITS};
use super::PageTableEntry;
use core::fmt::{self, Debug, Formatter};
const PA_WIDTH_SV39: usize = 56;
const VA_WIDTH_SV39: usize = 39;
const PPN_WIDTH_SV39: usize = PA_WIDTH_SV39 - PAGE_SIZE_BITS;
const VPN_WIDTH_SV39: usize = VA_WIDTH_SV39 - PAGE_SIZE_BITS;
/// Definitions
#[repr(C)]
#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
@ -47,16 +52,16 @@ impl Debug for PhysPageNum {
/// usize -> T: usize.into()
impl From<usize> for PhysAddr {
fn from(v: usize) -> Self { Self(v) }
fn from(v: usize) -> Self { Self(v & ( (1 << PA_WIDTH_SV39) - 1 )) }
}
impl From<usize> for PhysPageNum {
fn from(v: usize) -> Self { Self(v) }
fn from(v: usize) -> Self { Self(v & ( (1 << PPN_WIDTH_SV39) - 1 )) }
}
impl From<usize> for VirtAddr {
fn from(v: usize) -> Self { Self(v) }
fn from(v: usize) -> Self { Self(v & ( (1 << VA_WIDTH_SV39) - 1 )) }
}
impl From<usize> for VirtPageNum {
fn from(v: usize) -> Self { Self(v) }
fn from(v: usize) -> Self { Self(v & ( (1 << VPN_WIDTH_SV39) - 1 )) }
}
impl From<PhysAddr> for usize {
fn from(v: PhysAddr) -> Self { v.0 }
@ -206,4 +211,4 @@ impl<T> Iterator for SimpleRangeIterator<T> where
}
}
}
pub type VPNRange = SimpleRange<VirtPageNum>;
pub type VPNRange = SimpleRange<VirtPageNum>;

@ -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),

@ -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 {

@ -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() {

@ -1 +1 @@
nightly-2021-08-25
nightly-2021-10-15

@ -8,4 +8,6 @@ edition = "2018"
[dependencies]
buddy_system_allocator = "0.6"
bitflags = "1.2.1"
bitflags = "1.2.1"
spin = "0.9"
lazy_static = { version = "1.4.0", features = ["spin_no_std"] }

@ -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

@ -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
}

@ -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
}

@ -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
}

@ -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
}

@ -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
}

@ -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
}

@ -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
}

@ -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
}

@ -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
}

@ -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
}

@ -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
}

@ -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
}

@ -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
}

@ -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
}

@ -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
}

@ -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
}

@ -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
}

@ -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
}

@ -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
}

@ -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
}

@ -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
}

@ -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
}

@ -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<String> = 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);
}
}
}
}
}

@ -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
}
}

@ -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<u8>);
lazy_static! {
static ref CONSOLE_BUFFER: Arc<Mutex<ConsoleBuffer>> = {
let buffer = VecDeque::<u8>::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();
}

@ -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);
}
}

@ -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();
}
}
}
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) }

@ -2,7 +2,7 @@
OUTPUT_ARCH(riscv)
ENTRY(_start)
BASE_ADDRESS = 0x0;
BASE_ADDRESS = 0x10000;
SECTIONS
{
@ -29,4 +29,4 @@ SECTIONS
*(.eh_frame)
*(.debug*)
}
}
}

@ -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])
}
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])
}

Loading…
Cancel
Save