Compare commits
No commits in common. "a91f29c7a37e5762333e2dc739f7f472cce4f93f" and "92d9170fcada9109291c6c31f5f56852b16648fb" have entirely different histories.
a91f29c7a3
...
92d9170fca
34 changed files with 89 additions and 1074 deletions
14
.gitignore
vendored
14
.gitignore
vendored
|
@ -1,16 +1,10 @@
|
|||
.idea
|
||||
Cargo.lock
|
||||
target
|
||||
.idea/*
|
||||
os/target/*
|
||||
os/.idea/*
|
||||
os/Cargo.lock
|
||||
os/src/link_app.S
|
||||
os/last-*
|
||||
os/Cargo.lock
|
||||
user/build
|
||||
user/target/*
|
||||
user/.idea/*
|
||||
user/Cargo.lock
|
||||
easy-fs/Cargo.lock
|
||||
easy-fs/target/*
|
||||
easy-fs-fuse/Cargo.lock
|
||||
easy-fs-fuse/target/*
|
||||
tools/
|
||||
pushall.sh
|
67
README.md
67
README.md
|
@ -1,67 +1,12 @@
|
|||
# rCore-Tutorial-v3
|
||||
rCore-Tutorial version 3.5. See the [Documentation in Chinese](https://rcore-os.github.io/rCore-Tutorial-Book-v3/).
|
||||
rCore-Tutorial version 3.x
|
||||
|
||||
## 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)
|
||||
## Dependency
|
||||
|
||||
## Overview
|
||||
### Binaries
|
||||
|
||||
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**.
|
||||
* rustc 1.56.0-nightly (b03ccace5 2021-08-24)
|
||||
|
||||
## Features
|
||||
* qemu: 5.0.0
|
||||
|
||||
* 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)
|
||||
|
||||
## Run our project
|
||||
|
||||
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.
|
||||
* rustsbi: qemu[7d71bfb7] k210[563144b0]
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
# 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
|
|
@ -29,8 +29,6 @@ OBJCOPY := rust-objcopy --binary-architecture=riscv64
|
|||
# Disassembly
|
||||
DISASM ?= -x
|
||||
|
||||
TEST ?= 0
|
||||
|
||||
build: env switch-check $(KERNEL_BIN)
|
||||
|
||||
switch-check:
|
||||
|
@ -50,7 +48,7 @@ $(KERNEL_BIN): kernel
|
|||
@$(OBJCOPY) $(KERNEL_ELF) --strip-all -O binary $@
|
||||
|
||||
kernel:
|
||||
@cd ../user && make build TEST=$(TEST)
|
||||
@cd ../user && make build
|
||||
@echo Platform: $(BOARD)
|
||||
@cp src/linker-$(BOARD).ld src/linker.ld
|
||||
@cargo build --release --features "board_$(BOARD)"
|
||||
|
|
22
os/build.rs
22
os/build.rs
|
@ -1,5 +1,5 @@
|
|||
use std::fs::{read_dir, File};
|
||||
use std::io::{Result, Write};
|
||||
use std::fs::{File, read_dir};
|
||||
|
||||
fn main() {
|
||||
println!("cargo:rerun-if-changed=../user/src/");
|
||||
|
@ -7,11 +7,11 @@ fn main() {
|
|||
insert_app_data().unwrap();
|
||||
}
|
||||
|
||||
static TARGET_PATH: &str = "../user/build/bin/";
|
||||
static TARGET_PATH: &str = "../user/target/riscv64gc-unknown-none-elf/release/";
|
||||
|
||||
fn insert_app_data() -> Result<()> {
|
||||
let mut f = File::create("src/link_app.S").unwrap();
|
||||
let mut apps: Vec<_> = read_dir("../user/build/bin/")
|
||||
let mut apps: Vec<_> = read_dir("../user/src/bin")
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.map(|dir_entry| {
|
||||
|
@ -22,16 +22,12 @@ fn insert_app_data() -> Result<()> {
|
|||
.collect();
|
||||
apps.sort();
|
||||
|
||||
writeln!(
|
||||
f,
|
||||
r#"
|
||||
writeln!(f, r#"
|
||||
.align 3
|
||||
.section .data
|
||||
.global _num_app
|
||||
_num_app:
|
||||
.quad {}"#,
|
||||
apps.len()
|
||||
)?;
|
||||
.quad {}"#, apps.len())?;
|
||||
|
||||
for i in 0..apps.len() {
|
||||
writeln!(f, r#" .quad app_{}_start"#, i)?;
|
||||
|
@ -40,17 +36,13 @@ _num_app:
|
|||
|
||||
for (idx, app) in apps.iter().enumerate() {
|
||||
println!("app_{}: {}", idx, app);
|
||||
writeln!(
|
||||
f,
|
||||
r#"
|
||||
writeln!(f, r#"
|
||||
.section .data
|
||||
.global app_{0}_start
|
||||
.global app_{0}_end
|
||||
app_{0}_start:
|
||||
.incbin "{2}{1}.bin"
|
||||
app_{0}_end:"#,
|
||||
idx, app, TARGET_PATH
|
||||
)?;
|
||||
app_{0}_end:"#, idx, app, TARGET_PATH)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
pub const USER_STACK_SIZE: usize = 4096 * 2;
|
||||
pub const KERNEL_STACK_SIZE: usize = 4096 * 2;
|
||||
pub const MAX_APP_NUM: usize = 8;
|
||||
pub const MAX_APP_NUM: usize = 4;
|
||||
pub const APP_BASE_ADDRESS: usize = 0x80400000;
|
||||
pub const APP_SIZE_LIMIT: usize = 0x20000;
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize {
|
|||
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(args[0] as *mut TimeVal, args[1]),
|
||||
SYSCALL_GET_TIME => sys_get_time(),
|
||||
_ => panic!("Unsupported syscall_id: {}", syscall_id),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,14 +2,7 @@ use crate::task::{
|
|||
suspend_current_and_run_next,
|
||||
exit_current_and_run_next,
|
||||
};
|
||||
use crate::timer::get_time_us;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct TimeVal {
|
||||
pub sec: usize,
|
||||
pub usec: usize,
|
||||
}
|
||||
use crate::timer::get_time_ms;
|
||||
|
||||
pub fn sys_exit(exit_code: i32) -> ! {
|
||||
println!("[kernel] Application exited with code {}", exit_code);
|
||||
|
@ -22,17 +15,6 @@ 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_get_time() -> isize {
|
||||
get_time_ms() as isize
|
||||
}
|
|
@ -1,16 +1,16 @@
|
|||
use crate::config::CLOCK_FREQ;
|
||||
use crate::sbi::set_timer;
|
||||
use riscv::register::time;
|
||||
use crate::sbi::set_timer;
|
||||
use crate::config::CLOCK_FREQ;
|
||||
|
||||
const TICKS_PER_SEC: usize = 100;
|
||||
const MICRO_PER_SEC: usize = 1_000_000;
|
||||
const MSEC_PER_SEC: usize = 1000;
|
||||
|
||||
pub fn get_time() -> usize {
|
||||
time::read()
|
||||
}
|
||||
|
||||
pub fn get_time_us() -> usize {
|
||||
time::read() / (CLOCK_FREQ / MICRO_PER_SEC)
|
||||
pub fn get_time_ms() -> usize {
|
||||
time::read() / (CLOCK_FREQ / MSEC_PER_SEC)
|
||||
}
|
||||
|
||||
pub fn set_next_trigger() {
|
||||
|
|
|
@ -7,7 +7,3 @@ edition = "2018"
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
buddy_system_allocator = "0.6"
|
||||
bitflags = "1.2.1"
|
||||
spin = "0.9"
|
||||
lazy_static = { version = "1.4.0", features = ["spin_no_std"] }
|
||||
|
|
|
@ -2,39 +2,22 @@ TARGET := riscv64gc-unknown-none-elf
|
|||
MODE := release
|
||||
APP_DIR := src/bin
|
||||
TARGET_DIR := target/$(TARGET)/$(MODE)
|
||||
BUILD_DIR := build
|
||||
APPS := $(wildcard $(APP_DIR)/*.rs)
|
||||
ELFS := $(patsubst $(APP_DIR)/%.rs, $(TARGET_DIR)/%, $(APPS))
|
||||
BINS := $(patsubst $(APP_DIR)/%.rs, $(TARGET_DIR)/%.bin, $(APPS))
|
||||
|
||||
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$(TEST)*.rs)
|
||||
endif
|
||||
ELFS := $(patsubst $(APP_DIR)/%.rs, $(TARGET_DIR)/%, $(APPS))
|
||||
|
||||
elf: $(APPS)
|
||||
@python3 build.py
|
||||
|
||||
binary: 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));)
|
||||
$(foreach elf, $(ELFS), $(OBJCOPY) $(elf) --strip-all -O binary $(patsubst $(TARGET_DIR)/%, $(TARGET_DIR)/%.bin, $(elf));)
|
||||
|
||||
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/;)
|
||||
build: binary
|
||||
|
||||
clean:
|
||||
@cargo clean
|
||||
@rm -rf $(BUILD_DIR)
|
||||
|
||||
.PHONY: elf binary build clean
|
|
@ -5,7 +5,7 @@ step = 0x20000
|
|||
linker = 'src/linker.ld'
|
||||
|
||||
app_id = 0
|
||||
apps = os.listdir('build/app')
|
||||
apps = os.listdir('src/bin')
|
||||
apps.sort()
|
||||
for app in apps:
|
||||
app = app[:app.find('.')]
|
||||
|
|
18
user/src/bin/03sleep.rs
Normal file
18
user/src/bin/03sleep.rs
Normal file
|
@ -0,0 +1,18 @@
|
|||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
#[macro_use]
|
||||
extern crate user_lib;
|
||||
|
||||
use user_lib::{get_time, yield_};
|
||||
|
||||
#[no_mangle]
|
||||
fn main() -> i32 {
|
||||
let current_timer = get_time();
|
||||
let wait_for = current_timer + 3000;
|
||||
while get_time() < wait_for {
|
||||
yield_();
|
||||
}
|
||||
println!("Test sleep OK!");
|
||||
0
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
#![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
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
#![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
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
#![no_std]
|
||||
#![no_main]
|
||||
#![feature(asm)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate user_lib;
|
||||
extern crate core;
|
||||
use core::slice;
|
||||
use user_lib::{write, STDOUT};
|
||||
|
||||
/// 正确输出:
|
||||
/// Test write0 OK!
|
||||
|
||||
const STACK_SIZE: usize = 0x1000;
|
||||
|
||||
unsafe fn r_sp() -> usize {
|
||||
let mut sp: usize;
|
||||
asm!("mv {}, sp", out(reg) sp);
|
||||
sp
|
||||
}
|
||||
|
||||
unsafe fn stack_range() -> (usize, usize) {
|
||||
let sp = r_sp();
|
||||
let top = (sp + STACK_SIZE - 1) & (!(STACK_SIZE - 1));
|
||||
(top - STACK_SIZE, top)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn main() -> i32 {
|
||||
assert_eq!(
|
||||
write(STDOUT, unsafe {
|
||||
#[allow(clippy::zero_ptr)]
|
||||
slice::from_raw_parts(0x0 as *const _, 10)
|
||||
}),
|
||||
-1
|
||||
);
|
||||
let (bottom, top) = unsafe { stack_range() };
|
||||
assert_eq!(
|
||||
write(STDOUT, unsafe {
|
||||
slice::from_raw_parts((top - 5) as *const _, 10)
|
||||
}),
|
||||
-1
|
||||
);
|
||||
assert_eq!(
|
||||
write(STDOUT, unsafe {
|
||||
slice::from_raw_parts((bottom - 5) as *const _, 10)
|
||||
}),
|
||||
-1
|
||||
);
|
||||
// TODO: test string located in .data section
|
||||
println!("Test write0 OK!");
|
||||
0
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
#[macro_use]
|
||||
extern crate user_lib;
|
||||
use user_lib::{write, STDOUT};
|
||||
const DATA_STRING: &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
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
#[macro_use]
|
||||
extern crate user_lib;
|
||||
use user_lib::set_priority;
|
||||
|
||||
/// 正确输出:(无报错信息)
|
||||
/// Test set_priority OK!
|
||||
|
||||
#[no_mangle]
|
||||
pub fn main() -> i32 {
|
||||
assert_eq!(set_priority(10), 10);
|
||||
assert_eq!(set_priority(isize::MAX), isize::MAX);
|
||||
assert_eq!(set_priority(0), -1);
|
||||
assert_eq!(set_priority(1), -1);
|
||||
assert_eq!(set_priority(-10), -1);
|
||||
println!("Test set_priority OK!");
|
||||
0
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
#[macro_use]
|
||||
extern crate user_lib;
|
||||
use user_lib::{get_time, set_priority};
|
||||
|
||||
/*
|
||||
理想结果:6个进程退出时,输出 count 基本正比于 priority
|
||||
*/
|
||||
|
||||
fn spin_delay() {
|
||||
let mut j = true;
|
||||
for _ in 0..10 {
|
||||
j = !j;
|
||||
}
|
||||
}
|
||||
|
||||
// to get enough accuracy, MAX_TIME (the running time of each process) should > 1000 mseconds.
|
||||
const MAX_TIME: isize = 1000;
|
||||
pub fn count_during(prio: isize) -> isize {
|
||||
let start_time = get_time();
|
||||
let mut acc = 0;
|
||||
set_priority(prio);
|
||||
loop {
|
||||
spin_delay();
|
||||
acc += 1;
|
||||
if acc % 400 == 0 {
|
||||
let time = get_time() - start_time;
|
||||
if time > MAX_TIME {
|
||||
return acc;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn main() -> usize {
|
||||
let prio = 5;
|
||||
let count = count_during(prio);
|
||||
println!("priority = {}, exitcode = {}", prio, count);
|
||||
0
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
#[macro_use]
|
||||
extern crate user_lib;
|
||||
use user_lib::{get_time, set_priority};
|
||||
|
||||
fn spin_delay() {
|
||||
let mut j = true;
|
||||
for _ in 0..10 {
|
||||
j = !j;
|
||||
}
|
||||
}
|
||||
|
||||
// to get enough accuracy, MAX_TIME (the running time of each process) should > 1000 mseconds.
|
||||
const MAX_TIME: isize = 1000;
|
||||
fn count_during(prio: isize) -> isize {
|
||||
let start_time = get_time();
|
||||
let mut acc = 0;
|
||||
set_priority(prio);
|
||||
loop {
|
||||
spin_delay();
|
||||
acc += 1;
|
||||
if acc % 400 == 0 {
|
||||
let time = get_time() - start_time;
|
||||
if time > MAX_TIME {
|
||||
return acc;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn main() -> usize {
|
||||
let prio = 6;
|
||||
let count = count_during(prio);
|
||||
println!("priority = {}, exitcode = {}", prio, count);
|
||||
0
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
#[macro_use]
|
||||
extern crate user_lib;
|
||||
use user_lib::{get_time, set_priority};
|
||||
|
||||
fn spin_delay() {
|
||||
let mut j = true;
|
||||
for _ in 0..10 {
|
||||
j = !j;
|
||||
}
|
||||
}
|
||||
|
||||
// to get enough accuracy, MAX_TIME (the running time of each process) should > 1000 mseconds.
|
||||
const MAX_TIME: isize = 1000;
|
||||
fn count_during(prio: isize) -> isize {
|
||||
let start_time = get_time();
|
||||
let mut acc = 0;
|
||||
set_priority(prio);
|
||||
loop {
|
||||
spin_delay();
|
||||
acc += 1;
|
||||
if acc % 400 == 0 {
|
||||
let time = get_time() - start_time;
|
||||
if time > MAX_TIME {
|
||||
return acc;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn main() -> usize {
|
||||
let prio = 7;
|
||||
let count = count_during(prio);
|
||||
println!("priority = {}, exitcode = {}", prio, count);
|
||||
0
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
#[macro_use]
|
||||
extern crate user_lib;
|
||||
use user_lib::{get_time, set_priority};
|
||||
|
||||
fn spin_delay() {
|
||||
let mut j = true;
|
||||
for _ in 0..10 {
|
||||
j = !j;
|
||||
}
|
||||
}
|
||||
|
||||
// to get enough accuracy, MAX_TIME (the running time of each process) should > 1000 mseconds.
|
||||
const MAX_TIME: isize = 1000;
|
||||
fn count_during(prio: isize) -> isize {
|
||||
let start_time = get_time();
|
||||
let mut acc = 0;
|
||||
set_priority(prio);
|
||||
loop {
|
||||
spin_delay();
|
||||
acc += 1;
|
||||
if acc % 400 == 0 {
|
||||
let time = get_time() - start_time;
|
||||
if time > MAX_TIME {
|
||||
return acc;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn main() -> usize {
|
||||
let prio = 8;
|
||||
let count = count_during(prio);
|
||||
println!("priority = {}, exitcode = {}", prio, count);
|
||||
0
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
#[macro_use]
|
||||
extern crate user_lib;
|
||||
use user_lib::{get_time, set_priority};
|
||||
|
||||
fn spin_delay() {
|
||||
let mut j = true;
|
||||
for _ in 0..10 {
|
||||
j = !j;
|
||||
}
|
||||
}
|
||||
|
||||
// to get enough accuracy, MAX_TIME (the running time of each process) should > 1000 mseconds.
|
||||
const MAX_TIME: isize = 1000;
|
||||
fn count_during(prio: isize) -> isize {
|
||||
let start_time = get_time();
|
||||
let mut acc = 0;
|
||||
set_priority(prio);
|
||||
loop {
|
||||
spin_delay();
|
||||
acc += 1;
|
||||
if acc % 400 == 0 {
|
||||
let time = get_time() - start_time;
|
||||
if time > MAX_TIME {
|
||||
return acc;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn main() -> usize {
|
||||
let prio = 9;
|
||||
let count = count_during(prio);
|
||||
println!("priority = {}, exitcode = {}", prio, count);
|
||||
0
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
#[macro_use]
|
||||
extern crate user_lib;
|
||||
use user_lib::{get_time, set_priority};
|
||||
|
||||
fn spin_delay() {
|
||||
let mut j = true;
|
||||
for _ in 0..10 {
|
||||
j = !j;
|
||||
}
|
||||
}
|
||||
|
||||
// to get enough accuracy, MAX_TIME (the running time of each process) should > 1000 mseconds.
|
||||
const MAX_TIME: isize = 1000;
|
||||
fn count_during(prio: isize) -> isize {
|
||||
let start_time = get_time();
|
||||
let mut acc = 0;
|
||||
set_priority(prio);
|
||||
loop {
|
||||
spin_delay();
|
||||
acc += 1;
|
||||
if acc % 400 == 0 {
|
||||
let time = get_time() - start_time;
|
||||
if time > MAX_TIME {
|
||||
return acc;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn main() -> usize {
|
||||
let prio = 10;
|
||||
let count = count_during(prio);
|
||||
println!("priority = {}, exitcode = {}", prio, count);
|
||||
0
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
#[macro_use]
|
||||
extern crate user_lib;
|
||||
|
||||
use user_lib::yield_;
|
||||
|
||||
const WIDTH: usize = 10;
|
||||
const HEIGHT: usize = 5;
|
||||
|
||||
/*
|
||||
理想结果:三个程序交替输出 ABC
|
||||
*/
|
||||
|
||||
#[no_mangle]
|
||||
fn main() -> i32 {
|
||||
for i in 0..HEIGHT {
|
||||
let buf = ['A' as u8; WIDTH];
|
||||
println!(
|
||||
"{} [{}/{}]",
|
||||
core::str::from_utf8(&buf).unwrap(),
|
||||
i + 1,
|
||||
HEIGHT
|
||||
);
|
||||
yield_();
|
||||
}
|
||||
println!("Test write A OK!");
|
||||
0
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
#[macro_use]
|
||||
extern crate user_lib;
|
||||
|
||||
use user_lib::yield_;
|
||||
|
||||
const WIDTH: usize = 10;
|
||||
const HEIGHT: usize = 5;
|
||||
|
||||
/*
|
||||
理想结果:三个程序交替输出 ABC
|
||||
*/
|
||||
|
||||
#[no_mangle]
|
||||
#[no_mangle]
|
||||
fn main() -> i32 {
|
||||
for i in 0..HEIGHT {
|
||||
let buf = ['B' as u8; WIDTH];
|
||||
println!(
|
||||
"{} [{}/{}]",
|
||||
core::str::from_utf8(&buf).unwrap(),
|
||||
i + 1,
|
||||
HEIGHT
|
||||
);
|
||||
yield_();
|
||||
}
|
||||
println!("Test write B OK!");
|
||||
0
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
#[macro_use]
|
||||
extern crate user_lib;
|
||||
|
||||
use user_lib::yield_;
|
||||
|
||||
/*
|
||||
理想结果:三个程序交替输出 ABC
|
||||
*/
|
||||
|
||||
const WIDTH: usize = 10;
|
||||
const HEIGHT: usize = 5;
|
||||
|
||||
#[no_mangle]
|
||||
#[no_mangle]
|
||||
fn main() -> i32 {
|
||||
for i in 0..HEIGHT {
|
||||
let buf = ['C' as u8; WIDTH];
|
||||
println!(
|
||||
"{} [{}/{}]",
|
||||
core::str::from_utf8(&buf).unwrap(),
|
||||
i + 1,
|
||||
HEIGHT
|
||||
);
|
||||
yield_();
|
||||
}
|
||||
println!("Test write C OK!");
|
||||
0
|
||||
}
|
|
@ -1,52 +1,19 @@
|
|||
use alloc::collections::vec_deque::VecDeque;
|
||||
use alloc::sync::Arc;
|
||||
use core::fmt::{self, Write};
|
||||
use spin::mutex::Mutex;
|
||||
use super::write;
|
||||
|
||||
pub const STDIN: usize = 0;
|
||||
pub const STDOUT: usize = 1;
|
||||
struct Stdout;
|
||||
|
||||
const CONSOLE_BUFFER_SIZE: usize = 256 * 10;
|
||||
const STDOUT: usize = 1;
|
||||
|
||||
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)))
|
||||
};
|
||||
}
|
||||
|
||||
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 ConsoleBuffer {
|
||||
impl Write for Stdout {
|
||||
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||
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);
|
||||
}
|
||||
}
|
||||
write(STDOUT, s.as_bytes());
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn print(args: fmt::Arguments) {
|
||||
let mut buf = CONSOLE_BUFFER.lock();
|
||||
// buf.write_fmt(args).unwrap();
|
||||
// BUG FIX: 关闭 stdout 后,本函数不能触发 panic,否则会造成死锁
|
||||
buf.write_fmt(args);
|
||||
Stdout.write_fmt(args).unwrap();
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
|
@ -62,14 +29,3 @@ macro_rules! println {
|
|||
$crate::console::print(format_args!(concat!($fmt, "\n") $(, $($arg)+)?));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn getchar() -> u8 {
|
||||
let mut c = [0u8; 1];
|
||||
read(STDIN, &mut c);
|
||||
c[0]
|
||||
}
|
||||
|
||||
pub fn flush() {
|
||||
let mut buf = CONSOLE_BUFFER.lock();
|
||||
buf.flush();
|
||||
}
|
||||
|
|
|
@ -1,17 +1,10 @@
|
|||
use crate::exit;
|
||||
|
||||
#[panic_handler]
|
||||
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);
|
||||
loop {}
|
||||
}
|
229
user/src/lib.rs
229
user/src/lib.rs
|
@ -2,42 +2,18 @@
|
|||
#![feature(asm)]
|
||||
#![feature(linkage)]
|
||||
#![feature(panic_info_message)]
|
||||
#![feature(alloc_error_handler)]
|
||||
|
||||
#[macro_use]
|
||||
pub mod console;
|
||||
mod lang_items;
|
||||
mod syscall;
|
||||
|
||||
extern crate alloc;
|
||||
extern crate core;
|
||||
#[macro_use]
|
||||
extern crate bitflags;
|
||||
|
||||
use buddy_system_allocator::LockedHeap;
|
||||
pub use console::{flush, STDIN, STDOUT};
|
||||
pub use syscall::*;
|
||||
|
||||
const USER_HEAP_SIZE: usize = 16384;
|
||||
|
||||
static mut HEAP_SPACE: [u8; USER_HEAP_SIZE] = [0; USER_HEAP_SIZE];
|
||||
|
||||
#[global_allocator]
|
||||
static HEAP: LockedHeap = LockedHeap::empty();
|
||||
|
||||
#[alloc_error_handler]
|
||||
pub fn handle_alloc_error(layout: core::alloc::Layout) -> ! {
|
||||
panic!("Heap allocation error, layout = {:?}", layout);
|
||||
}
|
||||
mod lang_items;
|
||||
|
||||
#[no_mangle]
|
||||
#[link_section = ".text.entry"]
|
||||
pub extern "C" fn _start() -> ! {
|
||||
unsafe {
|
||||
HEAP.lock()
|
||||
.init(HEAP_SPACE.as_ptr() as usize, USER_HEAP_SIZE);
|
||||
}
|
||||
clear_bss();
|
||||
exit(main());
|
||||
panic!("unreachable after sys_exit!");
|
||||
}
|
||||
|
||||
#[linkage = "weak"]
|
||||
|
@ -46,194 +22,19 @@ fn main() -> i32 {
|
|||
panic!("Cannot find main!");
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
pub struct OpenFlags: u32 {
|
||||
const RDONLY = 0;
|
||||
const WRONLY = 1 << 0;
|
||||
const RDWR = 1 << 1;
|
||||
const CREATE = 1 << 9;
|
||||
const TRUNC = 1 << 10;
|
||||
fn clear_bss() {
|
||||
extern "C" {
|
||||
fn start_bss();
|
||||
fn end_bss();
|
||||
}
|
||||
(start_bss as usize..end_bss as usize).for_each(|addr| {
|
||||
unsafe { (addr as *mut u8).write_volatile(0); }
|
||||
});
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Default)]
|
||||
pub struct TimeVal {
|
||||
pub sec: usize,
|
||||
pub usec: usize,
|
||||
}
|
||||
use syscall::*;
|
||||
|
||||
impl TimeVal {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
}
|
||||
|
||||
#[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],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Stat {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
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) -> isize {
|
||||
sys_exec(path)
|
||||
}
|
||||
|
||||
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 => {
|
||||
sys_yield();
|
||||
}
|
||||
n => {
|
||||
return n;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn waitpid(pid: usize, exit_code: &mut i32) -> isize {
|
||||
loop {
|
||||
match sys_waitpid(pid as isize, exit_code as *mut _) {
|
||||
-2 => {
|
||||
sys_yield();
|
||||
}
|
||||
n => {
|
||||
return n;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sleep(period_ms: usize) {
|
||||
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)
|
||||
}
|
||||
pub fn write(fd: usize, buf: &[u8]) -> isize { sys_write(fd, buf) }
|
||||
pub fn exit(exit_code: i32) -> isize { sys_exit(exit_code) }
|
||||
pub fn yield_() -> isize { sys_yield() }
|
||||
pub fn get_time() -> isize { sys_get_time() }
|
|
@ -1,29 +1,9 @@
|
|||
use super::{Stat, TimeVal};
|
||||
const SYSCALL_WRITE: usize = 64;
|
||||
const SYSCALL_EXIT: usize = 93;
|
||||
const SYSCALL_YIELD: usize = 124;
|
||||
const SYSCALL_GET_TIME: usize = 169;
|
||||
|
||||
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 {
|
||||
fn syscall(id: usize, args: [usize; 3]) -> isize {
|
||||
let mut ret: isize;
|
||||
unsafe {
|
||||
asm!(
|
||||
|
@ -37,143 +17,18 @@ pub fn syscall(id: usize, args: [usize; 3]) -> isize {
|
|||
ret
|
||||
}
|
||||
|
||||
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_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_read(fd: usize, buffer: &mut [u8]) -> isize {
|
||||
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!");
|
||||
pub fn sys_exit(exit_code: i32) -> isize {
|
||||
syscall(SYSCALL_EXIT, [exit_code as usize, 0, 0])
|
||||
}
|
||||
|
||||
pub fn sys_yield() -> isize {
|
||||
syscall(SYSCALL_YIELD, [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 {
|
||||
syscall(SYSCALL_GETPID, [0, 0, 0])
|
||||
}
|
||||
|
||||
pub fn sys_fork() -> isize {
|
||||
syscall(SYSCALL_FORK, [0, 0, 0])
|
||||
}
|
||||
|
||||
pub fn sys_exec(path: &str) -> isize {
|
||||
syscall(SYSCALL_EXEC, [path.as_ptr() as usize, 0, 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])
|
||||
pub fn sys_get_time() -> isize {
|
||||
syscall(SYSCALL_GET_TIME, [0, 0, 0])
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue