From 6b51c34c4396058200730328f4c28155a690b2cb Mon Sep 17 00:00:00 2001 From: Yu Chen Date: Fri, 24 Jun 2022 02:25:30 +0800 Subject: [PATCH] add CI autotest, update README --- .github/workflows/build-doc.yml | 25 ------ .github/workflows/doc-and-test.yml | 69 +++++++++++++++ README.md | 82 ++++++++++++----- os/Makefile | 5 +- os/src/boards/k210.rs | 1 + os/src/boards/qemu.rs | 86 +++++++++++++++++- os/src/task/id.rs | 2 + os/src/task/mod.rs | 21 ++++- user/Makefile | 6 ++ user/src/bin/usertests.rs | 136 ++++++++++++++++++++++++----- user/src/bin/usertests_simple.rs | 43 +++++++++ 11 files changed, 404 insertions(+), 72 deletions(-) delete mode 100644 .github/workflows/build-doc.yml create mode 100644 .github/workflows/doc-and-test.yml create mode 100644 user/src/bin/usertests_simple.rs diff --git a/.github/workflows/build-doc.yml b/.github/workflows/build-doc.yml deleted file mode 100644 index a48f1474..00000000 --- a/.github/workflows/build-doc.yml +++ /dev/null @@ -1,25 +0,0 @@ -name: Build Rust Doc - -on: [push] - -env: - CARGO_TERM_COLOR: always - -jobs: - build-doc: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: Build doc - run: | - rustup target add riscv64gc-unknown-none-elf - rustup component add llvm-tools-preview - rustup component add rust-src - cd os - cargo doc --no-deps --verbose - - name: Deploy to Github Pages - uses: peaceiris/actions-gh-pages@v3 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - publish_dir: ./os/target/riscv64gc-unknown-none-elf/doc - destination_dir: ${{ github.ref_name }} \ No newline at end of file diff --git a/.github/workflows/doc-and-test.yml b/.github/workflows/doc-and-test.yml new file mode 100644 index 00000000..98fdc666 --- /dev/null +++ b/.github/workflows/doc-and-test.yml @@ -0,0 +1,69 @@ +name: Build Rust Doc And Run tests + +on: [push] + +env: + CARGO_TERM_COLOR: always + +jobs: + build-doc: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: nightly-2022-04-11 + components: rust-src, llvm-tools-preview + target: riscv64gc-unknown-none-elf + - name: Build doc + run: cd os && cargo doc --no-deps --verbose --features "board_qemu" + - name: Deploy to Github Pages + uses: peaceiris/actions-gh-pages@v3 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: ./os/target/riscv64gc-unknown-none-elf/doc + destination_dir: ${{ github.ref_name }} + + run-tests: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: nightly-2022-04-11 + components: rust-src, llvm-tools-preview + target: riscv64gc-unknown-none-elf + - uses: actions-rs/install@v0.1 + with: + crate: cargo-binutils + version: latest + use-tool-cache: true + - name: Cache QEMU + uses: actions/cache@v3 + with: + path: qemu-7.0.0 + key: qemu-7.0.0-x86_64-riscv64 + - name: Install QEMU + run: | + sudo apt-get update + sudo apt-get install ninja-build -y + if [ ! -d qemu-7.0.0 ]; then + wget https://download.qemu.org/qemu-7.0.0.tar.xz + tar -xf qemu-7.0.0.tar.xz + cd qemu-7.0.0 + ./configure --target-list=riscv64-softmmu + make -j + else + cd qemu-7.0.0 + fi + sudo make install + qemu-system-riscv64 --version + + - name: Run usertests + run: cd os && make run TEST=1 + timeout-minutes: 10 + + - name: Build for k210 + run: cd os && make build BOARD=k210 \ No newline at end of file diff --git a/README.md b/README.md index 5f27d55e..767cb147 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,14 @@ # 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.6. See the [Documentation in Chinese](https://rcore-os.github.io/rCore-Tutorial-Book-v3/). rCore-Tutorial API Docs. See the [API Docs of Ten OSes ](#OS-API-DOCS) +If you don't know Rust Language and try to learn it, please visit [Rust Learning Resources](https://github.com/rcore-os/rCore/wiki/study-resource-of-system-programming-in-RUST) + Official QQ group number: 735045051 ## news -- 25/01/2022: Version 3.6.0 is on the way! Now we directly update the code on chX branches, please periodically check if there are any updates. +- 23/06/2022: Version 3.6.0 is on the way! Now we directly update the code on chX branches, please periodically check if there are any updates. ## Overview @@ -42,7 +44,7 @@ $ rustup component add rust-src ### Install Qemu -Here we manually compile and install Qemu 5.0.0. For example, on Ubuntu 18.04: +Here we manually compile and install Qemu 7.0.0. For example, on Ubuntu 18.04: ```sh # install dependency packages @@ -50,10 +52,10 @@ $ sudo apt install autoconf automake autotools-dev curl libmpc-dev libmpfr-dev l gawk build-essential bison flex texinfo gperf libtool patchutils bc \ zlib1g-dev libexpat-dev pkg-config libglib2.0-dev libpixman-1-dev git tmux python3 python3-pip # download Qemu source code -$ wget https://download.qemu.org/qemu-5.0.0.tar.xz -# extract to qemu-5.0.0/ -$ tar xvJf qemu-5.0.0.tar.xz -$ cd qemu-5.0.0 +$ wget https://download.qemu.org/qemu-7.0.0.tar.xz +# extract to qemu-7.0.0/ +$ tar xvJf qemu-7.0.0.tar.xz +$ cd qemu-7.0.0 # build $ ./configure --target-list=riscv64-softmmu,riscv64-linux-user $ make -j$(nproc) @@ -62,9 +64,9 @@ $ make -j$(nproc) Then, add following contents to `~/.bashrc`(please adjust these paths according to your environment): ``` -export PATH=$PATH:/home/shinbokuow/Downloads/built/qemu-5.0.0 -export PATH=$PATH:/home/shinbokuow/Downloads/built/qemu-5.0.0/riscv64-softmmu -export PATH=$PATH:/home/shinbokuow/Downloads/built/qemu-5.0.0/riscv64-linux-user +export PATH=$PATH:/home/shinbokuow/Downloads/built/qemu-7.0.0 +export PATH=$PATH:/home/shinbokuow/Downloads/built/qemu-7.0.0/riscv64-softmmu +export PATH=$PATH:/home/shinbokuow/Downloads/built/qemu-7.0.0/riscv64-linux-user ``` Finally, update the current shell: @@ -77,7 +79,7 @@ Now we can check the version of Qemu: ```sh $ qemu-system-riscv64 --version -QEMU emulator version 5.0.0 +QEMU emulator version 7.0.0 Copyright (c) 2003-2020 Fabrice Bellard and the QEMU Project developers ``` @@ -188,6 +190,46 @@ $ make run BOARD=k210 Type `Ctrl+]` to disconnect from K210. + +## Show runtime debug info of OS kernel version +The branch of ch9-log contains a lot of debug info. You could try to run rcore tutorial +for understand the internal behavior of os kernel. + +```sh +$ git clone https://github.com/rcore-os/rCore-Tutorial-v3.git +$ cd rCore-Tutorial-v3/os +$ git checkout ch9-log +$ make run +...... +[rustsbi] RustSBI version 0.2.0-alpha.10, adapting to RISC-V SBI v0.3 +.______ __ __ _______.___________. _______..______ __ +| _ \ | | | | / | | / || _ \ | | +| |_) | | | | | | (----`---| |----`| (----`| |_) || | +| / | | | | \ \ | | \ \ | _ < | | +| |\ \----.| `--' |.----) | | | .----) | | |_) || | +| _| `._____| \______/ |_______/ |__| |_______/ |______/ |__| + +[rustsbi] Implementation: RustSBI-QEMU Version 0.0.2 +[rustsbi-dtb] Hart count: cluster0 with 1 cores +[rustsbi] misa: RV64ACDFIMSU +[rustsbi] mideleg: ssoft, stimer, sext (0x222) +[rustsbi] medeleg: ima, ia, bkpt, la, sa, uecall, ipage, lpage, spage (0xb1ab) +[rustsbi] pmp0: 0x10000000 ..= 0x10001fff (rw-) +[rustsbi] pmp1: 0x2000000 ..= 0x200ffff (rw-) +[rustsbi] pmp2: 0xc000000 ..= 0xc3fffff (rw-) +[rustsbi] pmp3: 0x80000000 ..= 0x8fffffff (rwx) +[rustsbi] enter supervisor 0x80200000 +[KERN] rust_main() begin +[KERN] clear_bss() begin +[KERN] clear_bss() end +[KERN] mm::init() begin +[KERN] mm::init_heap() begin +[KERN] mm::init_heap() end +[KERN] mm::init_frame_allocator() begin +[KERN] mm::frame_allocator::lazy_static!FRAME_ALLOCATOR begin +...... +``` + ## Rustdoc Currently it can only help you view the code since only a tiny part of the code has been documented. @@ -209,13 +251,9 @@ The API Docs for Ten OS ## Working in progress -Our first release 3.5.0 (chapter 1-7) has been published. +Our first release 3.6.0 (chapter 1-9) has been published, and we are still working on it. -There will be 9 chapters in our next release 3.6.0, where 2 new chapters will be added: -* chapter 8: synchronization on a uniprocessor -* chapter 9: I/O devices - -Current version is 3.6.0-alpha.1 and we are still working on it. +* chapter 9: need more descripts about different I/O devices Here are the updates since 3.5.0: @@ -237,18 +275,16 @@ Here are the updates since 3.5.0: * [x] switch the code of chapter 6 and chapter 7 * [x] support signal mechanism in chapter 7/8(only works for apps with a single thread) * [x] Add boards/ directory and support rustdoc, for example you can use `cargo doc --no-deps --open` to view the documentation of a crate - +* [x] code of chapter 9: device drivers based on interrupts, including UART, block, keyboard, mouse, gpu devices +* [x] add CI autotest and doc in github ### Todo(High priority) -* [ ] review documentation, current progress: 5/9 -* [ ] support user-level sync primitives in chapter 8 -* [ ] code of chapter 9: device drivers based on interrupts, including UART and block devices +* [ ] review documentation, current progress: 8/9 * [ ] 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 - +* [ ] add more os functions for understanding os conecpts and principles ### Todo(Low priority) * [ ] rewrite practice doc and remove some inproper questions diff --git a/os/Makefile b/os/Makefile index 91ae60bf..0add3d2d 100644 --- a/os/Makefile +++ b/os/Makefile @@ -37,6 +37,9 @@ OBJCOPY := rust-objcopy --binary-architecture=riscv64 # Disassembly DISASM ?= -x +# Run usertests or usershell +TEST ?= + build: env switch-check $(KERNEL_BIN) fs-img switch-check: @@ -61,7 +64,7 @@ $(KERNEL_BIN): kernel @$(OBJCOPY) $(KERNEL_ELF) --strip-all -O binary $@ fs-img: $(APPS) - @cd ../user && make build + @cd ../user && make build TEST=$(TEST) @rm -f $(FS_IMG) @cd ../easy-fs-fuse && cargo run --release -- -s ../user/src/bin/ -t ../user/target/riscv64gc-unknown-none-elf/release/ diff --git a/os/src/boards/k210.rs b/os/src/boards/k210.rs index aa6d1ea6..6f65be16 100644 --- a/os/src/boards/k210.rs +++ b/os/src/boards/k210.rs @@ -1,4 +1,5 @@ pub const CLOCK_FREQ: usize = 403000000 / 62; +pub const MEMORY_END: usize = 0x80600000; pub const MMIO: &[(usize, usize)] = &[ // we don't need clint in S priv when running diff --git a/os/src/boards/qemu.rs b/os/src/boards/qemu.rs index b49ccc27..0508dfa5 100644 --- a/os/src/boards/qemu.rs +++ b/os/src/boards/qemu.rs @@ -1,5 +1,89 @@ pub const CLOCK_FREQ: usize = 12500000; +pub const MEMORY_END: usize = 0x801000000; -pub const MMIO: &[(usize, usize)] = &[(0x10001000, 0x1000)]; +pub const MMIO: &[(usize, usize)] = &[ + (0x0010_0000, 0x00_2000), // VIRT_TEST/RTC in virt machine + (0x1000_1000, 0x00_1000), // Virtio Block in virt machine +]; pub type BlockDeviceImpl = crate::drivers::block::VirtIOBlock; + +//ref:: https://github.com/andre-richter/qemu-exit +use core::arch::asm; + +const EXIT_SUCCESS: u32 = 0x5555; // Equals `exit(0)`. qemu successful exit + +const EXIT_FAILURE_FLAG: u32 = 0x3333; +const EXIT_FAILURE: u32 = exit_code_encode(1); // Equals `exit(1)`. qemu failed exit +const EXIT_RESET: u32 = 0x7777; // qemu reset + +pub trait QEMUExit { + /// Exit with specified return code. + /// + /// Note: For `X86`, code is binary-OR'ed with `0x1` inside QEMU. + fn exit(&self, code: u32) -> !; + + /// Exit QEMU using `EXIT_SUCCESS`, aka `0`, if possible. + /// + /// Note: Not possible for `X86`. + fn exit_success(&self) -> !; + + /// Exit QEMU using `EXIT_FAILURE`, aka `1`. + fn exit_failure(&self) -> !; +} + +/// RISCV64 configuration +pub struct RISCV64 { + /// Address of the sifive_test mapped device. + addr: u64, +} + +/// Encode the exit code using EXIT_FAILURE_FLAG. +const fn exit_code_encode(code: u32) -> u32 { + (code << 16) | EXIT_FAILURE_FLAG +} + +impl RISCV64 { + /// Create an instance. + pub const fn new(addr: u64) -> Self { + RISCV64 { addr } + } +} + +impl QEMUExit for RISCV64 { + /// Exit qemu with specified exit code. + fn exit(&self, code: u32) -> ! { + // If code is not a special value, we need to encode it with EXIT_FAILURE_FLAG. + let code_new = match code { + EXIT_SUCCESS | EXIT_FAILURE | EXIT_RESET => code, + _ => exit_code_encode(code), + }; + + unsafe { + asm!( + "sw {0}, 0({1})", + in(reg)code_new, in(reg)self.addr + ); + + // For the case that the QEMU exit attempt did not work, transition into an infinite + // loop. Calling `panic!()` here is unfeasible, since there is a good chance + // this function here is the last expression in the `panic!()` handler + // itself. This prevents a possible infinite loop. + loop { + asm!("wfi", options(nomem, nostack)); + } + } + } + + fn exit_success(&self) -> ! { + self.exit(EXIT_SUCCESS); + } + + fn exit_failure(&self) -> ! { + self.exit(EXIT_FAILURE); + } +} + +const VIRT_TEST: u64 = 0x100000; + +pub const QEMU_EXIT_HANDLE: RISCV64 = RISCV64::new(VIRT_TEST); diff --git a/os/src/task/id.rs b/os/src/task/id.rs index 178a09f6..3b5aa0d2 100644 --- a/os/src/task/id.rs +++ b/os/src/task/id.rs @@ -46,6 +46,8 @@ lazy_static! { unsafe { UPSafeCell::new(RecycleAllocator::new()) }; } +pub const IDLE_PID: usize = 0; + pub struct PidHandle(pub usize); pub fn pid_alloc() -> PidHandle { diff --git a/os/src/task/mod.rs b/os/src/task/mod.rs index 94eb18bb..8d756286 100644 --- a/os/src/task/mod.rs +++ b/os/src/task/mod.rs @@ -18,7 +18,7 @@ use switch::__switch; use crate::timer::remove_timer; pub use context::TaskContext; -pub use id::{kstack_alloc, pid_alloc, KernelStack, PidHandle}; +pub use id::{kstack_alloc, pid_alloc, KernelStack, PidHandle, IDLE_PID}; pub use manager::{add_task, remove_task, pid2process, remove_from_pid2process}; pub use processor::{ current_kstack_top, current_process, current_task, current_trap_cx, current_trap_cx_user_va, @@ -53,6 +53,8 @@ pub fn block_current_and_run_next() { drop(task_inner); schedule(task_cx_ptr); } +#[cfg(feature = "board_qemu")] +use crate::board::QEMUExit; pub fn exit_current_and_run_next(exit_code: i32) { let task = take_current_task().unwrap(); @@ -69,7 +71,22 @@ pub fn exit_current_and_run_next(exit_code: i32) { // however, if this is the main thread of current process // the process should terminate at once if tid == 0 { - remove_from_pid2process(process.getpid()); + let pid = process.getpid(); + #[cfg(feature = "board_qemu")] + if pid == IDLE_PID { + println!( + "[kernel] Idle process exit with exit_code {} ...", + exit_code + ); + if exit_code != 0 { + //crate::sbi::shutdown(255); //255 == -1 for err hint + crate::board::QEMU_EXIT_HANDLE.exit_failure(); + } else { + //crate::sbi::shutdown(0); //0 for success hint + crate::board::QEMU_EXIT_HANDLE.exit_success(); + } + } + remove_from_pid2process(pid); let mut process_inner = process.inner_exclusive_access(); // mark this process as a zombie process process_inner.is_zombie = true; diff --git a/user/Makefile b/user/Makefile index e2eaf994..c09b5e96 100644 --- a/user/Makefile +++ b/user/Makefile @@ -8,9 +8,15 @@ BINS := $(patsubst $(APP_DIR)/%.rs, $(TARGET_DIR)/%.bin, $(APPS)) OBJDUMP := rust-objdump --arch-name=riscv64 OBJCOPY := rust-objcopy --binary-architecture=riscv64 +CP := cp + +TEST ?= elf: $(APPS) @cargo build --release +ifeq ($(TEST), 1) + @$(CP) $(TARGET_DIR)/usertests $(TARGET_DIR)/initproc +endif binary: elf $(foreach elf, $(ELFS), $(OBJCOPY) $(elf) --strip-all -O binary $(patsubst $(TARGET_DIR)/%, $(TARGET_DIR)/%.bin, $(elf));) diff --git a/user/src/bin/usertests.rs b/user/src/bin/usertests.rs index 4fd49a4f..553757b9 100644 --- a/user/src/bin/usertests.rs +++ b/user/src/bin/usertests.rs @@ -4,40 +4,136 @@ #[macro_use] extern crate user_lib; -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", +// not in SUCC_TESTS & FAIL_TESTS +// count_lines, infloop, user_shell, usertests + +// item of TESTS : app_name(argv_0), argv_1, argv_2, argv_3, exit_code +static SUCC_TESTS: &[(&str, &str, &str, &str, i32)] = &[ + ("filetest_simple\0", "\0", "\0", "\0", 0), + ("cat\0", "filea\0", "\0", "\0", 0), + ("cmdline_args\0", "1\0", "2\0", "3\0", 0), + ("exit\0", "\0", "\0", "\0", 0), + ("fantastic_text\0", "\0", "\0", "\0", 0), + ("forktest_simple\0", "\0", "\0", "\0", 0), + ("forktest\0", "\0", "\0", "\0", 0), + ("forktest2\0", "\0", "\0", "\0", 0), + ("forktree\0", "\0", "\0", "\0", 0), + ("hello_world\0", "\0", "\0", "\0", 0), + ("huge_write\0", "\0", "\0", "\0", 0), + ("matrix\0", "\0", "\0", "\0", 0), + ("mpsc_sem\0", "\0", "\0", "\0", 0), + ("phil_din_mutex\0", "\0", "\0", "\0", 0), + ("pipe_large_test\0", "\0", "\0", "\0", 0), + ("pipetest\0", "\0", "\0", "\0", 0), + ("race_adder_arg\0", "3\0", "\0", "\0", 0), + ("race_adder_atomic\0", "\0", "\0", "\0", 0), + ("race_adder_mutex_blocking\0", "\0", "\0", "\0", 0), + ("race_adder_mutex_spin\0", "\0", "\0", "\0", 0), + ("run_pipe_test\0", "\0", "\0", "\0", 0), + ("sleep_simple\0", "\0", "\0", "\0", 0), + ("sleep\0", "\0", "\0", "\0", 0), + ("sleep_simple\0", "\0", "\0", "\0", 0), + ("sync_sem\0", "\0", "\0", "\0", 0), + ("test_condvar\0", "\0", "\0", "\0", 0), + ("threads_arg\0", "\0", "\0", "\0", 0), + ("threads\0", "\0", "\0", "\0", 0), + ("yield\0", "\0", "\0", "\0", 0), +]; + +static FAIL_TESTS: &[(&str, &str, &str, &str, i32)] = &[ + ("stack_overflow\0", "\0", "\0", "\0", -11), + ("race_adder_loop\0", "\0", "\0", "\0", -6), + ("priv_csr\0", "\0", "\0", "\0", -4), + ("priv_inst\0", "\0", "\0", "\0", -4), + ("store_fault\0", "\0", "\0", "\0", -11), + ("until_timeout\0", "\0", "\0", "\0", -6), + ("race_adder\0", "\0", "\0", "\0", -6), + ("huge_write_mt\0", "\0", "\0", "\0", -6), ]; use user_lib::{exec, fork, waitpid}; -#[no_mangle] -pub fn main() -> i32 { - for test in TESTS { - println!("Usertests: Running {}", test); +fn run_tests(tests: &[(&str, &str, &str, &str, i32)]) -> i32 { + let mut pass_num = 0; + let mut arr: [*const u8; 4] = [ + core::ptr::null::(), + core::ptr::null::(), + core::ptr::null::(), + core::ptr::null::(), + ]; + + for test in tests { + println!("Usertests: Running {}", test.0); + arr[0] = test.0.as_ptr(); + if test.1 != "\0" { + arr[1] = test.1.as_ptr(); + arr[2] = core::ptr::null::(); + arr[3] = core::ptr::null::(); + if test.2 != "\0" { + arr[2] = test.2.as_ptr(); + arr[3] = core::ptr::null::(); + if test.3 != "\0" { + arr[3] = test.3.as_ptr(); + } else { + arr[3] = core::ptr::null::(); + } + } else { + arr[2] = core::ptr::null::(); + arr[3] = core::ptr::null::(); + } + } else { + arr[1] = core::ptr::null::(); + arr[2] = core::ptr::null::(); + arr[3] = core::ptr::null::(); + } + let pid = fork(); if pid == 0 { - exec(*test, &[core::ptr::null::()]); + exec(test.0, &arr[..]); 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); + if exit_code == test.4 { + // summary apps with exit_code + pass_num = pass_num + 1; + } println!( "\x1b[32mUsertests: Test {} in Process {} exited with code {}\x1b[0m", - test, pid, exit_code + test.0, pid, exit_code ); } } - println!("Usertests passed!"); - 0 + pass_num +} + +#[no_mangle] +pub fn main() -> i32 { + let succ_num = run_tests(SUCC_TESTS); + let err_num = run_tests(FAIL_TESTS); + if succ_num == SUCC_TESTS.len() as i32 && err_num == FAIL_TESTS.len() as i32 { + println!( + "{} of sueecssed apps, {} of failed apps run correctly. \nUsertests passed!", + SUCC_TESTS.len(), + FAIL_TESTS.len() + ); + return 0; + } + if succ_num != SUCC_TESTS.len() as i32 { + println!( + "all successed app_num is {} , but only passed {}", + SUCC_TESTS.len(), + succ_num + ); + } + if err_num != FAIL_TESTS.len() as i32 { + println!( + "all failed app_num is {} , but only passed {}", + FAIL_TESTS.len(), + err_num + ); + } + println!(" Usertests failed!"); + return -1; } diff --git a/user/src/bin/usertests_simple.rs b/user/src/bin/usertests_simple.rs new file mode 100644 index 00000000..4fd49a4f --- /dev/null +++ b/user/src/bin/usertests_simple.rs @@ -0,0 +1,43 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +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", +]; + +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, &[core::ptr::null::()]); + 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!("Usertests passed!"); + 0 +}