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..0ddd1d3d --- /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/Cargo.toml b/os/Cargo.toml index c690db67..d3f3f5b7 100644 --- a/os/Cargo.toml +++ b/os/Cargo.toml @@ -2,7 +2,7 @@ name = "os" version = "0.1.0" authors = ["Yifan Wu "] -edition = "2018" +edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/os/src/boards/k210.rs b/os/src/boards/k210.rs index 4fea2d11..2f8168cb 100644 --- a/os/src/boards/k210.rs +++ b/os/src/boards/k210.rs @@ -1 +1,20 @@ pub const CLOCK_FREQ: usize = 403000000 / 62; + +pub const MMIO: &[(usize, usize)] = &[ + // we don't need clint in S priv when running + // we only need claim/complete for target0 after initializing + (0x0C00_0000, 0x3000), /* PLIC */ + (0x0C20_0000, 0x1000), /* PLIC */ + (0x3800_0000, 0x1000), /* UARTHS */ + (0x3800_1000, 0x1000), /* GPIOHS */ + (0x5020_0000, 0x1000), /* GPIO */ + (0x5024_0000, 0x1000), /* SPI_SLAVE */ + (0x502B_0000, 0x1000), /* FPIOA */ + (0x502D_0000, 0x1000), /* TIMER0 */ + (0x502E_0000, 0x1000), /* TIMER1 */ + (0x502F_0000, 0x1000), /* TIMER2 */ + (0x5044_0000, 0x1000), /* SYSCTL */ + (0x5200_0000, 0x1000), /* SPI0 */ + (0x5300_0000, 0x1000), /* SPI1 */ + (0x5400_0000, 0x1000), /* SPI2 */ +]; \ No newline at end of file diff --git a/os/src/boards/qemu.rs b/os/src/boards/qemu.rs index 98874fbf..df564eb8 100644 --- a/os/src/boards/qemu.rs +++ b/os/src/boards/qemu.rs @@ -1 +1,87 @@ +//! Constants used in rCore for qemu + pub const CLOCK_FREQ: usize = 12500000; + +pub const MMIO: &[(usize, usize)] = &[ + (0x0010_0000, 0x00_2000), // VIRT_TEST/RTC in virt machine +]; + +//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/config.rs b/os/src/config.rs index eeda71ce..e7dcee33 100644 --- a/os/src/config.rs +++ b/os/src/config.rs @@ -16,4 +16,4 @@ pub fn kernel_stack_position(app_id: usize) -> (usize, usize) { (bottom, top) } -pub use crate::board::CLOCK_FREQ; +pub use crate::board::{CLOCK_FREQ, MMIO}; diff --git a/os/src/mm/memory_set.rs b/os/src/mm/memory_set.rs index e8de984a..f9471543 100644 --- a/os/src/mm/memory_set.rs +++ b/os/src/mm/memory_set.rs @@ -4,7 +4,7 @@ use super::{frame_alloc, FrameTracker}; use super::{PTEFlags, PageTable, PageTableEntry}; use super::{PhysAddr, PhysPageNum, VirtAddr, VirtPageNum}; use super::{StepByOne, VPNRange}; -use crate::config::{MEMORY_END, PAGE_SIZE, TRAMPOLINE, TRAP_CONTEXT, USER_STACK_SIZE}; +use crate::config::{MEMORY_END, MMIO, PAGE_SIZE, TRAMPOLINE, TRAP_CONTEXT, USER_STACK_SIZE}; use crate::sync::UPSafeCell; use alloc::collections::BTreeMap; use alloc::sync::Arc; @@ -138,6 +138,18 @@ impl MemorySet { ), None, ); + println!("mapping memory-mapped registers"); + for pair in MMIO { + memory_set.push( + MapArea::new( + (*pair).0.into(), + ((*pair).0 + (*pair).1).into(), + MapType::Identical, + MapPermission::R | MapPermission::W, + ), + None, + ); + } memory_set } /// Include sections in elf and trampoline and TrapContext and user stack, diff --git a/os/src/sbi.rs b/os/src/sbi.rs index f696cf61..bd1a3e38 100644 --- a/os/src/sbi.rs +++ b/os/src/sbi.rs @@ -4,13 +4,15 @@ use core::arch::asm; const SBI_SET_TIMER: usize = 0; const SBI_CONSOLE_PUTCHAR: usize = 1; + +#[cfg(feature = "board_k210")] +const SBI_SHUTDOWN: usize = 8; // const SBI_CONSOLE_GETCHAR: usize = 2; // const SBI_CLEAR_IPI: usize = 3; // const SBI_SEND_IPI: usize = 4; // const SBI_REMOTE_FENCE_I: usize = 5; // const SBI_REMOTE_SFENCE_VMA: usize = 6; // const SBI_REMOTE_SFENCE_VMA_ASID: usize = 7; -const SBI_SHUTDOWN: usize = 8; #[inline(always)] /// general sbi call @@ -44,8 +46,16 @@ pub fn console_putchar(c: usize) { // sbi_call(SBI_CONSOLE_GETCHAR, 0, 0, 0) // } +#[cfg(feature = "board_qemu")] +use crate::board::QEMUExit; /// use sbi call to shutdown the kernel pub fn shutdown() -> ! { + #[cfg(feature = "board_k210")] sbi_call(SBI_SHUTDOWN, 0, 0, 0); + + #[cfg(feature = "board_qemu")] + crate::board::QEMU_EXIT_HANDLE.exit_failure(); + + #[cfg(feature = "board_k210")] panic!("It should shutdown!"); } diff --git a/os/src/task/mod.rs b/os/src/task/mod.rs index 0f548d0a..91695d40 100644 --- a/os/src/task/mod.rs +++ b/os/src/task/mod.rs @@ -143,6 +143,14 @@ impl TaskManager { } // go back to user mode } else { + println!("All applications completed!"); + + #[cfg(feature = "board_qemu")] + use crate::board::QEMUExit; + #[cfg(feature = "board_qemu")] + crate::board::QEMU_EXIT_HANDLE.exit_success(); + + #[cfg(feature = "board_k210")] panic!("All applications completed!"); } }