diff --git a/.gitignore b/.gitignore index aa359a4..614368a 100644 --- a/.gitignore +++ b/.gitignore @@ -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 \ No newline at end of file diff --git a/README.md b/README.md index e2dc4e3..e28e783 100644 --- a/README.md +++ b/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] diff --git a/dev-env-info.md b/dev-env-info.md deleted file mode 100644 index f76470a..0000000 --- a/dev-env-info.md +++ /dev/null @@ -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 diff --git a/os/Makefile b/os/Makefile index a9ed0b7..35049e0 100644 --- a/os/Makefile +++ b/os/Makefile @@ -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)" diff --git a/os/build.rs b/os/build.rs index 4a44c56..5e03231 100644 --- a/os/build.rs +++ b/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(()) -} +} \ No newline at end of file diff --git a/os/src/config.rs b/os/src/config.rs index 3b994cd..e50175a 100644 --- a/os/src/config.rs +++ b/os/src/config.rs @@ -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; diff --git a/os/src/syscall/mod.rs b/os/src/syscall/mod.rs index 8ca22fe..da41168 100644 --- a/os/src/syscall/mod.rs +++ b/os/src/syscall/mod.rs @@ -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), } } diff --git a/os/src/syscall/process.rs b/os/src/syscall/process.rs index d016849..23eab1f 100644 --- a/os/src/syscall/process.rs +++ b/os/src/syscall/process.rs @@ -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 } \ No newline at end of file diff --git a/os/src/timer.rs b/os/src/timer.rs index 8b908bc..ad226e6 100644 --- a/os/src/timer.rs +++ b/os/src/timer.rs @@ -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() { diff --git a/user/Cargo.toml b/user/Cargo.toml index 01b75c2..817ca52 100644 --- a/user/Cargo.toml +++ b/user/Cargo.toml @@ -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"] } diff --git a/user/Makefile b/user/Makefile index 284b240..5ca334e 100644 --- a/user/Makefile +++ b/user/Makefile @@ -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 \ No newline at end of file diff --git a/user/build.py b/user/build.py index aababef..23c6d05 100644 --- a/user/build.py +++ b/user/build.py @@ -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('.')] diff --git a/user/src/bin/power_3.rs b/user/src/bin/00power_3.rs similarity index 100% rename from user/src/bin/power_3.rs rename to user/src/bin/00power_3.rs diff --git a/user/src/bin/power_5.rs b/user/src/bin/01power_5.rs similarity index 100% rename from user/src/bin/power_5.rs rename to user/src/bin/01power_5.rs diff --git a/user/src/bin/power_7.rs b/user/src/bin/02power_7.rs similarity index 100% rename from user/src/bin/power_7.rs rename to user/src/bin/02power_7.rs diff --git a/user/src/bin/03sleep.rs b/user/src/bin/03sleep.rs new file mode 100644 index 0000000..8341123 --- /dev/null +++ b/user/src/bin/03sleep.rs @@ -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 +} \ No newline at end of file diff --git a/user/src/bin/sleep.rs b/user/src/bin/sleep.rs deleted file mode 100644 index 1312f6c..0000000 --- a/user/src/bin/sleep.rs +++ /dev/null @@ -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 -} diff --git a/user/src/bin/sleep1.rs b/user/src/bin/sleep1.rs deleted file mode 100644 index da0cae3..0000000 --- a/user/src/bin/sleep1.rs +++ /dev/null @@ -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 -} diff --git a/user/src/bin/test1_write0.rs b/user/src/bin/test1_write0.rs deleted file mode 100644 index c4a77cc..0000000 --- a/user/src/bin/test1_write0.rs +++ /dev/null @@ -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 -} diff --git a/user/src/bin/test1_write1.rs b/user/src/bin/test1_write1.rs deleted file mode 100644 index 276ad9c..0000000 --- a/user/src/bin/test1_write1.rs +++ /dev/null @@ -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 -} diff --git a/user/src/bin/test2_setprio.rs b/user/src/bin/test2_setprio.rs deleted file mode 100644 index 6aa1064..0000000 --- a/user/src/bin/test2_setprio.rs +++ /dev/null @@ -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 -} diff --git a/user/src/bin/test3_stride0.rs b/user/src/bin/test3_stride0.rs deleted file mode 100644 index 7fd9764..0000000 --- a/user/src/bin/test3_stride0.rs +++ /dev/null @@ -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 -} diff --git a/user/src/bin/test3_stride1.rs b/user/src/bin/test3_stride1.rs deleted file mode 100644 index 52eb18a..0000000 --- a/user/src/bin/test3_stride1.rs +++ /dev/null @@ -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 -} \ No newline at end of file diff --git a/user/src/bin/test3_stride2.rs b/user/src/bin/test3_stride2.rs deleted file mode 100644 index e2c032c..0000000 --- a/user/src/bin/test3_stride2.rs +++ /dev/null @@ -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 -} \ No newline at end of file diff --git a/user/src/bin/test3_stride3.rs b/user/src/bin/test3_stride3.rs deleted file mode 100644 index 71348cc..0000000 --- a/user/src/bin/test3_stride3.rs +++ /dev/null @@ -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 -} \ No newline at end of file diff --git a/user/src/bin/test3_stride4.rs b/user/src/bin/test3_stride4.rs deleted file mode 100644 index 40369e7..0000000 --- a/user/src/bin/test3_stride4.rs +++ /dev/null @@ -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 -} \ No newline at end of file diff --git a/user/src/bin/test3_stride5.rs b/user/src/bin/test3_stride5.rs deleted file mode 100644 index 580494a..0000000 --- a/user/src/bin/test3_stride5.rs +++ /dev/null @@ -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 -} \ No newline at end of file diff --git a/user/src/bin/yield0.rs b/user/src/bin/yield0.rs deleted file mode 100644 index 1e09edd..0000000 --- a/user/src/bin/yield0.rs +++ /dev/null @@ -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 -} diff --git a/user/src/bin/yield1.rs b/user/src/bin/yield1.rs deleted file mode 100644 index 3d91adf..0000000 --- a/user/src/bin/yield1.rs +++ /dev/null @@ -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 -} diff --git a/user/src/bin/yield2.rs b/user/src/bin/yield2.rs deleted file mode 100644 index 05ea13a..0000000 --- a/user/src/bin/yield2.rs +++ /dev/null @@ -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 -} diff --git a/user/src/console.rs b/user/src/console.rs index 6d6d1f3..ac80117 100644 --- a/user/src/console.rs +++ b/user/src/console.rs @@ -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); - -lazy_static! { - static ref CONSOLE_BUFFER: Arc> = { - let buffer = VecDeque::::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] @@ -61,15 +28,4 @@ macro_rules! println { ($fmt: literal $(, $($arg: tt)+)?) => { $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(); -} +} \ No newline at end of file diff --git a/user/src/lang_items.rs b/user/src/lang_items.rs index 2d81a1d..c90d297 100644 --- a/user/src/lang_items.rs +++ b/user/src/lang_items.rs @@ -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 {} +} \ No newline at end of file diff --git a/user/src/lib.rs b/user/src/lib.rs index d97fbf3..902c542 100644 --- a/user/src/lib.rs +++ b/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() } \ No newline at end of file diff --git a/user/src/syscall.rs b/user/src/syscall.rs index 7aaa584..ed3d16a 100644 --- a/user/src/syscall.rs +++ b/user/src/syscall.rs @@ -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]) +} \ No newline at end of file