diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json deleted file mode 100644 index 2d7932f..0000000 --- a/.devcontainer/devcontainer.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "name": "rcore-tutorial-v3", - "build": { - "dockerfile": "../Dockerfile", - "args": { - "QEMU_VERSION": "7.0.0", - "DEBIAN_FRONTEND": "noninteractive", - "GDB_VERSION": "14.1" - } - }, - "postCreateCommand": "rustup show", - "customizations": { - "vscode": { - "extensions": [ - "rust-lang.rust-analyzer", - "ms-vscode.cpptools", - "tamasfe.even-better-toml" - ] - } - } -} diff --git a/.dockerignore b/.dockerignore index 8971c06..df3359d 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,2 +1 @@ -*/* -!rust-toolchain.toml \ No newline at end of file +*/* \ No newline at end of file diff --git a/.github/workflows/doc-and-test.yml b/.github/workflows/doc-and-test.yml index 0a05371..49d9eed 100644 --- a/.github/workflows/doc-and-test.yml +++ b/.github/workflows/doc-and-test.yml @@ -4,7 +4,7 @@ on: [push] env: CARGO_TERM_COLOR: always - rust_toolchain: nightly-2024-01-18 + rust_toolchain: nightly-2022-08-05 jobs: build-doc: diff --git a/.gitignore b/.gitignore index 67ee557..4391862 100644 --- a/.gitignore +++ b/.gitignore @@ -1,12 +1,9 @@ .*/* !.github/* !.vscode/settings.json -!.devcontainer/devcontainer.json - .idea -**/Cargo.lock -**/target/ - +Cargo.lock +target os/src/link_app.S os/src/linker.ld os/last-* diff --git a/Dockerfile b/Dockerfile index 30731a7..284db4c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,72 +1,85 @@ # syntax=docker/dockerfile:1 - -# Stage 1 Build QEMU -# - https://www.qemu.org/download/ -# - https://wiki.qemu.org/Hosts/Linux#Building_QEMU_for_Linux -# - https://wiki.qemu.org/Documentation/Platforms/RISCV - -FROM ubuntu:20.04 as build_qemu +# This Dockerfile is adapted from https://github.com/LearningOS/rCore-Tutorial-v3/blob/main/Dockerfile +# with the following major updates: +# - ubuntu 18.04 -> 20.04 +# - qemu 5.0.0 -> 7.0.0 +# - Extensive comments linking to relevant documentation +FROM ubuntu:20.04 ARG QEMU_VERSION=7.0.0 +ARG HOME=/root -RUN sed -i 's/archive.ubuntu.com/mirrors.tuna.tsinghua.edu.cn/g' /etc/apt/sources.list && \ - sed -i 's/security.ubuntu.com/mirrors.tuna.tsinghua.edu.cn/g' /etc/apt/sources.list && \ - apt-get update && \ - DEBIAN_FRONTEND=noninteractive apt-get install -y wget build-essential libglib2.0-dev libfdt-dev libpixman-1-dev zlib1g-dev ninja-build +# 0. Install general tools +ARG DEBIAN_FRONTEND=noninteractive +RUN apt-get update && \ + apt-get install -y \ + curl \ + git \ + python3 \ + wget +# 1. Set up QEMU RISC-V +# - https://learningos.github.io/rust-based-os-comp2022/0setup-devel-env.html#qemu +# - https://www.qemu.org/download/ +# - https://wiki.qemu.org/Documentation/Platforms/RISCV +# - https://risc-v-getting-started-guide.readthedocs.io/en/latest/linux-qemu.html + +# 1.1. Download source +WORKDIR ${HOME} RUN wget https://download.qemu.org/qemu-${QEMU_VERSION}.tar.xz && \ - tar xf qemu-${QEMU_VERSION}.tar.xz && \ - cd qemu-${QEMU_VERSION} && \ - ./configure --target-list=riscv64-softmmu,riscv64-linux-user && \ + tar xvJf qemu-${QEMU_VERSION}.tar.xz + +# 1.2. Install dependencies +# - https://risc-v-getting-started-guide.readthedocs.io/en/latest/linux-qemu.html#prerequisites +RUN apt-get install -y \ + autoconf automake autotools-dev curl libmpc-dev libmpfr-dev libgmp-dev \ + gawk build-essential bison flex texinfo gperf libtool patchutils bc \ + zlib1g-dev libexpat-dev git \ + ninja-build pkg-config libglib2.0-dev libpixman-1-dev libsdl2-dev + +# 1.3. Build and install from source +WORKDIR ${HOME}/qemu-${QEMU_VERSION} +RUN ./configure --target-list=riscv64-softmmu,riscv64-linux-user && \ make -j$(nproc) && \ make install -# Stage 2 Set Lab Environment -FROM ubuntu:20.04 as build +# 1.4. Clean up +WORKDIR ${HOME} +RUN rm -rf qemu-${QEMU_VERSION} qemu-${QEMU_VERSION}.tar.xz -WORKDIR /tmp +# 1.5. Sanity checking +RUN qemu-system-riscv64 --version && \ + qemu-riscv64 --version -# 2.0. Install general tools -RUN sed -i 's/archive.ubuntu.com/mirrors.tuna.tsinghua.edu.cn/g' /etc/apt/sources.list && \ - apt-get update && \ - DEBIAN_FRONTEND=noninteractive apt-get install -y jq curl git python3 wget build-essential \ - # qemu dependency - libglib2.0-0 libfdt1 libpixman-1-0 zlib1g \ - # gdb - gdb-multiarch - -# 2.1. Copy qemu -COPY --from=build_qemu /usr/local/bin/* /usr/local/bin - -# 2.2. Install Rust +# 2. Set up Rust +# - https://learningos.github.io/rust-based-os-comp2022/0setup-devel-env.html#qemu # - https://www.rust-lang.org/tools/install +# - https://github.com/rust-lang/docker-rust/blob/master/Dockerfile-debian.template + +# 2.1. Install ENV RUSTUP_HOME=/usr/local/rustup \ CARGO_HOME=/usr/local/cargo \ PATH=/usr/local/cargo/bin:$PATH \ - RUSTUP_DIST_SERVER=https://mirrors.ustc.edu.cn/rust-static \ - RUSTUP_UPDATE_ROOT=https://mirrors.ustc.edu.cn/rust-static/rustup -RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | \ - sh -s -- -y --no-modify-path --profile minimal --default-toolchain nightly + RUST_VERSION=nightly +RUN set -eux; \ + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs -o rustup-init; \ + chmod +x rustup-init; \ + ./rustup-init -y --no-modify-path --profile minimal --default-toolchain $RUST_VERSION; \ + rm rustup-init; \ + chmod -R a+w $RUSTUP_HOME $CARGO_HOME; -# 2.3. Build env for labs -# See os/Makefile `env:` for example. -# This avoids having to wait for these steps each time using a new container. -COPY rust-toolchain.toml rust-toolchain.toml -RUN rustup target add riscv64gc-unknown-none-elf && \ - cargo install toml-cli cargo-binutils && \ - RUST_VERSION=$(toml get -r rust-toolchain.toml toolchain.channel) && \ - Components=$(toml get -r rust-toolchain.toml toolchain.components | jq -r 'join(" ")') && \ - rustup install $RUST_VERSION && \ - rustup component add --toolchain $RUST_VERSION $Components - -# 2.4. Set GDB -RUN ln -s /usr/bin/gdb-multiarch /usr/bin/riscv64-unknown-elf-gdb - -# Stage 3 Sanity checking -FROM build as test -RUN qemu-system-riscv64 --version && \ - qemu-riscv64 --version && \ - rustup --version && \ +# 2.2. Sanity checking +RUN rustup --version && \ cargo --version && \ - rustc --version && \ - riscv64-unknown-elf-gdb --version \ No newline at end of file + rustc --version + +# 3. Build env for labs +# See os1/Makefile `env:` for example. +# This avoids having to wait for these steps each time using a new container. +RUN rustup target add riscv64gc-unknown-none-elf && \ + cargo install cargo-binutils --vers ~0.2 && \ + rustup component add rust-src && \ + rustup component add llvm-tools-preview + +# Ready to go +WORKDIR ${HOME} diff --git a/Makefile b/Makefile index 80fe9a1..ede5291 100644 --- a/Makefile +++ b/Makefile @@ -1,11 +1,11 @@ -DOCKER_TAG ?= rcore-tutorial-v3:latest +DOCKER_NAME ?= rcore-tutorial-v3 .PHONY: docker build_docker docker: - docker run --rm -it -v ${PWD}:/mnt -w /mnt --name rcore-tutorial-v3 ${DOCKER_TAG} bash + docker run --rm -it -v ${PWD}:/mnt -w /mnt ${DOCKER_NAME} bash build_docker: - docker build -t ${DOCKER_TAG} --target build . + docker build -t ${DOCKER_NAME} . fmt: cd os ; cargo fmt; cd .. diff --git a/os/.cargo/config.toml b/os/.cargo/config similarity index 100% rename from os/.cargo/config.toml rename to os/.cargo/config diff --git a/os/Makefile b/os/Makefile index a4c7967..21b9614 100644 --- a/os/Makefile +++ b/os/Makefile @@ -56,28 +56,25 @@ disasm-vim: kernel run: run-inner -QEMU_ARGS := -machine virt \ - -nographic \ - -bios $(BOOTLOADER) \ - -device loader,file=$(KERNEL_BIN),addr=$(KERNEL_ENTRY_PA) + -QEMU_NAME := qemu-system-riscv64 -qemu-version-check: - @sh scripts/qemu-ver-check.sh $(QEMU_NAME) +run-inner: build + @qemu-system-riscv64 \ + -machine virt \ + -nographic \ + -bios $(BOOTLOADER) \ + -device loader,file=$(KERNEL_BIN),addr=$(KERNEL_ENTRY_PA) -run-inner: qemu-version-check build - @qemu-system-riscv64 $(QEMU_ARGS) - -debug: qemu-version-check build +debug: build @tmux new-session -d \ - "qemu-system-riscv64 $(QEMU_ARGS) -s -S" && \ + "qemu-system-riscv64 -machine virt -nographic -bios $(BOOTLOADER) -device loader,file=$(KERNEL_BIN),addr=$(KERNEL_ENTRY_PA) -s -S" && \ tmux split-window -h "riscv64-unknown-elf-gdb -ex 'file $(KERNEL_ELF)' -ex 'set arch riscv:rv64' -ex 'target remote localhost:1234'" && \ tmux -2 attach-session -d -gdbserver: qemu-version-check build - @qemu-system-riscv64 $(QEMU_ARGS) -s -S +gdbserver: build + @qemu-system-riscv64 -machine virt -nographic -bios $(BOOTLOADER) -device loader,file=$(KERNEL_BIN),addr=$(KERNEL_ENTRY_PA) -s -S gdbclient: @riscv64-unknown-elf-gdb -ex 'file $(KERNEL_ELF)' -ex 'set arch riscv:rv64' -ex 'target remote localhost:1234' -.PHONY: build env kernel clean disasm disasm-vim run-inner gdbserver gdbclient qemu-version-check +.PHONY: build env kernel clean disasm disasm-vim run-inner gdbserver gdbclient diff --git a/os/scripts/qemu-ver-check.sh b/os/scripts/qemu-ver-check.sh deleted file mode 100644 index 8c20456..0000000 --- a/os/scripts/qemu-ver-check.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/sh - -# Argument1: The filename of qemu executable, e.g. qemu-system-riscv64 -QEMU_PATH=$(which $1) -RET=$? -MINIMUM_MAJOR_VERSION=7 -RED='\033[0;31m' -GREEN='\033[0;32m' -NC='\033[0m' -if [ $RET != 0 ] -then - echo "$1 not found" - exit 1 -else - QEMU_VERSION=$($1 --version|head -n 1|awk '{print $4}') - MAJOR_VERSION=$(echo $QEMU_VERSION|cut -c1-1) - if [ $MAJOR_VERSION -lt $MINIMUM_MAJOR_VERSION ] - then - echo "${RED}Error: Required major version of QEMU is ${MINIMUM_MAJOR_VERSION}, " \ - "but current is ${QEMU_VERSION}.${NC}" - exit 1 - else - echo "${GREEN}QEMU version is ${QEMU_VERSION}(>=${MINIMUM_MAJOR_VERSION}), OK!${NC}" - exit 0 - fi -fi diff --git a/os/src/config.rs b/os/src/config.rs index 9d019a7..ff7ffbe 100644 --- a/os/src/config.rs +++ b/os/src/config.rs @@ -5,7 +5,6 @@ pub const KERNEL_STACK_SIZE: usize = 4096 * 2; pub const MAX_APP_NUM: usize = 4; pub const APP_BASE_ADDRESS: usize = 0x80400000; pub const APP_SIZE_LIMIT: usize = 0x20000; -pub const MAX_SYSCALL_NUM: usize = 500; /* #[cfg(feature = "board_k210")] diff --git a/os/src/loader.rs b/os/src/loader.rs index 8c711f1..af9e508 100644 --- a/os/src/loader.rs +++ b/os/src/loader.rs @@ -70,6 +70,10 @@ pub fn load_apps() { let num_app_ptr = _num_app as usize as *const usize; let num_app = get_num_app(); let app_start = unsafe { core::slice::from_raw_parts(num_app_ptr.add(1), num_app + 1) }; + // clear i-cache first + unsafe { + asm!("fence.i"); + } // load apps for i in 0..num_app { let base_i = get_base_i(i); @@ -83,15 +87,6 @@ pub fn load_apps() { let dst = unsafe { core::slice::from_raw_parts_mut(base_i as *mut u8, src.len()) }; dst.copy_from_slice(src); } - // Memory fence about fetching the instruction memory - // It is guaranteed that a subsequent instruction fetch must - // observes all previous writes to the instruction memory. - // Therefore, fence.i must be executed after we have loaded - // the code of the next app into the instruction memory. - // See also: riscv non-priv spec chapter 3, 'Zifencei' extension. - unsafe { - asm!("fence.i"); - } } /// get app info with entry and sp and save `TrapContext` in kernel stack diff --git a/os/src/syscall/mod.rs b/os/src/syscall/mod.rs index 7adbc78..ee52f5b 100644 --- a/os/src/syscall/mod.rs +++ b/os/src/syscall/mod.rs @@ -14,7 +14,6 @@ const SYSCALL_WRITE: usize = 64; const SYSCALL_EXIT: usize = 93; const SYSCALL_YIELD: usize = 124; const SYSCALL_GET_TIME: usize = 169; -const SYSCALL_TASK_INFO: usize = 410; mod fs; mod process; @@ -22,17 +21,13 @@ mod process; use fs::*; use process::*; -use crate::task::TASK_MANAGER; - /// handle syscall exception with `syscall_id` and other arguments pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize { - TASK_MANAGER.mark_syscall(syscall_id); match syscall_id { SYSCALL_WRITE => sys_write(args[0], args[1] as *const u8, args[2]), SYSCALL_EXIT => sys_exit(args[0] as i32), SYSCALL_YIELD => sys_yield(), SYSCALL_GET_TIME => sys_get_time(), - SYSCALL_TASK_INFO => sys_task_info(args[0] as *mut TaskInfo), _ => panic!("Unsupported syscall_id: {}", syscall_id), } } diff --git a/os/src/syscall/process.rs b/os/src/syscall/process.rs index 7d6d102..bdf5c8b 100644 --- a/os/src/syscall/process.rs +++ b/os/src/syscall/process.rs @@ -1,20 +1,6 @@ //! Process management syscalls -use log::trace; - -use crate::task::{exit_current_and_run_next, suspend_current_and_run_next, TaskStatus, TASK_MANAGER}; -use crate::timer::{get_time, get_time_ms}; -use crate::config::MAX_SYSCALL_NUM; - -/// Task information -#[allow(dead_code)] -pub struct TaskInfo { - /// Task status in it's life cycle - status: TaskStatus, - /// The numbers of syscall called by task - syscall_times: [u32; MAX_SYSCALL_NUM], - /// Total running time of task - time: usize, -} +use crate::task::{exit_current_and_run_next, suspend_current_and_run_next}; +use crate::timer::get_time_ms; /// task exits and submit an exit code pub fn sys_exit(exit_code: i32) -> ! { @@ -33,14 +19,3 @@ pub fn sys_yield() -> isize { pub fn sys_get_time() -> isize { get_time_ms() as isize } - -/// YOUR JOB: Finish sys_task_info to pass testcases -pub fn sys_task_info(ti: *mut TaskInfo) -> isize { - unsafe { - (*ti).status = TASK_MANAGER.get_current_status(); - (*ti).time = get_time(); - (*ti).syscall_times = TASK_MANAGER.get_current_syscall_times() - } - trace!("kernel: sys_task_info"); - 0 -} diff --git a/os/src/task/mod.rs b/os/src/task/mod.rs index 0e15858..8696db4 100644 --- a/os/src/task/mod.rs +++ b/os/src/task/mod.rs @@ -15,13 +15,13 @@ mod switch; #[allow(clippy::module_inception)] mod task; -use crate::config::{MAX_APP_NUM, MAX_SYSCALL_NUM}; +use crate::config::MAX_APP_NUM; use crate::loader::{get_num_app, init_app_cx}; use crate::sbi::shutdown; use crate::sync::UPSafeCell; use lazy_static::*; use switch::__switch; -pub use task::{TaskControlBlock, TaskStatus}; +use task::{TaskControlBlock, TaskStatus}; pub use context::TaskContext; @@ -56,7 +56,6 @@ lazy_static! { let mut tasks = [TaskControlBlock { task_cx: TaskContext::zero_init(), task_status: TaskStatus::UnInit, - syscall_times: [0; MAX_SYSCALL_NUM] }; MAX_APP_NUM]; for (i, task) in tasks.iter_mut().enumerate() { task.task_cx = TaskContext::goto_restore(init_app_cx(i)); @@ -139,36 +138,6 @@ impl TaskManager { shutdown(false); } } - - /// get current task id - pub fn get_current_id(&self) -> usize { - let inner = self.inner.exclusive_access(); - inner.current_task - } - - /// get current task status - pub fn get_current_status(&self) -> TaskStatus { - let inner = self.inner.exclusive_access(); - let current = inner.current_task; - inner.tasks[current].task_status - } - - /// get current task syscall times - pub fn get_current_syscall_times(&self) -> [u32; MAX_SYSCALL_NUM] { - let inner = self.inner.exclusive_access(); - let current = inner.current_task; - return inner.tasks[current].syscall_times.clone(); - } - - /// record syscall - pub fn mark_syscall(&self, syscall_id: usize) { - if syscall_id >= MAX_SYSCALL_NUM { - return; - } - let mut inner = self.inner.exclusive_access(); - let current = inner.current_task; - inner.tasks[current].syscall_times[syscall_id] += 1; - } } /// run first task diff --git a/os/src/task/task.rs b/os/src/task/task.rs index 1826ac8..d72efc7 100644 --- a/os/src/task/task.rs +++ b/os/src/task/task.rs @@ -1,29 +1,17 @@ //! Types related to task management -use crate::config::MAX_SYSCALL_NUM; - use super::TaskContext; -/// The task control block (TCB) of a task. #[derive(Copy, Clone)] pub struct TaskControlBlock { - /// The task status in it's lifecycle pub task_status: TaskStatus, - /// The task context pub task_cx: TaskContext, - /// The numbers of syscall called by task - pub syscall_times: [u32; MAX_SYSCALL_NUM], } -/// The status of a task #[derive(Copy, Clone, PartialEq)] pub enum TaskStatus { - /// uninitialized UnInit, - /// ready to run Ready, - /// running Running, - /// exited Exited, } diff --git a/rust-toolchain.toml b/rust-toolchain.toml index c65d258..553747b 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,6 +1,5 @@ [toolchain] profile = "minimal" # use the nightly version of the last stable toolchain, see -channel = "nightly-2024-05-01" -components = ["rust-src", "llvm-tools", "rustfmt", "clippy"] -targets = ["riscv64gc-unknown-none-elf"] +channel = "nightly-2022-08-05" +components = ["rust-src", "llvm-tools-preview", "rustfmt", "clippy"] diff --git a/user/.cargo/config.toml b/user/.cargo/config similarity index 100% rename from user/.cargo/config.toml rename to user/.cargo/config diff --git a/user/src/bin/00power_3.rs b/user/src/bin/00power_3.rs index 963e7c9..1a04dc7 100644 --- a/user/src/bin/00power_3.rs +++ b/user/src/bin/00power_3.rs @@ -1,16 +1,28 @@ #![no_std] #![no_main] +#[macro_use] extern crate user_lib; -use user_lib::{ - println, task_info, TaskInfo, -}; +const LEN: usize = 100; #[no_mangle] -pub fn main() -> usize { - let info = TaskInfo::new(); - assert_eq!(0, task_info(&info)); - println!("task_info {:?}", info); +fn main() -> i32 { + let p = 3u64; + let m = 998244353u64; + let iter: usize = 200000; + let mut s = [0u64; LEN]; + let mut cur = 0usize; + s[cur] = 1; + for i in 1..=iter { + let next = if cur + 1 == LEN { 0 } else { cur + 1 }; + s[next] = s[cur] * p % m; + cur = next; + if i % 10000 == 0 { + println!("power_3 [{}/{}]", i, iter); + } + } + println!("{}^{} = {}(MOD {})", p, iter, s[cur], m); + println!("Test power_3 OK!"); 0 } diff --git a/user/src/bin/04taskinfo.rs b/user/src/bin/04taskinfo.rs deleted file mode 100644 index 963e7c9..0000000 --- a/user/src/bin/04taskinfo.rs +++ /dev/null @@ -1,16 +0,0 @@ -#![no_std] -#![no_main] - -extern crate user_lib; - -use user_lib::{ - println, task_info, TaskInfo, -}; - -#[no_mangle] -pub fn main() -> usize { - let info = TaskInfo::new(); - assert_eq!(0, task_info(&info)); - println!("task_info {:?}", info); - 0 -} diff --git a/user/src/lib.rs b/user/src/lib.rs index 5dc26ae..1491afc 100644 --- a/user/src/lib.rs +++ b/user/src/lib.rs @@ -45,35 +45,3 @@ pub fn yield_() -> isize { pub fn get_time() -> isize { sys_get_time() } - - -#[derive(Copy, Clone, PartialEq, Debug)] -pub enum TaskStatus { - UnInit, - Ready, - Running, - Exited, -} - -const MAX_SYSCALL_NUM: usize = 500; - -#[derive(Debug)] -pub struct TaskInfo { - pub status: TaskStatus, - pub syscall_times: [u32; MAX_SYSCALL_NUM], - pub time: usize, -} - -impl TaskInfo { - pub fn new() -> Self { - TaskInfo { - status: TaskStatus::UnInit, - syscall_times: [0; MAX_SYSCALL_NUM], - time: 0, - } - } -} - -pub fn task_info(info: &TaskInfo) -> isize { - sys_task_info(info) -} diff --git a/user/src/syscall.rs b/user/src/syscall.rs index 45ee63f..b009569 100644 --- a/user/src/syscall.rs +++ b/user/src/syscall.rs @@ -1,12 +1,9 @@ use core::arch::asm; -use crate::TaskInfo; - const SYSCALL_WRITE: usize = 64; const SYSCALL_EXIT: usize = 93; const SYSCALL_YIELD: usize = 124; const SYSCALL_GET_TIME: usize = 169; -pub const SYSCALL_TASK_INFO: usize = 410; fn syscall(id: usize, args: [usize; 3]) -> isize { let mut ret: isize; @@ -37,7 +34,3 @@ pub fn sys_yield() -> isize { pub fn sys_get_time() -> isize { syscall(SYSCALL_GET_TIME, [0, 0, 0]) } - -pub fn sys_task_info(info: &TaskInfo) -> isize { - syscall(SYSCALL_TASK_INFO, [info as *const _ as usize, 0, 0]) -} \ No newline at end of file