From 62931b3663571f21eb96e839c3d7cef116cd375f Mon Sep 17 00:00:00 2001 From: Yu Chen Date: Thu, 23 Jun 2022 22:41:20 +0800 Subject: [PATCH 01/68] update README --- README.md | 40 +++++++++++++++++----------------------- 1 file changed, 17 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index c65d14c..767cb14 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # 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) @@ -8,7 +8,7 @@ If you don't know Rust Language and try to learn it, please visit [Rust Learnin 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 @@ -44,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 @@ -52,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) @@ -64,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: @@ -79,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 ``` @@ -251,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: @@ -279,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 From 3337b81d8916c8926b939c5c8d9091f6267d5313 Mon Sep 17 00:00:00 2001 From: Yu Chen Date: Thu, 23 Jun 2022 22:41:51 +0800 Subject: [PATCH 02/68] update README --- README.md | 40 +++++++++++++++++----------------------- 1 file changed, 17 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index c65d14c..767cb14 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # 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) @@ -8,7 +8,7 @@ If you don't know Rust Language and try to learn it, please visit [Rust Learnin 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 @@ -44,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 @@ -52,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) @@ -64,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: @@ -79,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 ``` @@ -251,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: @@ -279,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 From 637cb41d46f0875443bcd35dff2aef1dc015cbea Mon Sep 17 00:00:00 2001 From: Yu Chen Date: Thu, 14 Jul 2022 09:37:06 +0800 Subject: [PATCH 03/68] support rust-analyzer for board_qemu features --- .vscode/settings.json | 7 +++++-- easy-fs-fuse/Cargo.toml | 6 +++++- easy-fs/Cargo.toml | 4 ++++ user/Cargo.toml | 4 ++++ 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 11de111..bf81ab5 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -6,5 +6,8 @@ "rust.all_targets": false, // For Rust Analyzer plugin users: "rust-analyzer.cargo.target": "riscv64gc-unknown-none-elf", - "rust-analyzer.checkOnSave.allTargets": false -} + "rust-analyzer.checkOnSave.allTargets": false, + "rust-analyzer.cargo.features": [ + "board_qemu" + ] +} \ No newline at end of file diff --git a/easy-fs-fuse/Cargo.toml b/easy-fs-fuse/Cargo.toml index ee0ef97..0527e9b 100644 --- a/easy-fs-fuse/Cargo.toml +++ b/easy-fs-fuse/Cargo.toml @@ -9,4 +9,8 @@ edition = "2018" [dependencies] clap = "2.33.3" easy-fs = { path = "../easy-fs" } -rand = "0.8.0" \ No newline at end of file +rand = "0.8.0" + +[features] +board_qemu = [] +board_k210 = [] \ No newline at end of file diff --git a/easy-fs/Cargo.toml b/easy-fs/Cargo.toml index c969077..7a2f38e 100644 --- a/easy-fs/Cargo.toml +++ b/easy-fs/Cargo.toml @@ -12,3 +12,7 @@ lazy_static = { version = "1.4.0", features = ["spin_no_std"] } [profile.release] debug = true + +[features] +board_qemu = [] +board_k210 = [] \ No newline at end of file diff --git a/user/Cargo.toml b/user/Cargo.toml index 542a624..18634c3 100644 --- a/user/Cargo.toml +++ b/user/Cargo.toml @@ -13,3 +13,7 @@ riscv = { git = "https://github.com/rcore-os/riscv", features = ["inline-asm"] } [profile.release] debug = true + +[features] +board_qemu = [] +board_k210 = [] \ No newline at end of file From 6d435500f482543d26b5960429b7235f9323ecc1 Mon Sep 17 00:00:00 2001 From: Yu Chen Date: Thu, 14 Jul 2022 09:44:20 +0800 Subject: [PATCH 04/68] update .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index f411b22..01335bf 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ os/last-* os/.gdb_history tools/ pushall.sh +.vscode/*.log \ No newline at end of file From 836849e09ba4f01ef780da502a1fbf58617d3f49 Mon Sep 17 00:00:00 2001 From: Yu Chen Date: Mon, 18 Jul 2022 11:23:20 +0800 Subject: [PATCH 05/68] update Dockerfile: ubuntu 18.04-->20.04, QEMU-5.0-->7.0 --- Dockerfile | 117 ++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 81 insertions(+), 36 deletions(-) diff --git a/Dockerfile b/Dockerfile index ac784bc..284db4c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,40 +1,85 @@ -FROM ubuntu:18.04 -LABEL maintainer="dinghao188" \ - version="1.1" \ - description="ubuntu 18.04 with tools for tsinghua's rCore-Tutorial-V3" +# syntax=docker/dockerfile:1 +# 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 -#install some deps -RUN set -x \ - && apt-get update \ - && apt-get install -y curl wget autoconf automake autotools-dev curl libmpc-dev libmpfr-dev libgmp-dev \ - gawk build-essential bison flex texinfo gperf libtool patchutils bc xz-utils \ - zlib1g-dev libexpat-dev pkg-config libglib2.0-dev libpixman-1-dev git tmux python3 +ARG QEMU_VERSION=7.0.0 +ARG HOME=/root -#install rust and qemu -RUN set -x; \ - RUSTUP='/root/rustup.sh' \ - && cd $HOME \ - #install rust - && curl https://sh.rustup.rs -sSf > $RUSTUP && chmod +x $RUSTUP \ - && $RUSTUP -y --default-toolchain nightly --profile minimal \ +# 0. Install general tools +ARG DEBIAN_FRONTEND=noninteractive +RUN apt-get update && \ + apt-get install -y \ + curl \ + git \ + python3 \ + wget - #compile qemu - && wget https://ftp.osuosl.org/pub/blfs/conglomeration/qemu/qemu-5.0.0.tar.xz \ - && tar xvJf qemu-5.0.0.tar.xz \ - && cd qemu-5.0.0 \ - && ./configure --target-list=riscv64-softmmu,riscv64-linux-user \ - && make -j$(nproc) install \ - && cd $HOME && rm -rf qemu-5.0.0 qemu-5.0.0.tar.xz +# 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 -#for chinese network -RUN set -x; \ - APT_CONF='/etc/apt/sources.list'; \ - CARGO_CONF='/root/.cargo/config'; \ - BASHRC='/root/.bashrc' \ - && echo 'export RUSTUP_DIST_SERVER=https://mirrors.ustc.edu.cn/rust-static' >> $BASHRC \ - && echo 'export RUSTUP_UPDATE_ROOT=https://mirrors.ustc.edu.cn/rust-static/rustup' >> $BASHRC \ - && touch $CARGO_CONF \ - && echo '[source.crates-io]' > $CARGO_CONF \ - && echo "replace-with = 'ustc'" >> $CARGO_CONF \ - && echo '[source.ustc]' >> $CARGO_CONF \ - && echo 'registry = "git://mirrors.ustc.edu.cn/crates.io-index"' >> $CARGO_CONF \ No newline at end of file +# 1.1. Download source +WORKDIR ${HOME} +RUN wget https://download.qemu.org/qemu-${QEMU_VERSION}.tar.xz && \ + 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 + +# 1.4. Clean up +WORKDIR ${HOME} +RUN rm -rf qemu-${QEMU_VERSION} qemu-${QEMU_VERSION}.tar.xz + +# 1.5. Sanity checking +RUN qemu-system-riscv64 --version && \ + qemu-riscv64 --version + +# 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 \ + 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.2. Sanity checking +RUN rustup --version && \ + cargo --version && \ + 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} From 25f4e37168262e7196c85db7429bb398f177338b Mon Sep 17 00:00:00 2001 From: Yu Chen Date: Mon, 25 Jul 2022 11:47:07 +0800 Subject: [PATCH 06/68] udpate rust-toolchain: nightly-2022-07-20, cargo-utils 0.36 --- .github/workflows/doc-and-test.yml | 4 ++-- os/Makefile | 2 +- rust-toolchain | 1 - rust-toolchain.toml | 4 ++++ 4 files changed, 7 insertions(+), 4 deletions(-) delete mode 100644 rust-toolchain create mode 100644 rust-toolchain.toml diff --git a/.github/workflows/doc-and-test.yml b/.github/workflows/doc-and-test.yml index 98fdc66..1e6f0b1 100644 --- a/.github/workflows/doc-and-test.yml +++ b/.github/workflows/doc-and-test.yml @@ -13,7 +13,7 @@ jobs: - uses: actions-rs/toolchain@v1 with: profile: minimal - toolchain: nightly-2022-04-11 + toolchain: nightly-2022-07-20 components: rust-src, llvm-tools-preview target: riscv64gc-unknown-none-elf - name: Build doc @@ -32,7 +32,7 @@ jobs: - uses: actions-rs/toolchain@v1 with: profile: minimal - toolchain: nightly-2022-04-11 + toolchain: nightly-2022-07-20 components: rust-src, llvm-tools-preview target: riscv64gc-unknown-none-elf - uses: actions-rs/install@v0.1 diff --git a/os/Makefile b/os/Makefile index b38c23a..0658a5e 100644 --- a/os/Makefile +++ b/os/Makefile @@ -51,7 +51,7 @@ endif env: (rustup target list | grep "riscv64gc-unknown-none-elf (installed)") || rustup target add $(TARGET) - cargo install cargo-binutils --vers =0.3.3 + cargo install cargo-binutils rustup component add rust-src rustup component add llvm-tools-preview diff --git a/rust-toolchain b/rust-toolchain deleted file mode 100644 index abcacd9..0000000 --- a/rust-toolchain +++ /dev/null @@ -1 +0,0 @@ -nightly-2022-04-11 diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..c56a59e --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,4 @@ +[toolchain] +profile = "minimal" +channel = "nightly-2022-07-20" +components = ["rust-src", "llvm-tools-preview", "rustfmt", "clippy"] From 25a398adc27017216b0f4ce8979cb950b4eb804b Mon Sep 17 00:00:00 2001 From: Yifan Wu Date: Fri, 2 Sep 2022 02:54:55 -0700 Subject: [PATCH 07/68] Merged PR #87 --- os/src/drivers/block/virtio_blk.rs | 51 ++--------------------------- os/src/drivers/bus/mod.rs | 1 + os/src/drivers/bus/virtio.rs | 52 ++++++++++++++++++++++++++++++ os/src/drivers/gpu/mod.rs | 5 +-- os/src/drivers/input/mod.rs | 5 +-- os/src/drivers/mod.rs | 4 +++ 6 files changed, 66 insertions(+), 52 deletions(-) create mode 100644 os/src/drivers/bus/mod.rs create mode 100644 os/src/drivers/bus/virtio.rs diff --git a/os/src/drivers/block/virtio_blk.rs b/os/src/drivers/block/virtio_blk.rs index ff460d7..2d853e0 100644 --- a/os/src/drivers/block/virtio_blk.rs +++ b/os/src/drivers/block/virtio_blk.rs @@ -1,29 +1,19 @@ use super::BlockDevice; -use crate::mm::{ - frame_alloc, frame_dealloc, kernel_token, FrameTracker, PageTable, PhysAddr, PhysPageNum, - StepByOne, VirtAddr, -}; use crate::sync::{Condvar, UPIntrFreeCell}; use crate::task::schedule; use crate::DEV_NON_BLOCKING_ACCESS; use alloc::collections::BTreeMap; -use alloc::vec::Vec; -use lazy_static::*; use virtio_drivers::{BlkResp, RespStatus, VirtIOBlk, VirtIOHeader}; +use crate::drivers::bus::virtio::VirtioHal; #[allow(unused)] const VIRTIO0: usize = 0x10008000; pub struct VirtIOBlock { - virtio_blk: UPIntrFreeCell>, + virtio_blk: UPIntrFreeCell>, condvars: BTreeMap, } -lazy_static! { - static ref QUEUE_FRAMES: UPIntrFreeCell> = - unsafe { UPIntrFreeCell::new(Vec::new()) }; -} - impl BlockDevice for VirtIOBlock { fn read_block(&self, block_id: usize, buf: &mut [u8]) { let nb = *DEV_NON_BLOCKING_ACCESS.exclusive_access(); @@ -79,7 +69,7 @@ impl BlockDevice for VirtIOBlock { impl VirtIOBlock { pub fn new() -> Self { let virtio_blk = unsafe { - UPIntrFreeCell::new(VirtIOBlk::new(&mut *(VIRTIO0 as *mut VirtIOHeader)).unwrap()) + UPIntrFreeCell::new(VirtIOBlk::::new(&mut *(VIRTIO0 as *mut VirtIOHeader)).unwrap()) }; let mut condvars = BTreeMap::new(); let channels = virtio_blk.exclusive_access().virt_queue_size(); @@ -94,38 +84,3 @@ impl VirtIOBlock { } } -#[no_mangle] -pub extern "C" fn virtio_dma_alloc(pages: usize) -> PhysAddr { - let mut ppn_base = PhysPageNum(0); - for i in 0..pages { - let frame = frame_alloc().unwrap(); - if i == 0 { - ppn_base = frame.ppn; - } - assert_eq!(frame.ppn.0, ppn_base.0 + i); - QUEUE_FRAMES.exclusive_access().push(frame); - } - ppn_base.into() -} - -#[no_mangle] -pub extern "C" fn virtio_dma_dealloc(pa: PhysAddr, pages: usize) -> i32 { - let mut ppn_base: PhysPageNum = pa.into(); - for _ in 0..pages { - frame_dealloc(ppn_base); - ppn_base.step(); - } - 0 -} - -#[no_mangle] -pub extern "C" fn virtio_phys_to_virt(paddr: PhysAddr) -> VirtAddr { - VirtAddr(paddr.0) -} - -#[no_mangle] -pub extern "C" fn virtio_virt_to_phys(vaddr: VirtAddr) -> PhysAddr { - PageTable::from_token(kernel_token()) - .translate_va(vaddr) - .unwrap() -} diff --git a/os/src/drivers/bus/mod.rs b/os/src/drivers/bus/mod.rs new file mode 100644 index 0000000..ab8f38f --- /dev/null +++ b/os/src/drivers/bus/mod.rs @@ -0,0 +1 @@ +pub mod virtio; \ No newline at end of file diff --git a/os/src/drivers/bus/virtio.rs b/os/src/drivers/bus/virtio.rs new file mode 100644 index 0000000..fe7bc12 --- /dev/null +++ b/os/src/drivers/bus/virtio.rs @@ -0,0 +1,52 @@ +use alloc::vec::Vec; +use crate::mm::{ + frame_alloc, frame_dealloc, kernel_token, FrameTracker, PageTable, PhysAddr, PhysPageNum, + StepByOne, VirtAddr, +}; +use crate::sync::UPIntrFreeCell; +use lazy_static::*; +use virtio_drivers::Hal; + +lazy_static! { + static ref QUEUE_FRAMES: UPIntrFreeCell> = + unsafe { UPIntrFreeCell::new(Vec::new()) }; +} + +pub struct VirtioHal; + +impl Hal for VirtioHal { + fn dma_alloc(pages: usize) -> usize { + let mut ppn_base = PhysPageNum(0); + for i in 0..pages { + let frame = frame_alloc().unwrap(); + if i == 0 { + ppn_base = frame.ppn; + } + assert_eq!(frame.ppn.0, ppn_base.0 + i); + QUEUE_FRAMES.exclusive_access().push(frame); + } + let pa: PhysAddr = ppn_base.into(); + pa.0 + } + + fn dma_dealloc(pa: usize, pages: usize) -> i32 { + let pa = PhysAddr::from(pa); + let mut ppn_base: PhysPageNum = pa.into(); + for _ in 0..pages { + frame_dealloc(ppn_base); + ppn_base.step(); + } + 0 + } + + fn phys_to_virt(addr: usize) -> usize { + addr + } + + fn virt_to_phys(vaddr: usize) -> usize { + PageTable::from_token(kernel_token()) + .translate_va(VirtAddr::from(vaddr)) + .unwrap() + .0 + } +} \ No newline at end of file diff --git a/os/src/drivers/gpu/mod.rs b/os/src/drivers/gpu/mod.rs index 2dc80d4..2902821 100644 --- a/os/src/drivers/gpu/mod.rs +++ b/os/src/drivers/gpu/mod.rs @@ -4,6 +4,7 @@ use core::any::Any; use embedded_graphics::pixelcolor::Rgb888; use tinybmp::Bmp; use virtio_drivers::{VirtIOGpu, VirtIOHeader}; +use crate::drivers::bus::virtio::VirtioHal; const VIRTIO7: usize = 0x10007000; pub trait GPUDevice: Send + Sync + Any { fn update_cursor(&self); @@ -16,14 +17,14 @@ lazy_static::lazy_static!( ); pub struct VirtIOGPU { - gpu: UPIntrFreeCell>, + gpu: UPIntrFreeCell>, fb: &'static [u8], } static BMP_DATA: &[u8] = include_bytes!("../../assert/mouse.bmp"); impl VirtIOGPU { pub fn new() -> Self { unsafe { - let mut virtio = VirtIOGpu::new(&mut *(VIRTIO7 as *mut VirtIOHeader)).unwrap(); + let mut virtio = VirtIOGpu::::new(&mut *(VIRTIO7 as *mut VirtIOHeader)).unwrap(); let fbuffer = virtio.setup_framebuffer().unwrap(); let len = fbuffer.len(); diff --git a/os/src/drivers/input/mod.rs b/os/src/drivers/input/mod.rs index 0acb034..1da66a6 100644 --- a/os/src/drivers/input/mod.rs +++ b/os/src/drivers/input/mod.rs @@ -11,6 +11,7 @@ use embedded_graphics::{ }; use k210_hal::cache::Uncache; use virtio_drivers::{VirtIOHeader, VirtIOInput}; +use crate::drivers::bus::virtio::VirtioHal; use virtio_input_decoder::{Decoder, Key, KeyType}; use super::GPU_DEVICE; @@ -18,7 +19,7 @@ use super::GPU_DEVICE; const VIRTIO5: usize = 0x10005000; const VIRTIO6: usize = 0x10006000; -struct VirtIOINPUT(UPIntrFreeCell>); +struct VirtIOINPUT(UPIntrFreeCell>); pub trait INPUTDevice: Send + Sync + Any { fn handle_irq(&self); @@ -32,7 +33,7 @@ lazy_static::lazy_static!( impl VirtIOINPUT { pub fn new(addr: usize) -> Self { Self(unsafe { - UPIntrFreeCell::new(VirtIOInput::new(&mut *(addr as *mut VirtIOHeader)).unwrap()) + UPIntrFreeCell::new(VirtIOInput::::new(&mut *(addr as *mut VirtIOHeader)).unwrap()) }) } } diff --git a/os/src/drivers/mod.rs b/os/src/drivers/mod.rs index 4ecf8a9..cdd3757 100644 --- a/os/src/drivers/mod.rs +++ b/os/src/drivers/mod.rs @@ -4,6 +4,8 @@ pub mod chardev; pub mod gpu; #[cfg(feature = "board_qemu")] pub mod input; +#[cfg(feature = "board_qemu")] +pub mod bus; pub mod plic; pub use block::BLOCK_DEVICE; #[cfg(feature = "board_qemu")] @@ -12,3 +14,5 @@ pub use chardev::UART; pub use gpu::*; #[cfg(feature = "board_qemu")] pub use input::*; +#[cfg(feature = "board_qemu")] +pub use bus::*; From 9fee963ade1762a5213b8801d0af5bd44d9154d2 Mon Sep 17 00:00:00 2001 From: Yifan Wu Date: Mon, 5 Sep 2022 02:33:37 -0700 Subject: [PATCH 08/68] Lock virtio-drivers version at 4ee80e5 --- os/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/os/Cargo.toml b/os/Cargo.toml index 4ebae8a..915e5f9 100644 --- a/os/Cargo.toml +++ b/os/Cargo.toml @@ -13,7 +13,7 @@ buddy_system_allocator = "0.6" bitflags = "1.2.1" xmas-elf = "0.7.0" volatile = "0.3" -virtio-drivers = { git = "https://github.com/rcore-os/virtio-drivers" } +virtio-drivers = { git = "https://github.com/rcore-os/virtio-drivers", rev = "4ee80e5" } k210-pac = { git = "https://github.com/wyfcyx/k210-pac" } k210-hal = { git = "https://github.com/wyfcyx/k210-hal" } k210-soc = { git = "https://github.com/wyfcyx/k210-soc" } From 21287b2f8f4161e1cbdfa6b47a20773ed3ccb7a3 Mon Sep 17 00:00:00 2001 From: Yifan Wu Date: Sat, 1 Oct 2022 22:20:43 +0800 Subject: [PATCH 09/68] Update Docker --- Makefile | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index a657cd9..bd267f4 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,12 @@ -DOCKER_NAME ?= dinghao188/rcore-tutorial +DOCKER_NAME ?= rcore-tutorial-v3 .PHONY: docker build_docker - + docker: - docker run --rm -it --mount type=bind,source=$(shell pwd),destination=/mnt ${DOCKER_NAME} + docker run --rm -it -v ${PWD}:/mnt -w /mnt ${DOCKER_NAME} bash build_docker: docker build -t ${DOCKER_NAME} . + fmt: - cd easy-fs; cargo fmt; cd ../easy-fs-fuse cargo fmt; cd ../os ; cargo fmt; cd ../user; cargo fmt; cd .. \ No newline at end of file + cd easy-fs; cargo fmt; cd ../easy-fs-fuse cargo fmt; cd ../os ; cargo fmt; cd ../user; cargo fmt; cd .. + From 6bcb91a7d097e39d68e4ccec3bc533a66a4b35ca Mon Sep 17 00:00:00 2001 From: Yifan Wu Date: Sun, 9 Oct 2022 05:41:25 +0800 Subject: [PATCH 10/68] Bump rustsbi-qemu to 701e891 --- bootloader/rustsbi-qemu.bin | Bin 43568 -> 38920 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/bootloader/rustsbi-qemu.bin b/bootloader/rustsbi-qemu.bin index 9822f54e58daad6d5fa47ac4b9b51061dbad1a4a..022c7f27b18efadbfa80301fb467421c52f7cd5e 100755 GIT binary patch literal 38920 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 literal 43568 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∓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 Date: Thu, 20 Oct 2022 11:47:37 +0800 Subject: [PATCH 11/68] build: update toolchain Signed-off-by: YdrMaster --- .github/workflows/doc-and-test.yml | 7 ++++--- rust-toolchain.toml | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/workflows/doc-and-test.yml b/.github/workflows/doc-and-test.yml index 1e6f0b1..804727e 100644 --- a/.github/workflows/doc-and-test.yml +++ b/.github/workflows/doc-and-test.yml @@ -4,6 +4,7 @@ on: [push] env: CARGO_TERM_COLOR: always + rust_toolchain: nightly-2022-08-05 jobs: build-doc: @@ -13,7 +14,7 @@ jobs: - uses: actions-rs/toolchain@v1 with: profile: minimal - toolchain: nightly-2022-07-20 + toolchain: ${{ env.rust_toolchain }} components: rust-src, llvm-tools-preview target: riscv64gc-unknown-none-elf - name: Build doc @@ -32,7 +33,7 @@ jobs: - uses: actions-rs/toolchain@v1 with: profile: minimal - toolchain: nightly-2022-07-20 + toolchain: ${{ env.rust_toolchain }} components: rust-src, llvm-tools-preview target: riscv64gc-unknown-none-elf - uses: actions-rs/install@v0.1 @@ -66,4 +67,4 @@ jobs: timeout-minutes: 10 - name: Build for k210 - run: cd os && make build BOARD=k210 \ No newline at end of file + run: cd os && make build BOARD=k210 diff --git a/rust-toolchain.toml b/rust-toolchain.toml index c56a59e..553747b 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,4 +1,5 @@ [toolchain] profile = "minimal" -channel = "nightly-2022-07-20" +# use the nightly version of the last stable toolchain, see +channel = "nightly-2022-08-05" components = ["rust-src", "llvm-tools-preview", "rustfmt", "clippy"] From f6214968c80a907113fb2d2402b24d1595e6739f Mon Sep 17 00:00:00 2001 From: Yifan Wu Date: Tue, 29 Nov 2022 10:33:55 +0800 Subject: [PATCH 12/68] in entry.asm: boot_stack->boot_stack_lower_bound --- os/src/entry.asm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/os/src/entry.asm b/os/src/entry.asm index a28dc8f..c32d68f 100644 --- a/os/src/entry.asm +++ b/os/src/entry.asm @@ -5,8 +5,8 @@ _start: call rust_main .section .bss.stack - .globl boot_stack -boot_stack: + .globl boot_stack_lower_bound +boot_stack_lower_bound: .space 4096 * 16 .globl boot_stack_top boot_stack_top: From 3fba081487035a6181b7b2d200bc0415f978dbe7 Mon Sep 17 00:00:00 2001 From: Yifan Wu Date: Tue, 29 Nov 2022 11:14:51 +0800 Subject: [PATCH 13/68] Update stack_overflow --- user/src/bin/stack_overflow.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/user/src/bin/stack_overflow.rs b/user/src/bin/stack_overflow.rs index 5d365f5..3bec557 100644 --- a/user/src/bin/stack_overflow.rs +++ b/user/src/bin/stack_overflow.rs @@ -4,9 +4,12 @@ #[macro_use] extern crate user_lib; -fn f(d: usize) { - println!("d = {}", d); - f(d + 1); +#[allow(unconditional_recursion)] +fn f(depth: usize) { + if depth % 10 == 0 { + println!("depth = {}", depth); + } + f(depth + 1); } #[no_mangle] From 775755cf128f6605cc815e01f35442fc46871736 Mon Sep 17 00:00:00 2001 From: Yifan Wu Date: Tue, 13 Dec 2022 23:52:27 +0800 Subject: [PATCH 14/68] Remove K210 support. --- bootloader/rustsbi-k210.bin | Bin 94904 -> 0 bytes os/Cargo.toml | 7 - os/Makefile | 42 +- os/src/boards/k210.rs | 30 -- os/src/console.rs | 6 - os/src/drivers/block/mod.rs | 2 - os/src/drivers/block/sdcard.rs | 767 --------------------------------- os/src/drivers/chardev/mod.rs | 3 +- os/src/drivers/input/mod.rs | 1 - os/src/drivers/mod.rs | 8 +- os/src/fs/stdio.rs | 27 -- os/src/gui/mod.rs | 1 + os/src/linker-k210.ld | 53 --- os/src/main.rs | 10 +- os/src/sbi.rs | 8 +- os/src/syscall/mod.rs | 37 -- os/src/task/mod.rs | 2 - 17 files changed, 10 insertions(+), 994 deletions(-) delete mode 100755 bootloader/rustsbi-k210.bin delete mode 100644 os/src/boards/k210.rs delete mode 100644 os/src/drivers/block/sdcard.rs delete mode 100644 os/src/linker-k210.ld diff --git a/bootloader/rustsbi-k210.bin b/bootloader/rustsbi-k210.bin deleted file mode 100755 index c53ed1fc198816f8d4a0cfec958eaae3f2976cd0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 94904 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 diff --git a/os/Cargo.toml b/os/Cargo.toml index 915e5f9..f4b2d80 100644 --- a/os/Cargo.toml +++ b/os/Cargo.toml @@ -14,17 +14,10 @@ bitflags = "1.2.1" xmas-elf = "0.7.0" volatile = "0.3" virtio-drivers = { git = "https://github.com/rcore-os/virtio-drivers", rev = "4ee80e5" } -k210-pac = { git = "https://github.com/wyfcyx/k210-pac" } -k210-hal = { git = "https://github.com/wyfcyx/k210-hal" } -k210-soc = { git = "https://github.com/wyfcyx/k210-soc" } easy-fs = { path = "../easy-fs" } virtio-input-decoder = "0.1.4" embedded-graphics = "0.7.1" tinybmp = "0.3.1" -[features] -board_qemu = [] -board_k210 = [] - [profile.release] debug = true diff --git a/os/Makefile b/os/Makefile index 0658a5e..b5725d4 100644 --- a/os/Makefile +++ b/os/Makefile @@ -5,14 +5,12 @@ KERNEL_ELF := target/$(TARGET)/$(MODE)/os KERNEL_BIN := $(KERNEL_ELF).bin DISASM_TMP := target/$(TARGET)/$(MODE)/asm FS_IMG := ../user/target/$(TARGET)/$(MODE)/fs.img -SDCARD := /dev/sdb APPS := ../user/src/bin/* # BOARD -BOARD ?= qemu +BOARD := qemu SBI ?= rustsbi BOOTLOADER := ../bootloader/$(SBI)-$(BOARD).bin -K210_BOOTLOADER_SIZE := 131072 # Building mode argument ifeq ($(MODE), release) @@ -20,15 +18,7 @@ ifeq ($(MODE), release) endif # KERNEL ENTRY -ifeq ($(BOARD), qemu) - KERNEL_ENTRY_PA := 0x80200000 -else ifeq ($(BOARD), k210) - KERNEL_ENTRY_PA := 0x80020000 -endif - -# Run K210 -K210-SERIALPORT = /dev/ttyUSB0 -K210-BURNER = ../tools/kflash.py +KERNEL_ENTRY_PA := 0x80200000 # Binutils OBJDUMP := rust-objdump --arch-name=riscv64 @@ -40,14 +30,7 @@ DISASM ?= -x # Run usertests or usershell TEST ?= -build: env switch-check $(KERNEL_BIN) fs-img - -switch-check: -ifeq ($(BOARD), qemu) - (which last-qemu) || (rm -f last-k210 && touch last-qemu && make clean) -else ifeq ($(BOARD), k210) - (which last-k210) || (rm -f last-qemu && touch last-k210 && make clean) -endif +build: env $(KERNEL_BIN) fs-img env: (rustup target list | grep "riscv64gc-unknown-none-elf (installed)") || rustup target add $(TARGET) @@ -55,11 +38,6 @@ env: rustup component add rust-src rustup component add llvm-tools-preview -sdcard: fs-img - @echo "Are you sure write to $(SDCARD) ? [y/N] " && read ans && [ $${ans:-N} = y ] - @sudo dd if=/dev/zero of=$(SDCARD) bs=1048576 count=32 - @sudo dd if=$(FS_IMG) of=$(SDCARD) - $(KERNEL_BIN): kernel @$(OBJCOPY) $(KERNEL_ELF) --strip-all -O binary $@ @@ -73,7 +51,7 @@ $(APPS): kernel: @echo Platform: $(BOARD) @cp src/linker-$(BOARD).ld src/linker.ld - @cargo build --release --features "board_$(BOARD)" + @cargo build --release @rm src/linker.ld clean: @@ -105,7 +83,6 @@ ifeq ($(BOARD),qemu) endif run-inner: build -ifeq ($(BOARD),qemu) @qemu-system-riscv64 \ -M 128m \ -machine virt \ @@ -118,15 +95,6 @@ ifeq ($(BOARD),qemu) -device virtio-keyboard-device \ -device virtio-mouse-device \ -serial stdio -else - (which $(K210-BURNER)) || (cd .. && git clone https://github.com/sipeed/kflash.py.git && mv kflash.py tools) - @cp $(BOOTLOADER) $(BOOTLOADER).copy - @dd if=$(KERNEL_BIN) of=$(BOOTLOADER).copy bs=$(K210_BOOTLOADER_SIZE) seek=1 - @mv $(BOOTLOADER).copy $(KERNEL_BIN) - @sudo chmod 777 $(K210-SERIALPORT) - python3 $(K210-BURNER) -p $(K210-SERIALPORT) -b 1500000 $(KERNEL_BIN) - python3 -m serial.tools.miniterm --eol LF --dtr 0 --rts 0 --filter direct $(K210-SERIALPORT) 115200 -endif debug: build @tmux new-session -d \ @@ -141,4 +109,4 @@ gdbserver: build 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 switch-check fs-img gdbserver gdbclient +.PHONY: build env kernel clean disasm disasm-vim run-inner fs-img gdbserver gdbclient diff --git a/os/src/boards/k210.rs b/os/src/boards/k210.rs deleted file mode 100644 index 249e49f..0000000 --- a/os/src/boards/k210.rs +++ /dev/null @@ -1,30 +0,0 @@ -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 */ -]; - -pub type BlockDeviceImpl = crate::drivers::block::SDCardWrapper; - -pub fn device_init() { - unimplemented!(); -} - -pub fn irq_handler() { - unimplemented!(); -} diff --git a/os/src/console.rs b/os/src/console.rs index 5c8daaf..085637b 100644 --- a/os/src/console.rs +++ b/os/src/console.rs @@ -1,8 +1,5 @@ use crate::drivers::chardev::CharDevice; -#[cfg(feature = "board_qemu")] use crate::drivers::chardev::UART; -#[cfg(feature = "board_k210")] -use crate::sbi::console_putchar; use core::fmt::{self, Write}; struct Stdout; @@ -10,10 +7,7 @@ struct Stdout; impl Write for Stdout { fn write_str(&mut self, s: &str) -> fmt::Result { for c in s.chars() { - #[cfg(feature = "board_qemu")] UART.write(c as u8); - #[cfg(feature = "board_k210")] - console_putchar(c as usize); } Ok(()) } diff --git a/os/src/drivers/block/mod.rs b/os/src/drivers/block/mod.rs index 7361ec8..add8da0 100644 --- a/os/src/drivers/block/mod.rs +++ b/os/src/drivers/block/mod.rs @@ -1,7 +1,5 @@ -mod sdcard; mod virtio_blk; -pub use sdcard::SDCardWrapper; pub use virtio_blk::VirtIOBlock; use crate::board::BlockDeviceImpl; diff --git a/os/src/drivers/block/sdcard.rs b/os/src/drivers/block/sdcard.rs deleted file mode 100644 index 756e9a0..0000000 --- a/os/src/drivers/block/sdcard.rs +++ /dev/null @@ -1,767 +0,0 @@ -#![allow(non_snake_case)] -#![allow(non_camel_case_types)] -#![allow(unused)] - -use super::BlockDevice; -use crate::sync::UPIntrFreeCell; -use core::convert::TryInto; -use k210_hal::prelude::*; -use k210_pac::{Peripherals, SPI0}; -use k210_soc::{ - fpioa::{self, io}, - //dmac::{dma_channel, DMAC, DMACExt}, - gpio, - gpiohs, - sleep::usleep, - spi::{aitm, frame_format, tmod, work_mode, SPIExt, SPIImpl, SPI}, - sysctl, -}; -use lazy_static::*; - -pub struct SDCard { - spi: SPI, - spi_cs: u32, - cs_gpionum: u8, - //dmac: &'a DMAC, - //channel: dma_channel, -} - -/* - * Start Data tokens: - * Tokens (necessary because at nop/idle (and CS active) only 0xff is - * on the data/command line) - */ -/** Data token start byte, Start Single Block Read */ -pub const SD_START_DATA_SINGLE_BLOCK_READ: u8 = 0xFE; -/** Data token start byte, Start Multiple Block Read */ -pub const SD_START_DATA_MULTIPLE_BLOCK_READ: u8 = 0xFE; -/** Data token start byte, Start Single Block Write */ -pub const SD_START_DATA_SINGLE_BLOCK_WRITE: u8 = 0xFE; -/** Data token start byte, Start Multiple Block Write */ -pub const SD_START_DATA_MULTIPLE_BLOCK_WRITE: u8 = 0xFC; - -pub const SEC_LEN: usize = 512; - -/** SD commands */ -#[repr(u8)] -#[derive(Debug, PartialEq, Eq, Copy, Clone)] -#[allow(unused)] -pub enum CMD { - /** Software reset */ - CMD0 = 0, - /** Check voltage range (SDC V2) */ - CMD8 = 8, - /** Read CSD register */ - CMD9 = 9, - /** Read CID register */ - CMD10 = 10, - /** Stop to read data */ - CMD12 = 12, - /** Change R/W block size */ - CMD16 = 16, - /** Read block */ - CMD17 = 17, - /** Read multiple blocks */ - CMD18 = 18, - /** Number of blocks to erase (SDC) */ - ACMD23 = 23, - /** Write a block */ - CMD24 = 24, - /** Write multiple blocks */ - CMD25 = 25, - /** Initiate initialization process (SDC) */ - ACMD41 = 41, - /** Leading command for ACMD* */ - CMD55 = 55, - /** Read OCR */ - CMD58 = 58, - /** Enable/disable CRC check */ - CMD59 = 59, -} - -#[allow(unused)] -#[derive(Debug, Copy, Clone)] -pub enum InitError { - CMDFailed(CMD, u8), - CardCapacityStatusNotSet([u8; 4]), - CannotGetCardInfo, -} - -/** - * Card Specific Data: CSD Register - */ -#[derive(Debug, Copy, Clone)] -pub struct SDCardCSD { - pub CSDStruct: u8, /* CSD structure */ - pub SysSpecVersion: u8, /* System specification version */ - pub Reserved1: u8, /* Reserved */ - pub TAAC: u8, /* Data read access-time 1 */ - pub NSAC: u8, /* Data read access-time 2 in CLK cycles */ - pub MaxBusClkFrec: u8, /* Max. bus clock frequency */ - pub CardComdClasses: u16, /* Card command classes */ - pub RdBlockLen: u8, /* Max. read data block length */ - pub PartBlockRead: u8, /* Partial blocks for read allowed */ - pub WrBlockMisalign: u8, /* Write block misalignment */ - pub RdBlockMisalign: u8, /* Read block misalignment */ - pub DSRImpl: u8, /* DSR implemented */ - pub Reserved2: u8, /* Reserved */ - pub DeviceSize: u32, /* Device Size */ - //MaxRdCurrentVDDMin: u8, /* Max. read current @ VDD min */ - //MaxRdCurrentVDDMax: u8, /* Max. read current @ VDD max */ - //MaxWrCurrentVDDMin: u8, /* Max. write current @ VDD min */ - //MaxWrCurrentVDDMax: u8, /* Max. write current @ VDD max */ - //DeviceSizeMul: u8, /* Device size multiplier */ - pub EraseGrSize: u8, /* Erase group size */ - pub EraseGrMul: u8, /* Erase group size multiplier */ - pub WrProtectGrSize: u8, /* Write protect group size */ - pub WrProtectGrEnable: u8, /* Write protect group enable */ - pub ManDeflECC: u8, /* Manufacturer default ECC */ - pub WrSpeedFact: u8, /* Write speed factor */ - pub MaxWrBlockLen: u8, /* Max. write data block length */ - pub WriteBlockPaPartial: u8, /* Partial blocks for write allowed */ - pub Reserved3: u8, /* Reserded */ - pub ContentProtectAppli: u8, /* Content protection application */ - pub FileFormatGroup: u8, /* File format group */ - pub CopyFlag: u8, /* Copy flag (OTP) */ - pub PermWrProtect: u8, /* Permanent write protection */ - pub TempWrProtect: u8, /* Temporary write protection */ - pub FileFormat: u8, /* File Format */ - pub ECC: u8, /* ECC code */ - pub CSD_CRC: u8, /* CSD CRC */ - pub Reserved4: u8, /* always 1*/ -} - -/** - * Card Identification Data: CID Register - */ -#[derive(Debug, Copy, Clone)] -pub struct SDCardCID { - pub ManufacturerID: u8, /* ManufacturerID */ - pub OEM_AppliID: u16, /* OEM/Application ID */ - pub ProdName1: u32, /* Product Name part1 */ - pub ProdName2: u8, /* Product Name part2*/ - pub ProdRev: u8, /* Product Revision */ - pub ProdSN: u32, /* Product Serial Number */ - pub Reserved1: u8, /* Reserved1 */ - pub ManufactDate: u16, /* Manufacturing Date */ - pub CID_CRC: u8, /* CID CRC */ - pub Reserved2: u8, /* always 1 */ -} - -/** - * Card information - */ -#[derive(Debug, Copy, Clone)] -pub struct SDCardInfo { - pub SD_csd: SDCardCSD, - pub SD_cid: SDCardCID, - pub CardCapacity: u64, /* Card Capacity */ - pub CardBlockSize: u64, /* Card Block Size */ -} - -impl SDCard { - pub fn new( - spi: X, - spi_cs: u32, - cs_gpionum: u8, /*, dmac: &'a DMAC, channel: dma_channel*/ - ) -> Self { - Self { - spi, - spi_cs, - cs_gpionum, - /* - dmac, - channel, - */ - } - } - - fn CS_HIGH(&self) { - gpiohs::set_pin(self.cs_gpionum, true); - } - - fn CS_LOW(&self) { - gpiohs::set_pin(self.cs_gpionum, false); - } - - fn HIGH_SPEED_ENABLE(&self) { - self.spi.set_clk_rate(10000000); - } - - fn lowlevel_init(&self) { - gpiohs::set_direction(self.cs_gpionum, gpio::direction::OUTPUT); - self.spi.set_clk_rate(200000); - } - - fn write_data(&self, data: &[u8]) { - self.spi.configure( - work_mode::MODE0, - frame_format::STANDARD, - 8, /* data bits */ - 0, /* endian */ - 0, /*instruction length*/ - 0, /*address length*/ - 0, /*wait cycles*/ - aitm::STANDARD, - tmod::TRANS, - ); - self.spi.send_data(self.spi_cs, data); - } - - /* - fn write_data_dma(&self, data: &[u32]) { - self.spi.configure( - work_mode::MODE0, - frame_format::STANDARD, - 8, /* data bits */ - 0, /* endian */ - 0, /*instruction length*/ - 0, /*address length*/ - 0, /*wait cycles*/ - aitm::STANDARD, - tmod::TRANS, - ); - self.spi - .send_data_dma(self.dmac, self.channel, self.spi_cs, data); - } - */ - - fn read_data(&self, data: &mut [u8]) { - self.spi.configure( - work_mode::MODE0, - frame_format::STANDARD, - 8, /* data bits */ - 0, /* endian */ - 0, /*instruction length*/ - 0, /*address length*/ - 0, /*wait cycles*/ - aitm::STANDARD, - tmod::RECV, - ); - self.spi.recv_data(self.spi_cs, data); - } - - /* - fn read_data_dma(&self, data: &mut [u32]) { - self.spi.configure( - work_mode::MODE0, - frame_format::STANDARD, - 8, /* data bits */ - 0, /* endian */ - 0, /*instruction length*/ - 0, /*address length*/ - 0, /*wait cycles*/ - aitm::STANDARD, - tmod::RECV, - ); - self.spi - .recv_data_dma(self.dmac, self.channel, self.spi_cs, data); - } - */ - - /* - * Send 5 bytes command to the SD card. - * @param cmd: The user expected command to send to SD card. - * @param arg: The command argument. - * @param crc: The CRC. - * @retval None - */ - fn send_cmd(&self, cmd: CMD, arg: u32, crc: u8) { - /* SD chip select low */ - self.CS_LOW(); - /* Send the Cmd bytes */ - self.write_data(&[ - /* Construct byte 1 */ - ((cmd as u8) | 0x40), - /* Construct byte 2 */ - (arg >> 24) as u8, - /* Construct byte 3 */ - ((arg >> 16) & 0xff) as u8, - /* Construct byte 4 */ - ((arg >> 8) & 0xff) as u8, - /* Construct byte 5 */ - (arg & 0xff) as u8, - /* Construct CRC: byte 6 */ - crc, - ]); - } - - /* Send end-command sequence to SD card */ - fn end_cmd(&self) { - /* SD chip select high */ - self.CS_HIGH(); - /* Send the cmd byte */ - self.write_data(&[0xff]); - } - - /* - * Returns the SD response. - * @param None - * @retval The SD Response: - * - 0xFF: Sequence failed - * - 0: Sequence succeed - */ - fn get_response(&self) -> u8 { - let result = &mut [0u8]; - let mut timeout = 0x0FFF; - /* Check if response is got or a timeout is happen */ - while timeout != 0 { - self.read_data(result); - /* Right response got */ - if result[0] != 0xFF { - return result[0]; - } - timeout -= 1; - } - /* After time out */ - 0xFF - } - - /* - * Get SD card data response. - * @param None - * @retval The SD status: Read data response xxx01 - * - status 010: Data accepted - * - status 101: Data rejected due to a crc error - * - status 110: Data rejected due to a Write error. - * - status 111: Data rejected due to other error. - */ - fn get_dataresponse(&self) -> u8 { - let response = &mut [0u8]; - /* Read response */ - self.read_data(response); - /* Mask unused bits */ - response[0] &= 0x1F; - if response[0] != 0x05 { - return 0xFF; - } - /* Wait null data */ - self.read_data(response); - while response[0] == 0 { - self.read_data(response); - } - /* Return response */ - 0 - } - - /* - * Read the CSD card register - * Reading the contents of the CSD register in SPI mode is a simple - * read-block transaction. - * @param SD_csd: pointer on an SCD register structure - * @retval The SD Response: - * - `Err()`: Sequence failed - * - `Ok(info)`: Sequence succeed - */ - fn get_csdregister(&self) -> Result { - let mut csd_tab = [0u8; 18]; - /* Send CMD9 (CSD register) */ - self.send_cmd(CMD::CMD9, 0, 0); - /* Wait for response in the R1 format (0x00 is no errors) */ - if self.get_response() != 0x00 { - self.end_cmd(); - return Err(()); - } - if self.get_response() != SD_START_DATA_SINGLE_BLOCK_READ { - self.end_cmd(); - return Err(()); - } - /* Store CSD register value on csd_tab */ - /* Get CRC bytes (not really needed by us, but required by SD) */ - self.read_data(&mut csd_tab); - self.end_cmd(); - /* see also: https://cdn-shop.adafruit.com/datasheets/TS16GUSDHC6.pdf */ - Ok(SDCardCSD { - /* Byte 0 */ - CSDStruct: (csd_tab[0] & 0xC0) >> 6, - SysSpecVersion: (csd_tab[0] & 0x3C) >> 2, - Reserved1: csd_tab[0] & 0x03, - /* Byte 1 */ - TAAC: csd_tab[1], - /* Byte 2 */ - NSAC: csd_tab[2], - /* Byte 3 */ - MaxBusClkFrec: csd_tab[3], - /* Byte 4, 5 */ - CardComdClasses: (u16::from(csd_tab[4]) << 4) | ((u16::from(csd_tab[5]) & 0xF0) >> 4), - /* Byte 5 */ - RdBlockLen: csd_tab[5] & 0x0F, - /* Byte 6 */ - PartBlockRead: (csd_tab[6] & 0x80) >> 7, - WrBlockMisalign: (csd_tab[6] & 0x40) >> 6, - RdBlockMisalign: (csd_tab[6] & 0x20) >> 5, - DSRImpl: (csd_tab[6] & 0x10) >> 4, - Reserved2: 0, - // DeviceSize: (csd_tab[6] & 0x03) << 10, - /* Byte 7, 8, 9 */ - DeviceSize: ((u32::from(csd_tab[7]) & 0x3F) << 16) - | (u32::from(csd_tab[8]) << 8) - | u32::from(csd_tab[9]), - /* Byte 10 */ - EraseGrSize: (csd_tab[10] & 0x40) >> 6, - /* Byte 10, 11 */ - EraseGrMul: ((csd_tab[10] & 0x3F) << 1) | ((csd_tab[11] & 0x80) >> 7), - /* Byte 11 */ - WrProtectGrSize: (csd_tab[11] & 0x7F), - /* Byte 12 */ - WrProtectGrEnable: (csd_tab[12] & 0x80) >> 7, - ManDeflECC: (csd_tab[12] & 0x60) >> 5, - WrSpeedFact: (csd_tab[12] & 0x1C) >> 2, - /* Byte 12,13 */ - MaxWrBlockLen: ((csd_tab[12] & 0x03) << 2) | ((csd_tab[13] & 0xC0) >> 6), - /* Byte 13 */ - WriteBlockPaPartial: (csd_tab[13] & 0x20) >> 5, - Reserved3: 0, - ContentProtectAppli: (csd_tab[13] & 0x01), - /* Byte 14 */ - FileFormatGroup: (csd_tab[14] & 0x80) >> 7, - CopyFlag: (csd_tab[14] & 0x40) >> 6, - PermWrProtect: (csd_tab[14] & 0x20) >> 5, - TempWrProtect: (csd_tab[14] & 0x10) >> 4, - FileFormat: (csd_tab[14] & 0x0C) >> 2, - ECC: (csd_tab[14] & 0x03), - /* Byte 15 */ - CSD_CRC: (csd_tab[15] & 0xFE) >> 1, - Reserved4: 1, - /* Return the response */ - }) - } - - /* - * Read the CID card register. - * Reading the contents of the CID register in SPI mode is a simple - * read-block transaction. - * @param SD_cid: pointer on an CID register structure - * @retval The SD Response: - * - `Err()`: Sequence failed - * - `Ok(info)`: Sequence succeed - */ - fn get_cidregister(&self) -> Result { - let mut cid_tab = [0u8; 18]; - /* Send CMD10 (CID register) */ - self.send_cmd(CMD::CMD10, 0, 0); - /* Wait for response in the R1 format (0x00 is no errors) */ - if self.get_response() != 0x00 { - self.end_cmd(); - return Err(()); - } - if self.get_response() != SD_START_DATA_SINGLE_BLOCK_READ { - self.end_cmd(); - return Err(()); - } - /* Store CID register value on cid_tab */ - /* Get CRC bytes (not really needed by us, but required by SD) */ - self.read_data(&mut cid_tab); - self.end_cmd(); - Ok(SDCardCID { - /* Byte 0 */ - ManufacturerID: cid_tab[0], - /* Byte 1, 2 */ - OEM_AppliID: (u16::from(cid_tab[1]) << 8) | u16::from(cid_tab[2]), - /* Byte 3, 4, 5, 6 */ - ProdName1: (u32::from(cid_tab[3]) << 24) - | (u32::from(cid_tab[4]) << 16) - | (u32::from(cid_tab[5]) << 8) - | u32::from(cid_tab[6]), - /* Byte 7 */ - ProdName2: cid_tab[7], - /* Byte 8 */ - ProdRev: cid_tab[8], - /* Byte 9, 10, 11, 12 */ - ProdSN: (u32::from(cid_tab[9]) << 24) - | (u32::from(cid_tab[10]) << 16) - | (u32::from(cid_tab[11]) << 8) - | u32::from(cid_tab[12]), - /* Byte 13, 14 */ - Reserved1: (cid_tab[13] & 0xF0) >> 4, - ManufactDate: ((u16::from(cid_tab[13]) & 0x0F) << 8) | u16::from(cid_tab[14]), - /* Byte 15 */ - CID_CRC: (cid_tab[15] & 0xFE) >> 1, - Reserved2: 1, - }) - } - - /* - * Returns information about specific card. - * @param cardinfo: pointer to a SD_CardInfo structure that contains all SD - * card information. - * @retval The SD Response: - * - `Err(())`: Sequence failed - * - `Ok(info)`: Sequence succeed - */ - fn get_cardinfo(&self) -> Result { - let mut info = SDCardInfo { - SD_csd: self.get_csdregister()?, - SD_cid: self.get_cidregister()?, - CardCapacity: 0, - CardBlockSize: 0, - }; - info.CardBlockSize = 1 << u64::from(info.SD_csd.RdBlockLen); - info.CardCapacity = (u64::from(info.SD_csd.DeviceSize) + 1) * 1024 * info.CardBlockSize; - - Ok(info) - } - - /* - * Initializes the SD/SD communication in SPI mode. - * @param None - * @retval The SD Response info if succeeeded, otherwise Err - */ - pub fn init(&self) -> Result { - /* Initialize SD_SPI */ - self.lowlevel_init(); - /* SD chip select high */ - self.CS_HIGH(); - /* NOTE: this reset doesn't always seem to work if the SD access was broken off in the - * middle of an operation: CMDFailed(CMD0, 127). */ - - /* Send dummy byte 0xFF, 10 times with CS high */ - /* Rise CS and MOSI for 80 clocks cycles */ - /* Send dummy byte 0xFF */ - self.write_data(&[0xff; 10]); - /*------------Put SD in SPI mode--------------*/ - /* SD initialized and set to SPI mode properly */ - - /* Send software reset */ - self.send_cmd(CMD::CMD0, 0, 0x95); - let result = self.get_response(); - self.end_cmd(); - if result != 0x01 { - return Err(InitError::CMDFailed(CMD::CMD0, result)); - } - - /* Check voltage range */ - self.send_cmd(CMD::CMD8, 0x01AA, 0x87); - /* 0x01 or 0x05 */ - let result = self.get_response(); - let mut frame = [0u8; 4]; - self.read_data(&mut frame); - self.end_cmd(); - if result != 0x01 { - return Err(InitError::CMDFailed(CMD::CMD8, result)); - } - let mut index = 255; - while index != 0 { - /* */ - self.send_cmd(CMD::CMD55, 0, 0); - let result = self.get_response(); - self.end_cmd(); - if result != 0x01 { - return Err(InitError::CMDFailed(CMD::CMD55, result)); - } - /* Initiate SDC initialization process */ - self.send_cmd(CMD::ACMD41, 0x40000000, 0); - let result = self.get_response(); - self.end_cmd(); - if result == 0x00 { - break; - } - index -= 1; - } - if index == 0 { - return Err(InitError::CMDFailed(CMD::ACMD41, result)); - } - index = 255; - let mut frame = [0u8; 4]; - while index != 0 { - /* Read OCR */ - self.send_cmd(CMD::CMD58, 0, 1); - let result = self.get_response(); - self.read_data(&mut frame); - self.end_cmd(); - if result == 0 { - break; - } - index -= 1; - } - if index == 0 { - return Err(InitError::CMDFailed(CMD::CMD58, result)); - } - if (frame[0] & 0x40) == 0 { - return Err(InitError::CardCapacityStatusNotSet(frame)); - } - self.HIGH_SPEED_ENABLE(); - self.get_cardinfo() - .map_err(|_| InitError::CannotGetCardInfo) - } - - /* - * Reads a block of data from the SD. - * @param data_buf: slice that receives the data read from the SD. - * @param sector: SD's internal address to read from. - * @retval The SD Response: - * - `Err(())`: Sequence failed - * - `Ok(())`: Sequence succeed - */ - pub fn read_sector(&self, data_buf: &mut [u8], sector: u32) -> Result<(), ()> { - assert!(data_buf.len() >= SEC_LEN && (data_buf.len() % SEC_LEN) == 0); - /* Send CMD17 to read one block, or CMD18 for multiple */ - let flag = if data_buf.len() == SEC_LEN { - self.send_cmd(CMD::CMD17, sector, 0); - false - } else { - self.send_cmd(CMD::CMD18, sector, 0); - true - }; - /* Check if the SD acknowledged the read block command: R1 response (0x00: no errors) */ - if self.get_response() != 0x00 { - self.end_cmd(); - return Err(()); - } - let mut error = false; - //let mut dma_chunk = [0u32; SEC_LEN]; - let mut tmp_chunk = [0u8; SEC_LEN]; - for chunk in data_buf.chunks_mut(SEC_LEN) { - if self.get_response() != SD_START_DATA_SINGLE_BLOCK_READ { - error = true; - break; - } - /* Read the SD block data : read NumByteToRead data */ - //self.read_data_dma(&mut dma_chunk); - self.read_data(&mut tmp_chunk); - /* Place the data received as u32 units from DMA into the u8 target buffer */ - for (a, b) in chunk.iter_mut().zip(/*dma_chunk*/ tmp_chunk.iter()) { - //*a = (b & 0xff) as u8; - *a = *b; - } - /* Get CRC bytes (not really needed by us, but required by SD) */ - let mut frame = [0u8; 2]; - self.read_data(&mut frame); - } - self.end_cmd(); - if flag { - self.send_cmd(CMD::CMD12, 0, 0); - self.get_response(); - self.end_cmd(); - self.end_cmd(); - } - /* It is an error if not everything requested was read */ - if error { - Err(()) - } else { - Ok(()) - } - } - - /* - * Writes a block to the SD - * @param data_buf: slice containing the data to be written to the SD. - * @param sector: address to write on. - * @retval The SD Response: - * - `Err(())`: Sequence failed - * - `Ok(())`: Sequence succeed - */ - pub fn write_sector(&self, data_buf: &[u8], sector: u32) -> Result<(), ()> { - assert!(data_buf.len() >= SEC_LEN && (data_buf.len() % SEC_LEN) == 0); - let mut frame = [0xff, 0x00]; - if data_buf.len() == SEC_LEN { - frame[1] = SD_START_DATA_SINGLE_BLOCK_WRITE; - self.send_cmd(CMD::CMD24, sector, 0); - } else { - frame[1] = SD_START_DATA_MULTIPLE_BLOCK_WRITE; - self.send_cmd( - CMD::ACMD23, - (data_buf.len() / SEC_LEN).try_into().unwrap(), - 0, - ); - self.get_response(); - self.end_cmd(); - self.send_cmd(CMD::CMD25, sector, 0); - } - /* Check if the SD acknowledged the write block command: R1 response (0x00: no errors) */ - if self.get_response() != 0x00 { - self.end_cmd(); - return Err(()); - } - //let mut dma_chunk = [0u32; SEC_LEN]; - let mut tmp_chunk = [0u8; SEC_LEN]; - for chunk in data_buf.chunks(SEC_LEN) { - /* Send the data token to signify the start of the data */ - self.write_data(&frame); - /* Write the block data to SD : write count data by block */ - for (a, &b) in /*dma_chunk*/ tmp_chunk.iter_mut().zip(chunk.iter()) { - //*a = b.into(); - *a = b; - } - //self.write_data_dma(&mut dma_chunk); - self.write_data(&tmp_chunk); - /* Put dummy CRC bytes */ - self.write_data(&[0xff, 0xff]); - /* Read data response */ - if self.get_dataresponse() != 0x00 { - self.end_cmd(); - return Err(()); - } - } - self.end_cmd(); - self.end_cmd(); - Ok(()) - } -} - -/** GPIOHS GPIO number to use for controlling the SD card CS pin */ -const SD_CS_GPIONUM: u8 = 7; -/** CS value passed to SPI controller, this is a dummy value as SPI0_CS3 is not mapping to anything - * in the FPIOA */ -const SD_CS: u32 = 3; - -/** Connect pins to internal functions */ -fn io_init() { - fpioa::set_function(io::SPI0_SCLK, fpioa::function::SPI0_SCLK); - fpioa::set_function(io::SPI0_MOSI, fpioa::function::SPI0_D0); - fpioa::set_function(io::SPI0_MISO, fpioa::function::SPI0_D1); - fpioa::set_function(io::SPI0_CS0, fpioa::function::gpiohs(SD_CS_GPIONUM)); - fpioa::set_io_pull(io::SPI0_CS0, fpioa::pull::DOWN); // GPIO output=pull down -} - -lazy_static! { - static ref PERIPHERALS: UPIntrFreeCell = - unsafe { UPIntrFreeCell::new(Peripherals::take().unwrap()) }; -} - -fn init_sdcard() -> SDCard> { - // wait previous output - usleep(100000); - let peripherals = unsafe { Peripherals::steal() }; - sysctl::pll_set_freq(sysctl::pll::PLL0, 800_000_000).unwrap(); - sysctl::pll_set_freq(sysctl::pll::PLL1, 300_000_000).unwrap(); - sysctl::pll_set_freq(sysctl::pll::PLL2, 45_158_400).unwrap(); - let clocks = k210_hal::clock::Clocks::new(); - peripherals.UARTHS.configure(115_200.bps(), &clocks); - io_init(); - - let spi = peripherals.SPI0.constrain(); - let sd = SDCard::new(spi, SD_CS, SD_CS_GPIONUM); - let info = sd.init().unwrap(); - let num_sectors = info.CardCapacity / 512; - assert!(num_sectors > 0); - - println!("init sdcard!"); - sd -} - -pub struct SDCardWrapper(UPIntrFreeCell>>); - -impl SDCardWrapper { - pub fn new() -> Self { - unsafe { Self(UPIntrFreeCell::new(init_sdcard())) } - } -} - -impl BlockDevice for SDCardWrapper { - fn read_block(&self, block_id: usize, buf: &mut [u8]) { - self.0 - .exclusive_access() - .read_sector(buf, block_id as u32) - .unwrap(); - } - fn write_block(&self, block_id: usize, buf: &[u8]) { - self.0 - .exclusive_access() - .write_sector(buf, block_id as u32) - .unwrap(); - } - fn handle_irq(&self) { - unimplemented!(); - } -} diff --git a/os/src/drivers/chardev/mod.rs b/os/src/drivers/chardev/mod.rs index 2a04f8e..de1446d 100644 --- a/os/src/drivers/chardev/mod.rs +++ b/os/src/drivers/chardev/mod.rs @@ -1,6 +1,5 @@ mod ns16550a; -#[cfg(feature = "board_qemu")] use crate::board::CharDeviceImpl; use alloc::sync::Arc; use lazy_static::*; @@ -11,7 +10,7 @@ pub trait CharDevice { fn write(&self, ch: u8); fn handle_irq(&self); } -#[cfg(feature = "board_qemu")] + lazy_static! { pub static ref UART: Arc = Arc::new(CharDeviceImpl::new()); } diff --git a/os/src/drivers/input/mod.rs b/os/src/drivers/input/mod.rs index 1da66a6..1f2efc6 100644 --- a/os/src/drivers/input/mod.rs +++ b/os/src/drivers/input/mod.rs @@ -9,7 +9,6 @@ use embedded_graphics::{ prelude::{Point, Size}, text::Text, }; -use k210_hal::cache::Uncache; use virtio_drivers::{VirtIOHeader, VirtIOInput}; use crate::drivers::bus::virtio::VirtioHal; use virtio_input_decoder::{Decoder, Key, KeyType}; diff --git a/os/src/drivers/mod.rs b/os/src/drivers/mod.rs index cdd3757..a4cbfed 100644 --- a/os/src/drivers/mod.rs +++ b/os/src/drivers/mod.rs @@ -1,18 +1,12 @@ pub mod block; pub mod chardev; -#[cfg(feature = "board_qemu")] pub mod gpu; -#[cfg(feature = "board_qemu")] pub mod input; -#[cfg(feature = "board_qemu")] pub mod bus; pub mod plic; + pub use block::BLOCK_DEVICE; -#[cfg(feature = "board_qemu")] pub use chardev::UART; -#[cfg(feature = "board_qemu")] pub use gpu::*; -#[cfg(feature = "board_qemu")] pub use input::*; -#[cfg(feature = "board_qemu")] pub use bus::*; diff --git a/os/src/fs/stdio.rs b/os/src/fs/stdio.rs index 33af603..66f4c5a 100644 --- a/os/src/fs/stdio.rs +++ b/os/src/fs/stdio.rs @@ -1,12 +1,7 @@ use super::File; use crate::drivers::chardev::CharDevice; -#[cfg(feature = "board_qemu")] use crate::drivers::chardev::UART; use crate::mm::UserBuffer; -#[cfg(feature = "board_k210")] -use crate::sbi::console_getchar; -#[cfg(feature = "board_k210")] -use crate::task::suspend_current_and_run_next; pub struct Stdin; pub struct Stdout; @@ -18,7 +13,6 @@ impl File for Stdin { fn writable(&self) -> bool { false } - #[cfg(feature = "board_qemu")] fn read(&self, mut user_buf: UserBuffer) -> usize { assert_eq!(user_buf.len(), 1); //println!("before UART.read() in Stdin::read()"); @@ -28,27 +22,6 @@ impl File for Stdin { } 1 } - #[cfg(feature = "board_k210")] - fn read(&self, mut user_buf: UserBuffer) -> usize { - assert_eq!(user_buf.len(), 1); - // busy loop - let mut c: usize; - loop { - c = console_getchar(); - if c == 0 { - suspend_current_and_run_next(); - continue; - } else { - break; - } - } - let ch = c as u8; - unsafe { - user_buf.buffers[0].as_mut_ptr().write_volatile(ch); - } - 1 - } - fn write(&self, _user_buf: UserBuffer) -> usize { panic!("Cannot write to stdin!"); } diff --git a/os/src/gui/mod.rs b/os/src/gui/mod.rs index da3aae9..f702aa0 100644 --- a/os/src/gui/mod.rs +++ b/os/src/gui/mod.rs @@ -4,6 +4,7 @@ mod icon; mod image; mod panel; mod terminal; + use alloc::sync::Arc; pub use button::*; use core::any::Any; diff --git a/os/src/linker-k210.ld b/os/src/linker-k210.ld deleted file mode 100644 index eaa2c9f..0000000 --- a/os/src/linker-k210.ld +++ /dev/null @@ -1,53 +0,0 @@ -OUTPUT_ARCH(riscv) -ENTRY(_start) -BASE_ADDRESS = 0x80020000; - -SECTIONS -{ - . = BASE_ADDRESS; - skernel = .; - - stext = .; - .text : { - *(.text.entry) - . = ALIGN(4K); - strampoline = .; - *(.text.trampoline); - . = ALIGN(4K); - *(.text .text.*) - } - - . = ALIGN(4K); - etext = .; - srodata = .; - .rodata : { - *(.rodata .rodata.*) - *(.srodata .srodata.*) - } - - . = ALIGN(4K); - erodata = .; - sdata = .; - .data : { - *(.data .data.*) - *(.sdata .sdata.*) - } - - . = ALIGN(4K); - edata = .; - sbss_with_stack = .; - .bss : { - *(.bss.stack) - sbss = .; - *(.bss .bss.*) - *(.sbss .sbss.*) - } - - . = ALIGN(4K); - ebss = .; - ekernel = .; - - /DISCARD/ : { - *(.eh_frame) - } -} \ No newline at end of file diff --git a/os/src/main.rs b/os/src/main.rs index 014b029..ce7dcc1 100644 --- a/os/src/main.rs +++ b/os/src/main.rs @@ -2,7 +2,7 @@ #![no_main] #![feature(panic_info_message)] #![feature(alloc_error_handler)] -#[cfg(feature = "board_qemu")] + use crate::drivers::{GPU_DEVICE, KEYBOARD_DEVICE, MOUSE_DEVICE}; extern crate alloc; @@ -10,10 +10,6 @@ extern crate alloc; #[macro_use] extern crate bitflags; -#[cfg(feature = "board_k210")] -#[path = "boards/k210.rs"] -mod board; -#[cfg(not(any(feature = "board_k210")))] #[path = "boards/qemu.rs"] mod board; @@ -22,7 +18,6 @@ mod console; mod config; mod drivers; mod fs; -#[cfg(feature = "board_qemu")] mod gui; mod lang_items; mod mm; @@ -61,13 +56,10 @@ pub fn rust_main() -> ! { clear_bss(); mm::init(); println!("KERN: init gpu"); - #[cfg(feature = "board_qemu")] GPU_DEVICE.clone(); println!("KERN: init keyboard"); - #[cfg(feature = "board_qemu")] KEYBOARD_DEVICE.clone(); println!("KERN: init mouse"); - #[cfg(feature = "board_qemu")] MOUSE_DEVICE.clone(); println!("KERN: init trap"); trap::init(); diff --git a/os/src/sbi.rs b/os/src/sbi.rs index a218ec8..5113c90 100644 --- a/os/src/sbi.rs +++ b/os/src/sbi.rs @@ -40,13 +40,7 @@ pub fn console_getchar() -> usize { sbi_call(SBI_CONSOLE_GETCHAR, 0, 0, 0) } -#[cfg(feature = "board_qemu")] use crate::board::QEMUExit; pub fn shutdown(exit_code: usize) -> ! { - #[cfg(feature = "board_k210")] - sbi_call(SBI_SHUTDOWN, exit_code, 0, 0); - #[cfg(feature = "board_qemu")] - crate::board::QEMU_EXIT_HANDLE.exit_failure(); - #[cfg(feature = "board_k210")] - panic!("It should shutdown!"); + crate::board::QEMU_EXIT_HANDLE.exit_failure() } diff --git a/os/src/syscall/mod.rs b/os/src/syscall/mod.rs index 70a1f16..dccb73b 100644 --- a/os/src/syscall/mod.rs +++ b/os/src/syscall/mod.rs @@ -27,22 +27,18 @@ const SYSCALL_CONDVAR_SIGNAL: usize = 1031; const SYSCALL_CONDVAR_WAIT: usize = 1032; const SYSCALL_CREATE_DESKTOP: usize = 2000; mod fs; -#[cfg(feature = "board_qemu")] mod gui; mod process; mod sync; mod thread; -#[cfg(feature = "board_qemu")] pub use self::gui::create_desktop; use fs::*; -#[cfg(feature = "board_qemu")] pub use gui::PAD; use process::*; use sync::*; use thread::*; -#[cfg(feature = "board_qemu")] pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize { match syscall_id { SYSCALL_DUP => sys_dup(args[0]), @@ -77,36 +73,3 @@ pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize { } } -#[cfg(feature = "board_k210")] -pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize { - match syscall_id { - SYSCALL_DUP => sys_dup(args[0]), - SYSCALL_OPEN => sys_open(args[0] as *const u8, args[1] as u32), - SYSCALL_CLOSE => sys_close(args[0]), - SYSCALL_PIPE => sys_pipe(args[0] as *mut usize), - SYSCALL_READ => sys_read(args[0], args[1] as *const u8, args[2]), - SYSCALL_WRITE => sys_write(args[0], args[1] as *const u8, args[2]), - SYSCALL_EXIT => sys_exit(args[0] as i32), - SYSCALL_SLEEP => sys_sleep(args[0]), - SYSCALL_YIELD => sys_yield(), - SYSCALL_KILL => sys_kill(args[0], args[1] as u32), - SYSCALL_GET_TIME => sys_get_time(), - SYSCALL_GETPID => sys_getpid(), - SYSCALL_FORK => sys_fork(), - SYSCALL_EXEC => sys_exec(args[0] as *const u8, args[1] as *const usize), - SYSCALL_WAITPID => sys_waitpid(args[0] as isize, args[1] as *mut i32), - SYSCALL_THREAD_CREATE => sys_thread_create(args[0], args[1]), - SYSCALL_GETTID => sys_gettid(), - SYSCALL_WAITTID => sys_waittid(args[0]) as isize, - SYSCALL_MUTEX_CREATE => sys_mutex_create(args[0] == 1), - SYSCALL_MUTEX_LOCK => sys_mutex_lock(args[0]), - SYSCALL_MUTEX_UNLOCK => sys_mutex_unlock(args[0]), - SYSCALL_SEMAPHORE_CREATE => sys_semaphore_create(args[0]), - SYSCALL_SEMAPHORE_UP => sys_semaphore_up(args[0]), - SYSCALL_SEMAPHORE_DOWN => sys_semaphore_down(args[0]), - SYSCALL_CONDVAR_CREATE => sys_condvar_create(args[0]), - SYSCALL_CONDVAR_SIGNAL => sys_condvar_signal(args[0]), - SYSCALL_CONDVAR_WAIT => sys_condvar_wait(args[0], args[1]), - _ => panic!("Unsupported syscall_id: {}", syscall_id), - } -} diff --git a/os/src/task/mod.rs b/os/src/task/mod.rs index 31c792c..97e76bd 100644 --- a/os/src/task/mod.rs +++ b/os/src/task/mod.rs @@ -56,7 +56,6 @@ pub fn block_current_and_run_next() { let task_cx_ptr = block_current_task(); schedule(task_cx_ptr); } -#[cfg(feature = "board_qemu")] use crate::board::QEMUExit; pub fn exit_current_and_run_next(exit_code: i32) { @@ -75,7 +74,6 @@ pub fn exit_current_and_run_next(exit_code: i32) { // the process should terminate at once if tid == 0 { let pid = process.getpid(); - #[cfg(feature = "board_qemu")] if pid == IDLE_PID { println!( "[kernel] Idle process exit with exit_code {} ...", From b1173161fc38241b942856ca48dbc14149d84816 Mon Sep 17 00:00:00 2001 From: Yifan Wu Date: Wed, 14 Dec 2022 00:20:45 +0800 Subject: [PATCH 15/68] Modify run_pipe_test. --- user/src/bin/run_pipe_test.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user/src/bin/run_pipe_test.rs b/user/src/bin/run_pipe_test.rs index 5f50b0d..d3e329d 100644 --- a/user/src/bin/run_pipe_test.rs +++ b/user/src/bin/run_pipe_test.rs @@ -8,7 +8,7 @@ use user_lib::{exec, fork, wait}; #[no_mangle] pub fn main() -> i32 { - for i in 0..50 { + for i in 0..5 { if fork() == 0 { exec("pipe_large_test\0", &[core::ptr::null::()]); } else { From 206c09fe860548e228d32ad34fae9d991d987bb3 Mon Sep 17 00:00:00 2001 From: Yifan Wu Date: Wed, 14 Dec 2022 00:41:59 +0800 Subject: [PATCH 16/68] Workflow: Remove k210 support. --- .github/workflows/doc-and-test.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/doc-and-test.yml b/.github/workflows/doc-and-test.yml index 804727e..6da799d 100644 --- a/.github/workflows/doc-and-test.yml +++ b/.github/workflows/doc-and-test.yml @@ -18,7 +18,7 @@ jobs: 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" + run: cd os && cargo doc --no-deps --verbose - name: Deploy to Github Pages uses: peaceiris/actions-gh-pages@v3 with: @@ -66,5 +66,3 @@ jobs: run: cd os && make run TEST=1 timeout-minutes: 10 - - name: Build for k210 - run: cd os && make build BOARD=k210 From 932ae94711ffff97d43a4bea72bb1373479dd7f8 Mon Sep 17 00:00:00 2001 From: Yifan Wu Date: Mon, 19 Dec 2022 03:55:58 -0800 Subject: [PATCH 17/68] feat: simple drawing board GUI --- .gitignore | 3 +- os/Cargo.toml | 2 + os/Makefile | 29 ++++---- os/run-fdt.sh | 11 --- os/run-nodisp.sh | 10 --- os/run.sh | 9 --- os/src/boards/qemu.rs | 3 +- os/src/drivers/block/virtio_blk.rs | 7 +- os/src/drivers/bus/mod.rs | 2 +- os/src/drivers/bus/virtio.rs | 4 +- os/src/drivers/gpu/mod.rs | 19 +++--- os/src/drivers/input/mod.rs | 89 ++++++++++++------------ os/src/drivers/mod.rs | 4 +- os/src/gui/button.rs | 79 ---------------------- os/src/gui/graphic.rs | 16 +++-- os/src/gui/icon.rs | 79 ---------------------- os/src/gui/image.rs | 80 ---------------------- os/src/gui/mod.rs | 23 +------ os/src/gui/paint.rs | 62 +++++++++++++++++ os/src/gui/panel.rs | 66 ------------------ os/src/gui/terminal.rs | 105 ----------------------------- os/src/main.rs | 10 +-- os/src/mm/frame_allocator.rs | 2 +- os/src/mm/memory_set.rs | 26 +++---- os/src/syscall/gui.rs | 63 ----------------- os/src/syscall/mod.rs | 9 +-- os/src/timer.rs | 17 ++--- os/src/trap/mod.rs | 2 +- user/src/bin/gui.rs | 19 ------ user/src/bin/huge_write_mt.rs | 2 +- user/src/bin/peterson.rs | 1 - user/src/lib.rs | 4 +- user/src/syscall.rs | 3 - 33 files changed, 191 insertions(+), 669 deletions(-) delete mode 100755 os/run-fdt.sh delete mode 100755 os/run-nodisp.sh delete mode 100755 os/run.sh delete mode 100644 os/src/gui/button.rs delete mode 100644 os/src/gui/icon.rs delete mode 100644 os/src/gui/image.rs create mode 100644 os/src/gui/paint.rs delete mode 100644 os/src/gui/panel.rs delete mode 100644 os/src/gui/terminal.rs delete mode 100644 os/src/syscall/gui.rs delete mode 100644 user/src/bin/gui.rs diff --git a/.gitignore b/.gitignore index 01335bf..852c161 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ os/src/link_app.S os/src/linker.ld os/last-* os/.gdb_history +os/virt.out tools/ pushall.sh -.vscode/*.log \ No newline at end of file +.vscode/*.log diff --git a/os/Cargo.toml b/os/Cargo.toml index f4b2d80..b9ac5b8 100644 --- a/os/Cargo.toml +++ b/os/Cargo.toml @@ -18,6 +18,8 @@ easy-fs = { path = "../easy-fs" } virtio-input-decoder = "0.1.4" embedded-graphics = "0.7.1" tinybmp = "0.3.1" +embedded-term = { git = "https://github.com/rcore-os/embedded-term" } + [profile.release] debug = true diff --git a/os/Makefile b/os/Makefile index b5725d4..e02bc81 100644 --- a/os/Makefile +++ b/os/Makefile @@ -12,6 +12,12 @@ BOARD := qemu SBI ?= rustsbi BOOTLOADER := ../bootloader/$(SBI)-$(BOARD).bin +# GUI +GUI ?= off +ifeq ($(GUI), off) + GUI_OPTION := -display none +endif + # Building mode argument ifeq ($(MODE), release) MODE_ARG := --release @@ -67,27 +73,12 @@ disasm-vim: kernel run: run-inner -gui: build -ifeq ($(BOARD),qemu) - @qemu-system-riscv64 \ - -M 128m \ - -machine virt \ - -bios $(BOOTLOADER) \ - -device loader,file=$(KERNEL_BIN),addr=$(KERNEL_ENTRY_PA) \ - -drive file=$(FS_IMG),if=none,format=raw,id=x0 \ - -device virtio-blk-device,drive=x0 \ - -device virtio-gpu-device \ - -device virtio-keyboard-device \ - -device virtio-mouse-device \ - -serial stdio -endif - run-inner: build @qemu-system-riscv64 \ -M 128m \ -machine virt \ -bios $(BOOTLOADER) \ - -display none \ + $(GUI_OPTION) \ -device loader,file=$(KERNEL_BIN),addr=$(KERNEL_ENTRY_PA) \ -drive file=$(FS_IMG),if=none,format=raw,id=x0 \ -device virtio-blk-device,drive=x0 \ @@ -96,6 +87,10 @@ run-inner: build -device virtio-mouse-device \ -serial stdio +fdt: + @qemu-system-riscv64 -M 128m -machine virt,dumpdtb=virt.out + fdtdump virt.out + debug: build @tmux new-session -d \ "qemu-system-riscv64 -machine virt -nographic -bios $(BOOTLOADER) -device loader,file=$(KERNEL_BIN),addr=$(KERNEL_ENTRY_PA) -s -S" && \ @@ -109,4 +104,4 @@ gdbserver: build 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 fs-img gdbserver gdbclient +.PHONY: build env kernel clean disasm disasm-vim run-inner fs-img gdbserver gdbclient fdt diff --git a/os/run-fdt.sh b/os/run-fdt.sh deleted file mode 100755 index c7c886d..0000000 --- a/os/run-fdt.sh +++ /dev/null @@ -1,11 +0,0 @@ -qemu-system-riscv64 -M 128m -machine virt,dumpdtb=virt.out \ --bios ../bootloader/rustsbi-qemu.bin \ --device loader,file=target/riscv64gc-unknown-none-elf/release/os.bin,addr=0x80200000 \ --drive file=../user/target/riscv64gc-unknown-none-elf/release/fs.img,if=none,format=raw,id=x0 \ --device virtio-blk-device,drive=x0 \ --device virtio-gpu-device \ --device virtio-keyboard-device \ --device virtio-mouse-device \ --serial stdio - -fdtdump virt.out \ No newline at end of file diff --git a/os/run-nodisp.sh b/os/run-nodisp.sh deleted file mode 100755 index 7f2a5bb..0000000 --- a/os/run-nodisp.sh +++ /dev/null @@ -1,10 +0,0 @@ -qemu-system-riscv64 -M 128m -machine virt \ --bios ../bootloader/rustsbi-qemu.bin \ --display none \ --device loader,file=target/riscv64gc-unknown-none-elf/release/os.bin,addr=0x80200000 \ --drive file=../user/target/riscv64gc-unknown-none-elf/release/fs.img,if=none,format=raw,id=x0 \ --device virtio-blk-device,drive=x0 \ --device virtio-gpu-device \ --device virtio-keyboard-device \ --device virtio-mouse-device \ --serial stdio diff --git a/os/run.sh b/os/run.sh deleted file mode 100755 index f9e96d6..0000000 --- a/os/run.sh +++ /dev/null @@ -1,9 +0,0 @@ -qemu-system-riscv64 -M 128m -machine virt \ --bios ../bootloader/rustsbi-qemu.bin \ --device loader,file=target/riscv64gc-unknown-none-elf/release/os.bin,addr=0x80200000 \ --drive file=../user/target/riscv64gc-unknown-none-elf/release/fs.img,if=none,format=raw,id=x0 \ --device virtio-blk-device,drive=x0 \ --device virtio-gpu-device \ --device virtio-keyboard-device \ --device virtio-mouse-device \ --serial stdio diff --git a/os/src/boards/qemu.rs b/os/src/boards/qemu.rs index 1dae9f3..ffabff6 100644 --- a/os/src/boards/qemu.rs +++ b/os/src/boards/qemu.rs @@ -14,6 +14,7 @@ pub const VIRT_PLIC: usize = 0xC00_0000; pub const VIRT_UART: usize = 0x1000_0000; pub const VIRTGPU_XRES: u32 = 1280; +#[allow(unused)] pub const VIRTGPU_YRES: u32 = 800; use crate::drivers::block::BLOCK_DEVICE; @@ -30,7 +31,7 @@ pub fn device_init() { plic.set_threshold(hart_id, supervisor, 0); plic.set_threshold(hart_id, machine, 1); //irq nums: 5 keyboard, 6 mouse, 8 block, 10 uart - for intr_src_id in [5usize, 6, 8 , 10] { + for intr_src_id in [5usize, 6, 8, 10] { plic.enable(hart_id, supervisor, intr_src_id); plic.set_priority(intr_src_id, 1); } diff --git a/os/src/drivers/block/virtio_blk.rs b/os/src/drivers/block/virtio_blk.rs index 2d853e0..fb89084 100644 --- a/os/src/drivers/block/virtio_blk.rs +++ b/os/src/drivers/block/virtio_blk.rs @@ -1,10 +1,10 @@ use super::BlockDevice; +use crate::drivers::bus::virtio::VirtioHal; use crate::sync::{Condvar, UPIntrFreeCell}; use crate::task::schedule; use crate::DEV_NON_BLOCKING_ACCESS; use alloc::collections::BTreeMap; use virtio_drivers::{BlkResp, RespStatus, VirtIOBlk, VirtIOHeader}; -use crate::drivers::bus::virtio::VirtioHal; #[allow(unused)] const VIRTIO0: usize = 0x10008000; @@ -69,7 +69,9 @@ impl BlockDevice for VirtIOBlock { impl VirtIOBlock { pub fn new() -> Self { let virtio_blk = unsafe { - UPIntrFreeCell::new(VirtIOBlk::::new(&mut *(VIRTIO0 as *mut VirtIOHeader)).unwrap()) + UPIntrFreeCell::new( + VirtIOBlk::::new(&mut *(VIRTIO0 as *mut VirtIOHeader)).unwrap(), + ) }; let mut condvars = BTreeMap::new(); let channels = virtio_blk.exclusive_access().virt_queue_size(); @@ -83,4 +85,3 @@ impl VirtIOBlock { } } } - diff --git a/os/src/drivers/bus/mod.rs b/os/src/drivers/bus/mod.rs index ab8f38f..d43f304 100644 --- a/os/src/drivers/bus/mod.rs +++ b/os/src/drivers/bus/mod.rs @@ -1 +1 @@ -pub mod virtio; \ No newline at end of file +pub mod virtio; diff --git a/os/src/drivers/bus/virtio.rs b/os/src/drivers/bus/virtio.rs index fe7bc12..6871eb8 100644 --- a/os/src/drivers/bus/virtio.rs +++ b/os/src/drivers/bus/virtio.rs @@ -1,9 +1,9 @@ -use alloc::vec::Vec; use crate::mm::{ frame_alloc, frame_dealloc, kernel_token, FrameTracker, PageTable, PhysAddr, PhysPageNum, StepByOne, VirtAddr, }; use crate::sync::UPIntrFreeCell; +use alloc::vec::Vec; use lazy_static::*; use virtio_drivers::Hal; @@ -49,4 +49,4 @@ impl Hal for VirtioHal { .unwrap() .0 } -} \ No newline at end of file +} diff --git a/os/src/drivers/gpu/mod.rs b/os/src/drivers/gpu/mod.rs index 2902821..759633f 100644 --- a/os/src/drivers/gpu/mod.rs +++ b/os/src/drivers/gpu/mod.rs @@ -1,30 +1,31 @@ +use crate::drivers::bus::virtio::VirtioHal; use crate::sync::UPIntrFreeCell; use alloc::{sync::Arc, vec::Vec}; use core::any::Any; use embedded_graphics::pixelcolor::Rgb888; use tinybmp::Bmp; use virtio_drivers::{VirtIOGpu, VirtIOHeader}; -use crate::drivers::bus::virtio::VirtioHal; const VIRTIO7: usize = 0x10007000; -pub trait GPUDevice: Send + Sync + Any { +pub trait GpuDevice: Send + Sync + Any { fn update_cursor(&self); - fn getfreambuffer(&self) -> &mut [u8]; + fn get_framebuffer(&self) -> &mut [u8]; fn flush(&self); } lazy_static::lazy_static!( - pub static ref GPU_DEVICE: Arc = Arc::new(VirtIOGPU::new()); + pub static ref GPU_DEVICE: Arc = Arc::new(VirtIOGpuWrapper::new()); ); -pub struct VirtIOGPU { +pub struct VirtIOGpuWrapper { gpu: UPIntrFreeCell>, fb: &'static [u8], } static BMP_DATA: &[u8] = include_bytes!("../../assert/mouse.bmp"); -impl VirtIOGPU { +impl VirtIOGpuWrapper { pub fn new() -> Self { unsafe { - let mut virtio = VirtIOGpu::::new(&mut *(VIRTIO7 as *mut VirtIOHeader)).unwrap(); + let mut virtio = + VirtIOGpu::::new(&mut *(VIRTIO7 as *mut VirtIOHeader)).unwrap(); let fbuffer = virtio.setup_framebuffer().unwrap(); let len = fbuffer.len(); @@ -53,11 +54,11 @@ impl VirtIOGPU { } } -impl GPUDevice for VirtIOGPU { +impl GpuDevice for VirtIOGpuWrapper { fn flush(&self) { self.gpu.exclusive_access().flush().unwrap(); } - fn getfreambuffer(&self) -> &mut [u8] { + fn get_framebuffer(&self) -> &mut [u8] { unsafe { let ptr = self.fb.as_ptr() as *const _ as *mut u8; core::slice::from_raw_parts_mut(ptr, self.fb.len()) diff --git a/os/src/drivers/input/mod.rs b/os/src/drivers/input/mod.rs index 1f2efc6..cbe8933 100644 --- a/os/src/drivers/input/mod.rs +++ b/os/src/drivers/input/mod.rs @@ -1,74 +1,75 @@ -use crate::{ - gui::{Button, Component}, - sync::UPIntrFreeCell, - syscall::PAD, -}; -use alloc::{string::ToString, sync::Arc}; -use core::any::Any; -use embedded_graphics::{ - prelude::{Point, Size}, - text::Text, -}; -use virtio_drivers::{VirtIOHeader, VirtIOInput}; use crate::drivers::bus::virtio::VirtioHal; +use crate::{ + gui::{move_rect, reset}, + sync::UPIntrFreeCell, +}; +use alloc::sync::Arc; +use core::any::Any; +use virtio_drivers::{VirtIOHeader, VirtIOInput}; use virtio_input_decoder::{Decoder, Key, KeyType}; -use super::GPU_DEVICE; - const VIRTIO5: usize = 0x10005000; const VIRTIO6: usize = 0x10006000; -struct VirtIOINPUT(UPIntrFreeCell>); +struct VirtIOInputWrapper(UPIntrFreeCell>); -pub trait INPUTDevice: Send + Sync + Any { +pub trait InputDevice: Send + Sync + Any { fn handle_irq(&self); } lazy_static::lazy_static!( - pub static ref KEYBOARD_DEVICE: Arc = Arc::new(VirtIOINPUT::new(VIRTIO5)); - pub static ref MOUSE_DEVICE: Arc = Arc::new(VirtIOINPUT::new(VIRTIO6)); + pub static ref KEYBOARD_DEVICE: Arc = Arc::new(VirtIOInputWrapper::new(VIRTIO5)); + pub static ref MOUSE_DEVICE: Arc = Arc::new(VirtIOInputWrapper::new(VIRTIO6)); ); -impl VirtIOINPUT { +impl VirtIOInputWrapper { pub fn new(addr: usize) -> Self { Self(unsafe { - UPIntrFreeCell::new(VirtIOInput::::new(&mut *(addr as *mut VirtIOHeader)).unwrap()) + UPIntrFreeCell::new( + VirtIOInput::::new(&mut *(addr as *mut VirtIOHeader)).unwrap(), + ) }) } } -impl INPUTDevice for VirtIOINPUT { +impl InputDevice for VirtIOInputWrapper { fn handle_irq(&self) { let mut input = self.0.exclusive_access(); input.ack_interrupt(); - let event = input.pop_pending_event().unwrap(); - let dtype = match Decoder::decode( - event.event_type as usize, - event.code as usize, - event.value as usize, - ) { - Ok(dtype) => dtype, - Err(_) => return, - }; - match dtype { - virtio_input_decoder::DecodeType::Key(key, r#type) => { - println!("{:?} {:?}", key, r#type); - if r#type == KeyType::Press { - let mut inner = PAD.exclusive_access(); - let a = inner.as_ref().unwrap(); - match key.to_char() { - Ok(mut k) => { - if k == '\r' { - a.repaint(k.to_string() + "\n") - } else { - a.repaint(k.to_string()) + while let Some(event) = input.pop_pending_event() { + let dtype = match Decoder::decode( + event.event_type as usize, + event.code as usize, + event.value as usize, + ) { + Ok(dtype) => dtype, + Err(_) => break, + }; + match dtype { + virtio_input_decoder::DecodeType::Key(key, r#type) => { + if r#type == KeyType::Press { + match key { + Key::C | Key::MouseLeft => { + reset(); } + Key::W => { + move_rect(0, -10); + } + Key::S => { + move_rect(0, 10); + } + Key::A => { + move_rect(-10, 0); + } + Key::D => { + move_rect(10, 0); + } + _ => {} } - Err(_) => {} } } + _ => {} } - virtio_input_decoder::DecodeType::Mouse(mouse) => println!("{:?}", mouse), } } } diff --git a/os/src/drivers/mod.rs b/os/src/drivers/mod.rs index a4cbfed..57a15f0 100644 --- a/os/src/drivers/mod.rs +++ b/os/src/drivers/mod.rs @@ -1,12 +1,12 @@ pub mod block; +pub mod bus; pub mod chardev; pub mod gpu; pub mod input; -pub mod bus; pub mod plic; pub use block::BLOCK_DEVICE; +pub use bus::*; pub use chardev::UART; pub use gpu::*; pub use input::*; -pub use bus::*; diff --git a/os/src/gui/button.rs b/os/src/gui/button.rs deleted file mode 100644 index dee2f7c..0000000 --- a/os/src/gui/button.rs +++ /dev/null @@ -1,79 +0,0 @@ -use alloc::{string::String, sync::Arc}; -use embedded_graphics::{ - mono_font::{ - ascii::{FONT_10X20, FONT_6X10}, - MonoTextStyle, - }, - pixelcolor::Rgb888, - prelude::{Dimensions, Point, Primitive, RgbColor, Size}, - primitives::{PrimitiveStyle, Rectangle}, - text::{Alignment, Text}, - Drawable, -}; - -use crate::{drivers::GPU_DEVICE, sync::UPIntrFreeCell}; - -use super::{Component, Graphics}; - -pub struct Button { - inner: UPIntrFreeCell, -} - -pub struct ButtonInner { - graphic: Graphics, - text: String, - parent: Option>, -} - -impl Button { - pub fn new(size: Size, point: Point, parent: Option>, text: String) -> Self { - let point = match &parent { - Some(p) => { - let (_, p) = p.bound(); - Point::new(p.x + point.x, p.y + point.y) - } - None => point, - }; - Self { - inner: unsafe { - UPIntrFreeCell::new(ButtonInner { - graphic: Graphics { - size, - point, - drv: GPU_DEVICE.clone(), - }, - text, - parent, - }) - }, - } - } -} - -impl Component for Button { - fn paint(&self) { - let mut inner = self.inner.exclusive_access(); - let text = inner.text.clone(); - Text::with_alignment( - text.as_str(), - inner.graphic.bounding_box().center(), - MonoTextStyle::new(&FONT_10X20, Rgb888::BLACK), - Alignment::Center, - ) - .draw(&mut inner.graphic); - } - - fn add(&self, comp: alloc::sync::Arc) { - unreachable!() - } - - fn bound( - &self, - ) -> ( - embedded_graphics::prelude::Size, - embedded_graphics::prelude::Point, - ) { - let inner = self.inner.exclusive_access(); - (inner.graphic.size, inner.graphic.point) - } -} diff --git a/os/src/gui/graphic.rs b/os/src/gui/graphic.rs index cda7520..d13ad61 100644 --- a/os/src/gui/graphic.rs +++ b/os/src/gui/graphic.rs @@ -5,14 +5,14 @@ use embedded_graphics::{ prelude::{OriginDimensions, Point, RgbColor, Size}, }; -use crate::drivers::{GPUDevice, GPU_DEVICE,}; -use crate::board::{VIRTGPU_XRES, VIRTGPU_YRES}; +use crate::board::VIRTGPU_XRES; +use crate::drivers::{GpuDevice, GPU_DEVICE}; #[derive(Clone)] pub struct Graphics { pub size: Size, pub point: Point, - pub drv: Arc, + pub drv: Arc, } impl Graphics { @@ -23,6 +23,10 @@ impl Graphics { drv: GPU_DEVICE.clone(), } } + pub fn reset(&self) { + let fb = self.drv.get_framebuffer(); + fb.fill(0u8); + } } impl OriginDimensions for Graphics { @@ -40,10 +44,12 @@ impl DrawTarget for Graphics { where I: IntoIterator>, { - let fb = self.drv.getfreambuffer(); + let fb = self.drv.get_framebuffer(); pixels.into_iter().for_each(|px| { - let idx = ((self.point.y + px.0.y) * VIRTGPU_XRES as i32 + self.point.x + px.0.x) as usize * 4; + let idx = ((self.point.y + px.0.y) * VIRTGPU_XRES as i32 + self.point.x + px.0.x) + as usize + * 4; if idx + 2 >= fb.len() { return; } diff --git a/os/src/gui/icon.rs b/os/src/gui/icon.rs deleted file mode 100644 index 8d78470..0000000 --- a/os/src/gui/icon.rs +++ /dev/null @@ -1,79 +0,0 @@ -use alloc::{string::String, sync::Arc, vec::Vec}; -use embedded_graphics::{ - image::Image, - mono_font::{ascii::FONT_10X20, iso_8859_13::FONT_6X12, MonoTextStyle}, - pixelcolor::Rgb888, - prelude::{Point, RgbColor, Size}, - text::Text, - Drawable, -}; -use tinybmp::Bmp; - -use crate::{drivers::GPU_DEVICE, sync::UPIntrFreeCell}; -use crate::board::{VIRTGPU_XRES, VIRTGPU_YRES}; -use super::{Component, Graphics, ImageComp}; - -static FILEICON: &[u8] = include_bytes!("../assert/file.bmp"); - -pub struct IconController { - inner: UPIntrFreeCell, -} - -pub struct IconControllerInner { - files: Vec, - graphic: Graphics, - parent: Option>, -} - -impl IconController { - pub fn new(files: Vec, parent: Option>) -> Self { - IconController { - inner: unsafe { - UPIntrFreeCell::new(IconControllerInner { - files, - graphic: Graphics { - size: Size::new(VIRTGPU_XRES, VIRTGPU_YRES), - point: Point::new(0, 0), - drv: GPU_DEVICE.clone(), - }, - parent, - }) - }, - } - } -} - -impl Component for IconController { - fn paint(&self) { - println!("demo"); - let mut inner = self.inner.exclusive_access(); - let mut x = 10; - let mut y = 10; - let v = inner.files.clone(); - for file in v { - println!("file"); - let bmp = Bmp::::from_slice(FILEICON).unwrap(); - Image::new(&bmp, Point::new(x, y)).draw(&mut inner.graphic); - let text = Text::new( - file.as_str(), - Point::new(x + 20, y + 80), - MonoTextStyle::new(&FONT_10X20, Rgb888::BLACK), - ); - text.draw(&mut inner.graphic); - if y >= 600 { - x = x + 70; - y = 10; - } else { - y = y + 90; - } - } - } - - fn add(&self, comp: Arc) { - todo!() - } - - fn bound(&self) -> (Size, Point) { - todo!() - } -} diff --git a/os/src/gui/image.rs b/os/src/gui/image.rs deleted file mode 100644 index aac5829..0000000 --- a/os/src/gui/image.rs +++ /dev/null @@ -1,80 +0,0 @@ -use alloc::{sync::Arc, vec::Vec}; -use embedded_graphics::{ - image::Image, - pixelcolor::Rgb888, - prelude::{Point, Size}, - Drawable, -}; -use tinybmp::Bmp; - -use crate::{ - drivers::{BLOCK_DEVICE, GPU_DEVICE}, - sync::UPIntrFreeCell, -}; - -use super::{Component, Graphics}; - -pub struct ImageComp { - inner: UPIntrFreeCell, -} - -pub struct ImageInner { - image: &'static [u8], - graphic: Graphics, - parent: Option>, -} - -impl ImageComp { - pub fn new( - size: Size, - point: Point, - v: &'static [u8], - parent: Option>, - ) -> Self { - unsafe { - ImageComp { - inner: UPIntrFreeCell::new(ImageInner { - parent, - image: v, - graphic: Graphics { - size, - point, - drv: GPU_DEVICE.clone(), - }, - }), - } - } - } -} - -impl Component for ImageComp { - fn paint(&self) { - let mut inner = self.inner.exclusive_access(); - let b = unsafe { - let len = inner.image.len(); - let ptr = inner.image.as_ptr() as *const u8; - core::slice::from_raw_parts(ptr, len) - }; - let bmp = Bmp::::from_slice(b).unwrap(); - let point = match &inner.parent { - Some(parent) => { - let (_, point) = parent.bound(); - Point::new( - point.x + inner.graphic.point.x, - point.y + inner.graphic.point.y, - ) - } - None => inner.graphic.point, - }; - Image::new(&bmp, point).draw(&mut inner.graphic); - } - - fn add(&self, comp: alloc::sync::Arc) { - todo!() - } - - fn bound(&self) -> (Size, Point) { - let inner = self.inner.exclusive_access(); - (inner.graphic.size, inner.graphic.point) - } -} diff --git a/os/src/gui/mod.rs b/os/src/gui/mod.rs index f702aa0..766ded8 100644 --- a/os/src/gui/mod.rs +++ b/os/src/gui/mod.rs @@ -1,22 +1,5 @@ -mod button; mod graphic; -mod icon; -mod image; -mod panel; -mod terminal; +mod paint; -use alloc::sync::Arc; -pub use button::*; -use core::any::Any; -use embedded_graphics::prelude::{Point, Size}; -pub use graphic::*; -pub use icon::*; -pub use image::*; -pub use panel::*; -pub use terminal::*; - -pub trait Component: Send + Sync + Any { - fn paint(&self); - fn add(&self, comp: Arc); - fn bound(&self) -> (Size, Point); -} +use graphic::Graphics; +pub use paint::{init_paint, move_rect, reset}; diff --git a/os/src/gui/paint.rs b/os/src/gui/paint.rs new file mode 100644 index 0000000..0cdf60d --- /dev/null +++ b/os/src/gui/paint.rs @@ -0,0 +1,62 @@ +use super::Graphics; +use crate::sync::UPIntrFreeCell; +use embedded_graphics::pixelcolor::Rgb888; +use embedded_graphics::prelude::{Drawable, Point, RgbColor, Size}; +use embedded_graphics::primitives::Primitive; +use embedded_graphics::primitives::{PrimitiveStyle, Rectangle}; +use lazy_static::*; + +const INIT_X: i32 = 640; +const INIT_Y: i32 = 400; +const RECT_SIZE: u32 = 40; + +pub struct DrawingBoard { + graphics: Graphics, + latest_pos: Point, +} + +impl DrawingBoard { + pub fn new() -> Self { + Self { + graphics: Graphics::new(Size::new(1280, 800), Point::new(0, 0)), + latest_pos: Point::new(INIT_X, INIT_Y), + } + } + fn paint(&mut self) { + Rectangle::with_center(self.latest_pos, Size::new(RECT_SIZE, RECT_SIZE)) + .into_styled(PrimitiveStyle::with_stroke(Rgb888::WHITE, 1)) + .draw(&mut self.graphics) + .ok(); + } + pub fn move_rect(&mut self, dx: i32, dy: i32) { + self.latest_pos.x += dx; + self.latest_pos.y += dy; + self.paint(); + } + pub fn reset(&mut self) { + self.latest_pos = Point::new(INIT_X, INIT_Y); + self.graphics.reset(); + } +} + +lazy_static! { + pub static ref DRAWING_BOARD: UPIntrFreeCell = unsafe { UPIntrFreeCell::new(DrawingBoard::new()) }; +} + +pub fn init_paint() { + DRAWING_BOARD.exclusive_session(|ripple| { + ripple.paint(); + }); +} + +pub fn move_rect(dx: i32, dy: i32) { + DRAWING_BOARD.exclusive_session(|ripple| { + ripple.move_rect(dx, dy); + }); +} + +pub fn reset() { + DRAWING_BOARD.exclusive_session(|ripple| { + ripple.reset(); + }); +} diff --git a/os/src/gui/panel.rs b/os/src/gui/panel.rs deleted file mode 100644 index 2af2961..0000000 --- a/os/src/gui/panel.rs +++ /dev/null @@ -1,66 +0,0 @@ -use alloc::{collections::VecDeque, rc::Weak, sync::Arc}; -use embedded_graphics::{ - pixelcolor::Rgb888, - prelude::{Point, Primitive, RgbColor, Size}, - primitives::{PrimitiveStyle, Rectangle}, - Drawable, -}; - -use crate::{drivers::GPU_DEVICE, sync::UPIntrFreeCell}; - -use super::{Component, Graphics}; - -pub struct Panel { - inner: UPIntrFreeCell, -} -struct PanelInner { - graphic: Graphics, - comps: VecDeque>, -} - -impl Panel { - pub fn new(size: Size, point: Point) -> Self { - Self { - inner: unsafe { - UPIntrFreeCell::new(PanelInner { - graphic: Graphics { - size, - point, - drv: GPU_DEVICE.clone(), - }, - comps: VecDeque::new(), - }) - }, - } - } -} - -impl Component for Panel { - fn paint(&self) { - let mut inner = self.inner.exclusive_access(); - - Rectangle::new(Point::new(0, 0), inner.graphic.size) - .into_styled(PrimitiveStyle::with_fill(Rgb888::WHITE)) - .draw(&mut inner.graphic) - .unwrap(); - - let len = inner.comps.len(); - drop(inner); - for i in 0..len { - let mut inner = self.inner.exclusive_access(); - let comp = Arc::downgrade(&inner.comps[i]); - drop(inner); - comp.upgrade().unwrap().paint(); - } - } - - fn add(&self, comp: alloc::sync::Arc) { - let mut inner = self.inner.exclusive_access(); - inner.comps.push_back(comp); - } - - fn bound(&self) -> (Size, Point) { - let inner = self.inner.exclusive_access(); - (inner.graphic.size, inner.graphic.point) - } -} diff --git a/os/src/gui/terminal.rs b/os/src/gui/terminal.rs deleted file mode 100644 index 8d233f5..0000000 --- a/os/src/gui/terminal.rs +++ /dev/null @@ -1,105 +0,0 @@ -use alloc::{ - collections::VecDeque, - string::{String, ToString}, - sync::Arc, -}; -use embedded_graphics::{ - mono_font::{ascii::FONT_10X20, MonoTextStyle}, - pixelcolor::Rgb888, - prelude::{Dimensions, Point, Primitive, RgbColor, Size}, - primitives::{PrimitiveStyle, Rectangle}, - text::{Alignment, Text}, - Drawable, -}; - -use crate::{drivers::GPU_DEVICE, sync::UPIntrFreeCell}; - -use super::{button::Button, Component, Graphics, Panel}; - -pub struct Terminal { - inner: UPIntrFreeCell, -} - -pub struct TerminalInner { - pub text: String, - titel: Option, - graphic: Graphics, - comps: VecDeque>, -} - -impl Terminal { - pub fn new( - size: Size, - point: Point, - parent: Option>, - titel: Option, - text: String, - ) -> Self { - Self { - inner: unsafe { - UPIntrFreeCell::new(TerminalInner { - text, - titel, - graphic: Graphics { - size, - point, - drv: GPU_DEVICE.clone(), - }, - comps: VecDeque::new(), - }) - }, - } - } - - pub fn repaint(&self, text: String) { - let mut inner = self.inner.exclusive_access(); - inner.text += text.as_str(); - Text::with_alignment( - inner.text.clone().as_str(), - Point::new(20, 50), - MonoTextStyle::new(&FONT_10X20, Rgb888::BLACK), - Alignment::Left, - ) - .draw(&mut inner.graphic); - } -} - -impl Component for Terminal { - fn paint(&self) { - let mut inner = self.inner.exclusive_access(); - let len = inner.comps.len(); - drop(inner); - for i in 0..len { - let mut inner = self.inner.exclusive_access(); - let comp = Arc::downgrade(&inner.comps[i]); - drop(inner); - comp.upgrade().unwrap().paint(); - } - let mut inner = self.inner.exclusive_access(); - let titel = inner.titel.get_or_insert("No Titel".to_string()).clone(); - let text = Text::new( - titel.as_str(), - Point::new(20, 20), - MonoTextStyle::new(&FONT_10X20, Rgb888::BLACK), - ); - text.draw(&mut inner.graphic); - - Text::with_alignment( - inner.text.clone().as_str(), - Point::new(20, 50), - MonoTextStyle::new(&FONT_10X20, Rgb888::BLACK), - Alignment::Left, - ) - .draw(&mut inner.graphic); - } - - fn add(&self, comp: Arc) { - let mut inner = self.inner.exclusive_access(); - inner.comps.push_back(comp); - } - - fn bound(&self) -> (Size, Point) { - let inner = self.inner.exclusive_access(); - (inner.graphic.size, inner.graphic.point) - } -} diff --git a/os/src/main.rs b/os/src/main.rs index ce7dcc1..299e4cf 100644 --- a/os/src/main.rs +++ b/os/src/main.rs @@ -28,7 +28,7 @@ mod task; mod timer; mod trap; -// use syscall::create_desktop; //for test +//use syscall::create_desktop; //for test core::arch::global_asm!(include_str!("entry.asm")); @@ -56,18 +56,18 @@ pub fn rust_main() -> ! { clear_bss(); mm::init(); println!("KERN: init gpu"); - GPU_DEVICE.clone(); + let _gpu = GPU_DEVICE.clone(); println!("KERN: init keyboard"); - KEYBOARD_DEVICE.clone(); + let _keyboard = KEYBOARD_DEVICE.clone(); println!("KERN: init mouse"); - MOUSE_DEVICE.clone(); + let _mouse = MOUSE_DEVICE.clone(); println!("KERN: init trap"); trap::init(); trap::enable_timer_interrupt(); timer::set_next_trigger(); board::device_init(); fs::list_apps(); - //syscall::create_desktop(); //for test + gui::init_paint(); task::add_initproc(); *DEV_NON_BLOCKING_ACCESS.exclusive_access() = true; task::run_tasks(); diff --git a/os/src/mm/frame_allocator.rs b/os/src/mm/frame_allocator.rs index 3c62324..1ecfe99 100644 --- a/os/src/mm/frame_allocator.rs +++ b/os/src/mm/frame_allocator.rs @@ -48,7 +48,7 @@ impl StackFrameAllocator { pub fn init(&mut self, l: PhysPageNum, r: PhysPageNum) { self.current = l.0; self.end = r.0; - println!("last {} Physical Frames.", self.end - self.current); + // println!("last {} Physical Frames.", self.end - self.current); } } impl FrameAllocator for StackFrameAllocator { diff --git a/os/src/mm/memory_set.rs b/os/src/mm/memory_set.rs index 0862dc7..663b68d 100644 --- a/os/src/mm/memory_set.rs +++ b/os/src/mm/memory_set.rs @@ -92,14 +92,14 @@ impl MemorySet { // map trampoline memory_set.map_trampoline(); // map kernel sections - println!(".text [{:#x}, {:#x})", stext as usize, etext as usize); - println!(".rodata [{:#x}, {:#x})", srodata as usize, erodata as usize); - println!(".data [{:#x}, {:#x})", sdata as usize, edata as usize); - println!( - ".bss [{:#x}, {:#x})", - sbss_with_stack as usize, ebss as usize - ); - println!("mapping .text section"); + // println!(".text [{:#x}, {:#x})", stext as usize, etext as usize); + // println!(".rodata [{:#x}, {:#x})", srodata as usize, erodata as usize); + // println!(".data [{:#x}, {:#x})", sdata as usize, edata as usize); + // println!( + // ".bss [{:#x}, {:#x})", + // sbss_with_stack as usize, ebss as usize + // ); + // println!("mapping .text section"); memory_set.push( MapArea::new( (stext as usize).into(), @@ -109,7 +109,7 @@ impl MemorySet { ), None, ); - println!("mapping .rodata section"); + // println!("mapping .rodata section"); memory_set.push( MapArea::new( (srodata as usize).into(), @@ -119,7 +119,7 @@ impl MemorySet { ), None, ); - println!("mapping .data section"); + // println!("mapping .data section"); memory_set.push( MapArea::new( (sdata as usize).into(), @@ -129,7 +129,7 @@ impl MemorySet { ), None, ); - println!("mapping .bss section"); + // println!("mapping .bss section"); memory_set.push( MapArea::new( (sbss_with_stack as usize).into(), @@ -139,7 +139,7 @@ impl MemorySet { ), None, ); - println!("mapping physical memory"); + // println!("mapping physical memory"); memory_set.push( MapArea::new( (ekernel as usize).into(), @@ -149,7 +149,7 @@ impl MemorySet { ), None, ); - println!("mapping memory-mapped registers"); + //println!("mapping memory-mapped registers"); for pair in MMIO { memory_set.push( MapArea::new( diff --git a/os/src/syscall/gui.rs b/os/src/syscall/gui.rs deleted file mode 100644 index 82c42af..0000000 --- a/os/src/syscall/gui.rs +++ /dev/null @@ -1,63 +0,0 @@ -use alloc::{string::ToString, sync::Arc, vec::Vec}; -use embedded_graphics::{ - prelude::{Point, Size}, - primitives::arc, -}; - -use crate::{ - fs::ROOT_INODE, - gui::{Button, Component, IconController, ImageComp, Panel, Terminal}, - sync::UPIntrFreeCell, -}; - -use crate::board::{VIRTGPU_XRES, VIRTGPU_YRES}; - -static DT: &[u8] = include_bytes!("../assert/desktop.bmp"); - -lazy_static::lazy_static!( - pub static ref DESKTOP:UPIntrFreeCell> = unsafe { - UPIntrFreeCell::new(Arc::new(Panel::new(Size::new(VIRTGPU_XRES, VIRTGPU_YRES), Point::new(0, 0)))) - }; - pub static ref PAD:UPIntrFreeCell>> = unsafe { - UPIntrFreeCell::new(None) - }; -); - -pub fn create_desktop() -> isize { - let mut p: Arc = - Arc::new(Panel::new(Size::new(VIRTGPU_XRES, VIRTGPU_YRES), Point::new(0, 0))); - let image = ImageComp::new(Size::new(VIRTGPU_XRES, VIRTGPU_YRES), Point::new(0, 0), DT, Some(p.clone())); - let icon = IconController::new(ROOT_INODE.ls(), Some(p.clone())); - p.add(Arc::new(image)); - p.add(Arc::new(icon)); - let mut desktop = DESKTOP.exclusive_access(); - *desktop = p; - desktop.paint(); - drop(desktop); - create_terminal(); - 1 -} - -pub fn create_terminal() { - let desktop = DESKTOP.exclusive_access(); - let arc_t = Arc::new(Terminal::new( - Size::new(400, 400), - Point::new(200, 100), - Some(desktop.clone()), - Some("demo.txt".to_string()), - "".to_string(), - )); - let text = Panel::new(Size::new(400, 400), Point::new(200, 100)); - let button = Button::new( - Size::new(20, 20), - Point::new(370, 10), - Some(arc_t.clone()), - "X".to_string(), - ); - arc_t.add(Arc::new(text)); - arc_t.add(Arc::new(button)); - arc_t.paint(); - desktop.add(arc_t.clone()); - let mut pad = PAD.exclusive_access(); - *pad = Some(arc_t); -} diff --git a/os/src/syscall/mod.rs b/os/src/syscall/mod.rs index dccb73b..fa4a4cf 100644 --- a/os/src/syscall/mod.rs +++ b/os/src/syscall/mod.rs @@ -25,16 +25,13 @@ const SYSCALL_SEMAPHORE_DOWN: usize = 1022; const SYSCALL_CONDVAR_CREATE: usize = 1030; const SYSCALL_CONDVAR_SIGNAL: usize = 1031; const SYSCALL_CONDVAR_WAIT: usize = 1032; -const SYSCALL_CREATE_DESKTOP: usize = 2000; + mod fs; -mod gui; mod process; mod sync; mod thread; -pub use self::gui::create_desktop; -use fs::*; -pub use gui::PAD; +use fs::*; use process::*; use sync::*; use thread::*; @@ -68,8 +65,6 @@ pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize { SYSCALL_CONDVAR_CREATE => sys_condvar_create(args[0]), SYSCALL_CONDVAR_SIGNAL => sys_condvar_signal(args[0]), SYSCALL_CONDVAR_WAIT => sys_condvar_wait(args[0], args[1]), - SYSCALL_CREATE_DESKTOP => create_desktop(), _ => panic!("Unsupported syscall_id: {}", syscall_id), } } - diff --git a/os/src/timer.rs b/os/src/timer.rs index 06a70de..7be2d01 100644 --- a/os/src/timer.rs +++ b/os/src/timer.rs @@ -61,13 +61,14 @@ pub fn add_timer(expire_ms: usize, task: Arc) { pub fn check_timer() { let current_ms = get_time_ms(); - let mut timers = TIMERS.exclusive_access(); - while let Some(timer) = timers.peek() { - if timer.expire_ms <= current_ms { - add_task(Arc::clone(&timer.task)); - timers.pop(); - } else { - break; + TIMERS.exclusive_session(|timers| { + while let Some(timer) = timers.peek() { + if timer.expire_ms <= current_ms { + add_task(Arc::clone(&timer.task)); + timers.pop(); + } else { + break; + } } - } + }); } diff --git a/os/src/trap/mod.rs b/os/src/trap/mod.rs index ce2aae8..cb4a7ad 100644 --- a/os/src/trap/mod.rs +++ b/os/src/trap/mod.rs @@ -61,7 +61,7 @@ pub fn trap_handler() -> ! { set_kernel_trap_entry(); let scause = scause::read(); let stval = stval::read(); - //println!("into {:?}", scause.cause()); + // println!("into {:?}", scause.cause()); match scause.cause() { Trap::Exception(Exception::UserEnvCall) => { // jump to next instruction anyway diff --git a/user/src/bin/gui.rs b/user/src/bin/gui.rs deleted file mode 100644 index e3f7ec2..0000000 --- a/user/src/bin/gui.rs +++ /dev/null @@ -1,19 +0,0 @@ -#![no_std] -#![no_main] - -use user_lib::create_desktop; - -#[macro_use] -extern crate user_lib; - - - -#[no_mangle] -pub fn main() -> i32 { - println!("gui"); - create_desktop(); - println!("exit pass."); - loop{} - 0 -} - diff --git a/user/src/bin/huge_write_mt.rs b/user/src/bin/huge_write_mt.rs index 8ca7578..0a60fd8 100644 --- a/user/src/bin/huge_write_mt.rs +++ b/user/src/bin/huge_write_mt.rs @@ -5,7 +5,7 @@ extern crate user_lib; extern crate alloc; -use alloc::{fmt::format, string::String, vec::Vec}; +use alloc::{fmt::format, vec::Vec}; use user_lib::{close, get_time, gettid, open, write, OpenFlags}; use user_lib::{exit, thread_create, waittid}; diff --git a/user/src/bin/peterson.rs b/user/src/bin/peterson.rs index 5551997..089841d 100644 --- a/user/src/bin/peterson.rs +++ b/user/src/bin/peterson.rs @@ -1,7 +1,6 @@ #![no_std] #![no_main] #![feature(core_intrinsics)] -#![feature(asm)] #[macro_use] extern crate user_lib; diff --git a/user/src/lib.rs b/user/src/lib.rs index 6f57edd..729eaef 100644 --- a/user/src/lib.rs +++ b/user/src/lib.rs @@ -198,9 +198,7 @@ pub fn condvar_signal(condvar_id: usize) { pub fn condvar_wait(condvar_id: usize, mutex_id: usize) { sys_condvar_wait(condvar_id, mutex_id); } -pub fn create_desktop() { - sys_create_desktop(); -} + #[macro_export] macro_rules! vstore { ($var_ref: expr, $value: expr) => { diff --git a/user/src/syscall.rs b/user/src/syscall.rs index 3f36f53..b4bb67a 100644 --- a/user/src/syscall.rs +++ b/user/src/syscall.rs @@ -154,6 +154,3 @@ pub fn sys_condvar_signal(condvar_id: usize) -> isize { pub fn sys_condvar_wait(condvar_id: usize, mutex_id: usize) -> isize { syscall(SYSCALL_CONDVAR_WAIT, [condvar_id, mutex_id, 0]) } -pub fn sys_create_desktop() -> isize { - syscall(2000, [0, 0, 0]) -} \ No newline at end of file From 728b6e58196767e85fd6fa12d8454aab169f67b5 Mon Sep 17 00:00:00 2001 From: Yifan Wu Date: Mon, 19 Dec 2022 04:48:45 -0800 Subject: [PATCH 18/68] Remove a dependency --- os/Cargo.toml | 2 -- 1 file changed, 2 deletions(-) diff --git a/os/Cargo.toml b/os/Cargo.toml index b9ac5b8..f4b2d80 100644 --- a/os/Cargo.toml +++ b/os/Cargo.toml @@ -18,8 +18,6 @@ easy-fs = { path = "../easy-fs" } virtio-input-decoder = "0.1.4" embedded-graphics = "0.7.1" tinybmp = "0.3.1" -embedded-term = { git = "https://github.com/rcore-os/embedded-term" } - [profile.release] debug = true From b45dd60594089d36127abdbb4a93461d824a285a Mon Sep 17 00:00:00 2001 From: Yifan Wu Date: Wed, 21 Dec 2022 11:11:50 +0800 Subject: [PATCH 19/68] Add coroutine examples --- user/src/bin/stackful_coroutine.rs | 349 ++++++++++++++++++++++++++++ user/src/bin/stackless_coroutine.rs | 129 ++++++++++ 2 files changed, 478 insertions(+) create mode 100644 user/src/bin/stackful_coroutine.rs create mode 100644 user/src/bin/stackless_coroutine.rs diff --git a/user/src/bin/stackful_coroutine.rs b/user/src/bin/stackful_coroutine.rs new file mode 100644 index 0000000..83eceb7 --- /dev/null +++ b/user/src/bin/stackful_coroutine.rs @@ -0,0 +1,349 @@ +// we porting below codes to Rcore Tutorial v3 +// https://cfsamson.gitbook.io/green-threads-explained-in-200-lines-of-rust/ +// https://github.com/cfsamson/example-greenthreads +#![no_std] +#![no_main] +#![feature(naked_functions)] +#![feature(asm)] + +extern crate alloc; +#[macro_use] +extern crate user_lib; + +use core::arch::asm; + +#[macro_use] +use alloc::vec; +use alloc::vec::Vec; + +use user_lib::exit; + +// In our simple example we set most constraints here. +const DEFAULT_STACK_SIZE: usize = 4096; //128 got SEGFAULT, 256(1024, 4096) got right results. +const MAX_TASKS: usize = 5; +static mut RUNTIME: usize = 0; + +pub struct Runtime { + tasks: Vec, + current: usize, +} + +#[derive(PartialEq, Eq, Debug)] +enum State { + Available, + Running, + Ready, +} + +struct Task { + id: usize, + stack: Vec, + ctx: TaskContext, + state: State, +} + +#[derive(Debug, Default)] +#[repr(C)] // not strictly needed but Rust ABI is not guaranteed to be stable +pub struct TaskContext { + // 15 u64 + x1: u64, //ra: return addres + x2: u64, //sp + x8: u64, //s0,fp + x9: u64, //s1 + x18: u64, //x18-27: s2-11 + x19: u64, + x20: u64, + x21: u64, + x22: u64, + x23: u64, + x24: u64, + x25: u64, + x26: u64, + x27: u64, + nx1: u64, //new return addres +} + +impl Task { + fn new(id: usize) -> Self { + // We initialize each task here and allocate the stack. This is not neccesary, + // we can allocate memory for it later, but it keeps complexity down and lets us focus on more interesting parts + // to do it here. The important part is that once allocated it MUST NOT move in memory. + Task { + id, + stack: vec![0_u8; DEFAULT_STACK_SIZE], + ctx: TaskContext::default(), + state: State::Available, + } + } +} + +impl Runtime { + pub fn new() -> Self { + // This will be our base task, which will be initialized in the `running` state + let base_task = Task { + id: 0, + stack: vec![0_u8; DEFAULT_STACK_SIZE], + ctx: TaskContext::default(), + state: State::Running, + }; + + // We initialize the rest of our tasks. + let mut tasks = vec![base_task]; + let mut available_tasks: Vec = (1..MAX_TASKS).map(|i| Task::new(i)).collect(); + tasks.append(&mut available_tasks); + + Runtime { tasks, current: 0 } + } + + /// This is cheating a bit, but we need a pointer to our Runtime stored so we can call yield on it even if + /// we don't have a reference to it. + pub fn init(&self) { + unsafe { + let r_ptr: *const Runtime = self; + RUNTIME = r_ptr as usize; + } + } + + /// This is where we start running our runtime. If it is our base task, we call yield until + /// it returns false (which means that there are no tasks scheduled) and we are done. + pub fn run(&mut self) { + while self.t_yield() {} + println!("All tasks finished!"); + } + + /// This is our return function. The only place we use this is in our `guard` function. + /// If the current task is not our base task we set its state to Available. It means + /// we're finished with it. Then we yield which will schedule a new task to be run. + fn t_return(&mut self) { + if self.current != 0 { + self.tasks[self.current].state = State::Available; + self.t_yield(); + } + } + + /// This is the heart of our runtime. Here we go through all tasks and see if anyone is in the `Ready` state. + /// If no task is `Ready` we're all done. This is an extremely simple scheduler using only a round-robin algorithm. + /// + /// If we find a task that's ready to be run we change the state of the current task from `Running` to `Ready`. + /// Then we call switch which will save the current context (the old context) and load the new context + /// into the CPU which then resumes based on the context it was just passed. + /// + /// NOITCE: if we comment below `#[inline(never)]`, we can not get the corrent running result + #[inline(never)] + fn t_yield(&mut self) -> bool { + let mut pos = self.current; + while self.tasks[pos].state != State::Ready { + pos += 1; + if pos == self.tasks.len() { + pos = 0; + } + if pos == self.current { + return false; + } + } + + if self.tasks[self.current].state != State::Available { + self.tasks[self.current].state = State::Ready; + } + + self.tasks[pos].state = State::Running; + let old_pos = self.current; + self.current = pos; + + unsafe { + switch(&mut self.tasks[old_pos].ctx, &self.tasks[pos].ctx); + } + + // NOTE: this might look strange and it is. Normally we would just mark this as `unreachable!()` but our compiler + // is too smart for it's own good so it optimized our code away on release builds. Curiously this happens on windows + // and not on linux. This is a common problem in tests so Rust has a `black_box` function in the `test` crate that + // will "pretend" to use a value we give it to prevent the compiler from eliminating code. I'll just do this instead, + // this code will never be run anyways and if it did it would always be `true`. + self.tasks.len() > 0 + } + + /// While `yield` is the logically interesting function I think this the technically most interesting. + /// + /// When we spawn a new task we first check if there are any available tasks (tasks in `Parked` state). + /// If we run out of tasks we panic in this scenario but there are several (better) ways to handle that. + /// We keep things simple for now. + /// + /// When we find an available task we get the stack length and a pointer to our u8 bytearray. + /// + /// The next part we have to use some unsafe functions. First we write an address to our `guard` function + /// that will be called if the function we provide returns. Then we set the address to the function we + /// pass inn. + /// + /// Third, we set the value of `sp` which is the stack pointer to the address of our provided function so we start + /// executing that first when we are scheuled to run. + /// + /// Lastly we set the state as `Ready` which means we have work to do and is ready to do it. + pub fn spawn(&mut self, f: fn()) { + let available = self + .tasks + .iter_mut() + .find(|t| t.state == State::Available) + .expect("no available task."); + + let size = available.stack.len(); + unsafe { + let s_ptr = available.stack.as_mut_ptr().offset(size as isize); + + // make sure our stack itself is 8 byte aligned - it will always + // offset to a lower memory address. Since we know we're at the "high" + // memory address of our allocated space, we know that offsetting to + // a lower one will be a valid address (given that we actually allocated) + // enough space to actually get an aligned pointer in the first place). + let s_ptr = (s_ptr as usize & !7) as *mut u8; + + available.ctx.x1 = guard as u64; //ctx.x1 is old return address + available.ctx.nx1 = f as u64; //ctx.nx2 is new return address + available.ctx.x2 = s_ptr.offset(-32) as u64; //cxt.x2 is sp + } + available.state = State::Ready; + } +} + +/// This is our guard function that we place on top of the stack. All this function does is set the +/// state of our current task and then `yield` which will then schedule a new task to be run. +fn guard() { + unsafe { + let rt_ptr = RUNTIME as *mut Runtime; + (*rt_ptr).t_return(); + }; +} + +/// We know that Runtime is alive the length of the program and that we only access from one core +/// (so no datarace). We yield execution of the current task by dereferencing a pointer to our +/// Runtime and then calling `t_yield` +pub fn yield_task() { + unsafe { + let rt_ptr = RUNTIME as *mut Runtime; + (*rt_ptr).t_yield(); + }; +} + +/// So here is our inline Assembly. As you remember from our first example this is just a bit more elaborate where we first +/// read out the values of all the registers we need and then sets all the register values to the register values we +/// saved when we suspended exceution on the "new" task. +/// +/// This is essentially all we need to do to save and resume execution. +/// +/// Some details about inline assembly. +/// +/// The assembly commands in the string literal is called the assemblt template. It is preceeded by +/// zero or up to four segments indicated by ":": +/// +/// - First ":" we have our output parameters, this parameters that this function will return. +/// - Second ":" we have the input parameters which is our contexts. We only read from the "new" context +/// but we modify the "old" context saving our registers there (see volatile option below) +/// - Third ":" This our clobber list, this is information to the compiler that these registers can't be used freely +/// - Fourth ":" This is options we can pass inn, Rust has 3: "alignstack", "volatile" and "intel" +/// +/// For this to work on windows we need to use "alignstack" where the compiler adds the neccesary padding to +/// make sure our stack is aligned. Since we modify one of our inputs, our assembly has "side effects" +/// therefore we should use the `volatile` option. I **think** this is actually set for us by default +/// when there are no output parameters given (my own assumption after going through the source code) +/// for the `asm` macro, but we should make it explicit anyway. +/// +/// One last important part (it will not work without this) is the #[naked] attribute. Basically this lets us have full +/// control over the stack layout since normal functions has a prologue-and epilogue added by the +/// compiler that will cause trouble for us. We avoid this by marking the funtion as "Naked". +/// For this to work on `release` builds we also need to use the `#[inline(never)] attribute or else +/// the compiler decides to inline this function (curiously this currently only happens on Windows). +/// If the function is inlined we get a curious runtime error where it fails when switching back +/// to as saved context and in general our assembly will not work as expected. +/// +/// see: https://github.com/rust-lang/rfcs/blob/master/text/1201-naked-fns.md +/// see: https://doc.rust-lang.org/nightly/reference/inline-assembly.html +/// see: https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html +#[naked] +#[no_mangle] +unsafe fn switch(old: *mut TaskContext, new: *const TaskContext) { + // a0: _old, a1: _new + asm!( + " + sd x1, 0x00(a0) + sd x2, 0x08(a0) + sd x8, 0x10(a0) + sd x9, 0x18(a0) + sd x18, 0x20(a0) + sd x19, 0x28(a0) + sd x20, 0x30(a0) + sd x21, 0x38(a0) + sd x22, 0x40(a0) + sd x23, 0x48(a0) + sd x24, 0x50(a0) + sd x25, 0x58(a0) + sd x26, 0x60(a0) + sd x27, 0x68(a0) + sd x1, 0x70(a0) + + ld x1, 0x00(a1) + ld x2, 0x08(a1) + ld x8, 0x10(a1) + ld x9, 0x18(a1) + ld x18, 0x20(a1) + ld x19, 0x28(a1) + ld x20, 0x30(a1) + ld x21, 0x38(a1) + ld x22, 0x40(a1) + ld x23, 0x48(a1) + ld x24, 0x50(a1) + ld x25, 0x58(a1) + ld x26, 0x60(a1) + ld x27, 0x68(a1) + ld t0, 0x70(a1) + + jr t0 + ", + options(noreturn) + ); +} + +#[no_mangle] +pub fn main() { + println!("stackful_coroutine begin..."); + println!("TASK 0(Runtime) STARTING"); + let mut runtime = Runtime::new(); + runtime.init(); + runtime.spawn(|| { + println!("TASK 1 STARTING"); + let id = 1; + for i in 0..4 { + println!("task: {} counter: {}", id, i); + yield_task(); + } + println!("TASK 1 FINISHED"); + }); + runtime.spawn(|| { + println!("TASK 2 STARTING"); + let id = 2; + for i in 0..8 { + println!("task: {} counter: {}", id, i); + yield_task(); + } + println!("TASK 2 FINISHED"); + }); + runtime.spawn(|| { + println!("TASK 3 STARTING"); + let id = 3; + for i in 0..12 { + println!("task: {} counter: {}", id, i); + yield_task(); + } + println!("TASK 3 FINISHED"); + }); + runtime.spawn(|| { + println!("TASK 4 STARTING"); + let id = 4; + for i in 0..16 { + println!("task: {} counter: {}", id, i); + yield_task(); + } + println!("TASK 4 FINISHED"); + }); + runtime.run(); + println!("stackful_coroutine PASSED"); + exit(0); +} diff --git a/user/src/bin/stackless_coroutine.rs b/user/src/bin/stackless_coroutine.rs new file mode 100644 index 0000000..43aeb2d --- /dev/null +++ b/user/src/bin/stackless_coroutine.rs @@ -0,0 +1,129 @@ +// https://blog.aloni.org/posts/a-stack-less-rust-coroutine-100-loc/ +// https://github.com/chyyuu/example-coroutine-and-thread/tree/stackless-coroutine-x86 +#![no_std] +#![no_main] + +use core::future::Future; +use core::pin::Pin; +use core::task::{Context, Poll}; +use core::task::{RawWaker, RawWakerVTable, Waker}; + +extern crate alloc; +use alloc::collections::VecDeque; + +use alloc::boxed::Box; + +#[macro_use] +extern crate user_lib; + +enum State { + Halted, + Running, +} + +struct Task { + state: State, +} + +impl Task { + fn waiter<'a>(&'a mut self) -> Waiter<'a> { + Waiter { task: self } + } +} + +struct Waiter<'a> { + task: &'a mut Task, +} + +impl<'a> Future for Waiter<'a> { + type Output = (); + + fn poll(mut self: Pin<&mut Self>, _cx: &mut Context) -> Poll { + match self.task.state { + State::Halted => { + self.task.state = State::Running; + Poll::Ready(()) + } + State::Running => { + self.task.state = State::Halted; + Poll::Pending + } + } + } +} + +struct Executor { + tasks: VecDeque>>>, +} + +impl Executor { + fn new() -> Self { + Executor { + tasks: VecDeque::new(), + } + } + + fn push(&mut self, closure: C) + where + F: Future + 'static, + C: FnOnce(Task) -> F, + { + let task = Task { + state: State::Running, + }; + self.tasks.push_back(Box::pin(closure(task))); + } + + fn run(&mut self) { + let waker = create_waker(); + let mut context = Context::from_waker(&waker); + + while let Some(mut task) = self.tasks.pop_front() { + match task.as_mut().poll(&mut context) { + Poll::Pending => { + self.tasks.push_back(task); + } + Poll::Ready(()) => {} + } + } + } +} + +pub fn create_waker() -> Waker { + // Safety: The waker points to a vtable with functions that do nothing. Doing + // nothing is memory-safe. + unsafe { Waker::from_raw(RAW_WAKER) } +} + +const RAW_WAKER: RawWaker = RawWaker::new(core::ptr::null(), &VTABLE); +const VTABLE: RawWakerVTable = RawWakerVTable::new(clone, wake, wake_by_ref, drop); + +unsafe fn clone(_: *const ()) -> RawWaker { + RAW_WAKER +} +unsafe fn wake(_: *const ()) {} +unsafe fn wake_by_ref(_: *const ()) {} +unsafe fn drop(_: *const ()) {} + +#[no_mangle] +pub fn main() -> i32 { + println!("stackless coroutine Begin.."); + let mut exec = Executor::new(); + println!(" Create futures"); + for instance in 1..=3 { + exec.push(move |mut task| async move { + println!(" Task {}: begin state", instance); + task.waiter().await; + println!(" Task {}: next state", instance); + task.waiter().await; + println!(" Task {}: end state", instance); + }); + } + + println!(" Running"); + exec.run(); + println!(" Done"); + println!("stackless coroutine PASSED"); + + 0 +} From 3144455b55fc8b2809df422aa476c0ce98412f0f Mon Sep 17 00:00:00 2001 From: Yifan Wu Date: Wed, 21 Dec 2022 21:27:17 +0800 Subject: [PATCH 20/68] user add fp support --- user/.cargo/config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user/.cargo/config b/user/.cargo/config index e5ded8a..334d01e 100644 --- a/user/.cargo/config +++ b/user/.cargo/config @@ -3,5 +3,5 @@ target = "riscv64gc-unknown-none-elf" [target.riscv64gc-unknown-none-elf] rustflags = [ - "-Clink-args=-Tsrc/linker.ld", + "-Clink-args=-Tsrc/linker.ld", "-Cforce-frame-pointers=yes" ] From 4e5f16cb23bb07f112d4c53b7a990b9a45bff778 Mon Sep 17 00:00:00 2001 From: Yifan Wu Date: Fri, 23 Dec 2022 11:23:54 +0800 Subject: [PATCH 21/68] Fix pipe impl --- os/src/fs/pipe.rs | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/os/src/fs/pipe.rs b/os/src/fs/pipe.rs index 18c74d5..531eec4 100644 --- a/os/src/fs/pipe.rs +++ b/os/src/fs/pipe.rs @@ -114,36 +114,40 @@ impl File for Pipe { } fn read(&self, buf: UserBuffer) -> usize { assert!(self.readable()); + let want_to_read = buf.len(); let mut buf_iter = buf.into_iter(); - let mut read_size = 0usize; + let mut already_read = 0usize; loop { let mut ring_buffer = self.buffer.exclusive_access(); let loop_read = ring_buffer.available_read(); if loop_read == 0 { if ring_buffer.all_write_ends_closed() { - return read_size; + return already_read; } drop(ring_buffer); suspend_current_and_run_next(); continue; } - // read at most loop_read bytes for _ in 0..loop_read { if let Some(byte_ref) = buf_iter.next() { unsafe { *byte_ref = ring_buffer.read_byte(); } - read_size += 1; + already_read += 1; + if already_read == want_to_read { + return want_to_read; + } } else { - return read_size; + return already_read; } } } } fn write(&self, buf: UserBuffer) -> usize { assert!(self.writable()); + let want_to_write = buf.len(); let mut buf_iter = buf.into_iter(); - let mut write_size = 0usize; + let mut already_write = 0usize; loop { let mut ring_buffer = self.buffer.exclusive_access(); let loop_write = ring_buffer.available_write(); @@ -156,11 +160,14 @@ impl File for Pipe { for _ in 0..loop_write { if let Some(byte_ref) = buf_iter.next() { ring_buffer.write_byte(unsafe { *byte_ref }); - write_size += 1; + already_write += 1; + if already_write == want_to_write { + return want_to_write; + } } else { - return write_size; + return already_write; } } } } -} +} \ No newline at end of file From 01856f52433cb5da239224583329bbfb1e229c53 Mon Sep 17 00:00:00 2001 From: Yu Chen Date: Sat, 31 Dec 2022 10:36:35 +0800 Subject: [PATCH 22/68] fix rust-analyzer warning --- .vscode/settings.json | 6 +++--- easy-fs-fuse/Cargo.toml | 6 +++--- user/Cargo.toml | 6 +++--- user/src/bin/stackful_coroutine.rs | 9 +++++---- 4 files changed, 14 insertions(+), 13 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index bf81ab5..6a40655 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -7,7 +7,7 @@ // For Rust Analyzer plugin users: "rust-analyzer.cargo.target": "riscv64gc-unknown-none-elf", "rust-analyzer.checkOnSave.allTargets": false, - "rust-analyzer.cargo.features": [ - "board_qemu" - ] + // "rust-analyzer.cargo.features": [ + // "board_qemu" + // ] } \ No newline at end of file diff --git a/easy-fs-fuse/Cargo.toml b/easy-fs-fuse/Cargo.toml index 0527e9b..5c5e68d 100644 --- a/easy-fs-fuse/Cargo.toml +++ b/easy-fs-fuse/Cargo.toml @@ -11,6 +11,6 @@ clap = "2.33.3" easy-fs = { path = "../easy-fs" } rand = "0.8.0" -[features] -board_qemu = [] -board_k210 = [] \ No newline at end of file +# [features] +# board_qemu = [] +# board_k210 = [] \ No newline at end of file diff --git a/user/Cargo.toml b/user/Cargo.toml index 18634c3..a609f4d 100644 --- a/user/Cargo.toml +++ b/user/Cargo.toml @@ -14,6 +14,6 @@ riscv = { git = "https://github.com/rcore-os/riscv", features = ["inline-asm"] } [profile.release] debug = true -[features] -board_qemu = [] -board_k210 = [] \ No newline at end of file +# [features] +# board_qemu = [] +# board_k210 = [] \ No newline at end of file diff --git a/user/src/bin/stackful_coroutine.rs b/user/src/bin/stackful_coroutine.rs index 83eceb7..d9f3b94 100644 --- a/user/src/bin/stackful_coroutine.rs +++ b/user/src/bin/stackful_coroutine.rs @@ -4,7 +4,7 @@ #![no_std] #![no_main] #![feature(naked_functions)] -#![feature(asm)] +//#![feature(asm)] extern crate alloc; #[macro_use] @@ -12,7 +12,7 @@ extern crate user_lib; use core::arch::asm; -#[macro_use] +//#[macro_use] use alloc::vec; use alloc::vec::Vec; @@ -69,7 +69,7 @@ impl Task { // we can allocate memory for it later, but it keeps complexity down and lets us focus on more interesting parts // to do it here. The important part is that once allocated it MUST NOT move in memory. Task { - id, + id:id, stack: vec![0_u8; DEFAULT_STACK_SIZE], ctx: TaskContext::default(), state: State::Available, @@ -185,6 +185,7 @@ impl Runtime { .find(|t| t.state == State::Available) .expect("no available task."); + println!("RUNTIME: spawning task {}\n", available.id); let size = available.stack.len(); unsafe { let s_ptr = available.stack.as_mut_ptr().offset(size as isize); @@ -259,7 +260,7 @@ pub fn yield_task() { /// see: https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html #[naked] #[no_mangle] -unsafe fn switch(old: *mut TaskContext, new: *const TaskContext) { +unsafe extern "C" fn switch(old: *mut TaskContext, new: *const TaskContext) { // a0: _old, a1: _new asm!( " From 58bf26222f0946495827a86ef6b04f40e2fdb114 Mon Sep 17 00:00:00 2001 From: Yu Chen Date: Mon, 2 Jan 2023 11:28:06 +0800 Subject: [PATCH 23/68] run in qemu -bios none ENV --- os/Makefile | 18 +- os/src/boards/qemu.rs | 53 +++- os/src/entry.asm | 2 +- os/src/linker-qemu.ld | 2 +- os/src/main.rs | 92 ++++++- os/src/riscvregs.rs | 614 ++++++++++++++++++++++++++++++++++++++++++ os/src/start.rs | 86 ++++++ 7 files changed, 858 insertions(+), 9 deletions(-) create mode 100644 os/src/riscvregs.rs create mode 100644 os/src/start.rs diff --git a/os/Makefile b/os/Makefile index e02bc81..a8f180f 100644 --- a/os/Makefile +++ b/os/Makefile @@ -24,7 +24,7 @@ ifeq ($(MODE), release) endif # KERNEL ENTRY -KERNEL_ENTRY_PA := 0x80200000 +KERNEL_ENTRY_PA := 0x80000000 # Binutils OBJDUMP := rust-objdump --arch-name=riscv64 @@ -71,7 +71,21 @@ disasm-vim: kernel @nvim $(DISASM_TMP) @rm $(DISASM_TMP) -run: run-inner +run: run-inner-none + +run-inner-none: build + @qemu-system-riscv64 \ + -M 128m \ + -machine virt \ + -bios none \ + $(GUI_OPTION) \ + -kernel $(KERNEL_ELF) \ + -drive file=$(FS_IMG),if=none,format=raw,id=x0 \ + -device virtio-blk-device,drive=x0 \ +# -device virtio-gpu-device \ + -device virtio-keyboard-device \ + -device virtio-mouse-device \ + -serial stdio run-inner: build @qemu-system-riscv64 \ diff --git a/os/src/boards/qemu.rs b/os/src/boards/qemu.rs index ffabff6..d68ee2f 100644 --- a/os/src/boards/qemu.rs +++ b/os/src/boards/qemu.rs @@ -2,7 +2,7 @@ pub const CLOCK_FREQ: usize = 12500000; pub const MMIO: &[(usize, usize)] = &[ (0x0010_0000, 0x00_2000), // VIRT_TEST/RTC in virt machine - (0x2000000, 0x10000), + (0x2000000, 0x10000), // core local interrupter (CLINT) (0xc000000, 0x210000), // VIRT_PLIC in virt machine (0x10000000, 0x9000), // VIRT_UART0 with GPU in virt machine ]; @@ -53,6 +53,57 @@ pub fn irq_handler() { plic.complete(0, IntrTargetPriority::Supervisor, intr_src_id); } + +// core local interrupter (CLINT), which contains the timer +pub const CLINT: usize = 0x2000000; +pub const fn clint_mtimecmp(hartid: usize) -> usize { + CLINT + 0x4000 + 8 * hartid +} +pub const CLINT_MTIME: usize = CLINT + 0xBFF8; // Cycles since boot. + +#[naked] +#[repr(align(16))] // if miss this alignment, a load access fault will occur. +#[no_mangle] +pub unsafe extern "C" fn timervec() -> ! { + // start.rs has set up the memory that mscratch points to: + // scratch[0,8,16] : register save area. + // scratch[24] : address of CLINT's MTIMECMP register. + // scratch[32] : desired interval between interrupts. + + // Now, mscrach has a pointer to an additional scratch space. + // to aboid overwriting the contents of the integer registers, + // the prologue of an interrupts handler usually begins by swapping + // an integer register(say a0) with mscratch CSR. + // The interrupt handler stores the integer registers + // used for processing in this scratch space. + // a0 saved in mscrach, a1 ~ a3 saved in scratch space. + //loop {} + asm!( + "csrrw a0, mscratch, a0", + "sd a1, 0(a0)", + "sd a2, 8(a0)", + "sd a3, 16(a0)", + // schedule the next timer interrupt + // by adding interval to mtimecmp. + "ld a1, 24(a0)", // CLINT_MTIMECMP(hartid) contents + "ld a2, 32(a0)", // interval + "ld a3, 0(a1)", + "add a3, a3, a2", + "sd a3, 0(a1)", + // raise a supervisor software interrupt. + "li a1, 2", + "csrw sip, a1", + // restore and return + "ld a3, 16(a0)", + "ld a2, 8(a0)", + "ld a1, 0(a0)", + "csrrw a0, mscratch, a0", + "mret", + options(noreturn) + ); +} + + //ref:: https://github.com/andre-richter/qemu-exit use core::arch::asm; diff --git a/os/src/entry.asm b/os/src/entry.asm index c32d68f..1d1a175 100644 --- a/os/src/entry.asm +++ b/os/src/entry.asm @@ -2,7 +2,7 @@ .globl _start _start: la sp, boot_stack_top - call rust_main + call rust_start .section .bss.stack .globl boot_stack_lower_bound diff --git a/os/src/linker-qemu.ld b/os/src/linker-qemu.ld index 5baafbd..92dd51c 100644 --- a/os/src/linker-qemu.ld +++ b/os/src/linker-qemu.ld @@ -1,6 +1,6 @@ OUTPUT_ARCH(riscv) ENTRY(_start) -BASE_ADDRESS = 0x80200000; +BASE_ADDRESS = 0x80000000; SECTIONS { diff --git a/os/src/main.rs b/os/src/main.rs index 299e4cf..7859560 100644 --- a/os/src/main.rs +++ b/os/src/main.rs @@ -2,6 +2,8 @@ #![no_main] #![feature(panic_info_message)] #![feature(alloc_error_handler)] +#![feature(naked_functions)] +#![feature(fn_align)] use crate::drivers::{GPU_DEVICE, KEYBOARD_DEVICE, MOUSE_DEVICE}; @@ -27,7 +29,10 @@ mod syscall; mod task; mod timer; mod trap; - +//mod start; +mod riscvregs; +use riscvregs::registers::*; +use riscvregs::registers::pmpcfg0::*; //use syscall::create_desktop; //for test core::arch::global_asm!(include_str!("entry.asm")); @@ -51,6 +56,85 @@ lazy_static! { unsafe { UPIntrFreeCell::new(false) }; } + +#[repr(C, align(16))] +struct Stack([u8; 4096 * 4 * 1]); + +#[no_mangle] +static mut STACK0: Stack = Stack([0; 4096 * 4 * 1]); + +#[no_mangle] +pub unsafe fn rust_start() -> ! { + // set MPP mode to Supervisor, for mret + mstatus::set_mpp(mstatus::MPP::Supervisor); + + // set MEPC to main, for mret + mepc::write(rust_main as usize); + + // disable paging for now. + satp::write(0); + + // delegate all interrupts and exceptions to supervisor mode. + medeleg::set_all(); + mideleg::set_all(); + sie::set_sext(); + sie::set_ssoft(); + sie::set_stimer(); + + // configure Physical Memory Protection to give supervisor mode + // access to all of physical memory. + pmpaddr0::write(0x3fffffffffffff); + pmpcfg0::set_pmp(0, Range::TOR, Permission::RWX, false); // 0 < addr < pmpaddr0 + + // ask for clock interrupts. + timerinit(); + + // keep each CPU's hartid in its tp register, for cpuid(). + let id = mhartid::read(); + core::arch::asm!("mv tp, {0}", in(reg) id); + + // switch to supervisor mode and jump to main(). + core::arch::asm!("mret"); + + extern "C" { + fn rust_main() -> !; + } + core::hint::unreachable_unchecked(); +} + +// a scratch area per CPU for machine-mode timer interrupts. +static mut TIMER_SCRATCH: [[u64; 5]; 1] = [[0; 5]; 1]; + +unsafe fn timerinit() { + // each CPU has a separate source of timer interrupts + let id = mhartid::read(); + + // ask the CLINT for a timer interrupts + let interval = 1000000u64; // cycles; about 1/10th second in qemu. + let mtimecmp = board::clint_mtimecmp(id) as *mut u64; + let mtime = board::CLINT_MTIME as *const u64; + mtimecmp.write_volatile(mtime.read_volatile() + interval); + + // prepare information in scratch[] for timervec. + // scratch[0..2] : space for timervec to save registers. + // scratch[3] : address of CLINT MTIMECMP register. + // scratch[4] : desired interval (in cycles) between timer interrupts. + let scratch = &mut TIMER_SCRATCH[id]; + scratch[3] = mtimecmp as u64; + scratch[4] = interval; + mscratch::write(scratch.as_mut_ptr() as usize); + + // set the machine-mode trap handler + mtvec::write(board::timervec as usize, mtvec::TrapMode::Direct); + + // enable machine-mode interrupts. + mstatus::set_mie(); + + // enable machime-mode timer interrupts. + mie::set_mtimer(); +} + + #[no_mangle] pub fn rust_main() -> ! { clear_bss(); @@ -63,11 +147,11 @@ pub fn rust_main() -> ! { let _mouse = MOUSE_DEVICE.clone(); println!("KERN: init trap"); trap::init(); - trap::enable_timer_interrupt(); - timer::set_next_trigger(); + //trap::enable_timer_interrupt(); + //timer::set_next_trigger(); board::device_init(); fs::list_apps(); - gui::init_paint(); + //gui::init_paint(); task::add_initproc(); *DEV_NON_BLOCKING_ACCESS.exclusive_access() = true; task::run_tasks(); diff --git a/os/src/riscvregs.rs b/os/src/riscvregs.rs new file mode 100644 index 0000000..1871242 --- /dev/null +++ b/os/src/riscvregs.rs @@ -0,0 +1,614 @@ +// RISC-V registers +pub mod registers { + // hart (core) id registers + pub mod mhartid { + use core::arch::asm; + + #[inline] + pub fn read() -> usize { + let id: usize; + unsafe { + asm!("csrr {}, mhartid", out(reg) id); + } + id + } + } + + // Machine Status Register, mstatus + pub mod mstatus { + use core::arch::asm; + + // Machine Status Register bit + const MPP_MASK: usize = 3 << 11; + const MIE: usize = 1 << 3; + + // Machine Previous Privilege mode + #[derive(Clone, Copy, Debug, PartialEq, Eq)] + pub enum MPP { + Machine = 3, + Supervisor = 1, + User = 0, + } + + #[inline] + unsafe fn _read() -> usize { + let bits: usize; + asm!("csrr {}, mstatus", out(reg) bits); + bits + } + + #[inline] + unsafe fn _write(bits: usize) { + asm!("csrw mstatus, {}", in(reg) bits); + } + + // Machine Previous Privilege Mode + #[inline] + pub fn set_mpp(mpp: MPP) { + unsafe { + let mut value = _read(); + value &= !MPP_MASK; + value |= (mpp as usize) << 11; + _write(value); + } + } + + #[inline] + pub fn set_mie() { + unsafe { + asm!("csrs mstatus, {}", in(reg) MIE); + } + } + } + + // machine exception program counter, holds the + // instruction address to which a return from + // exception will go. + pub mod mepc { + use core::arch::asm; + + #[inline] + pub fn write(x: usize) { + unsafe { + asm!("csrw mepc, {}", in(reg) x); + } + } + } + + // Supervisor Status Register, sstatus + pub mod sstatus { + use core::arch::asm; + + // Supervisor Status Register bit + const SPP: usize = 1 << 8; // Previous mode, 1=Supervisor, 0=user + const SPIE: usize = 1 << 5; // Supervisor Previous Interrupt Enable + const SIE: usize = 1 << 1; // Supervisor Interrupt Enable + + #[derive(Clone, Copy, Debug)] + pub struct Sstatus { + bits: usize, + } + + impl Sstatus { + // Supervisor Interrupt Enable + #[inline] + pub(in crate::riscvregs) fn sie(&self) -> bool { + self.bits & SIE != 0 + } + + // Supervisor Previous Privilege mode + #[inline] + pub fn spp(&self) -> SPP { + match self.bits & SPP { + 0 => SPP::User, + _ => SPP::Supervisor, + } + } + + // restore status bits + #[inline] + pub fn restore(&self) { + unsafe { + _write(self.bits); + } + } + } + + // Supervisor Previous Privilege Mode + #[derive(Clone, Copy, Debug, PartialEq, Eq)] + pub enum SPP { + Supervisor = 1, + User = 0, + } + + #[inline] + pub fn read() -> Sstatus { + let bits: usize; + unsafe { asm!("csrr {}, sstatus", out(reg) bits) } + Sstatus { bits } + } + + #[inline] + unsafe fn _write(bits: usize) { + asm!("csrw sstatus, {}", in(reg) bits); + } + + // bit set + #[inline] + unsafe fn _set(bits: usize) { + asm!("csrs sstatus, {}", in(reg) bits); + } + + // bit clear + #[inline] + unsafe fn _clear(bits: usize) { + asm!("csrc sstatus, {}", in(reg) bits); + } + + #[inline] + pub(in crate::riscvregs) unsafe fn set_sie() { + _set(SIE) + } + + #[inline] + pub(in crate::riscvregs) unsafe fn clear_sie() { + _clear(SIE) + } + + #[inline] + pub unsafe fn set_spie() { + _set(SPIE); + } + + #[inline] + pub unsafe fn set_spp(spp: SPP) { + match spp { + SPP::Supervisor => _set(SPP), + SPP::User => _clear(SPP), + } + } + } + + // Supervisor Interrupt Pending + pub mod sip { + use core::arch::asm; + + const SSIP: usize = 1 << 1; + + // Supervisor Software Interrupt Pending + #[inline] + pub unsafe fn clear_ssoft() { + asm!("csrc sip, {}", in(reg) SSIP); + } + } + + // Supervisor Interrupt Enable + pub mod sie { + use core::arch::asm; + + const SEIE: usize = 1 << 9; // external + const STIE: usize = 1 << 5; // timer + const SSIE: usize = 1 << 1; // software + + #[inline] + unsafe fn _set(bits: usize) { + asm!("csrs sie, {}", in(reg) bits); + } + + #[inline] + pub unsafe fn set_sext() { + _set(SEIE); + } + + #[inline] + pub unsafe fn set_stimer() { + _set(STIE); + } + + #[inline] + pub unsafe fn set_ssoft() { + _set(SSIE); + } + } + + // Machine-mode Interrupt Enable + pub mod mie { + use core::arch::asm; + + const MTIE: usize = 1 << 7; + + #[inline] + pub unsafe fn set_mtimer() { + asm!("csrs mie, {}", in(reg) MTIE); + } + } + + // supervisor exceptions program counter, holds the + // instruction address to which a return from + // exception will go. + pub mod sepc { + use core::arch::asm; + + #[inline] + pub fn read() -> usize { + let bits: usize; + unsafe { + asm!("csrr {}, sepc", out(reg) bits); + } + bits + } + + #[inline] + pub fn write(bits: usize) { + unsafe { + asm!("csrw sepc, {}", in(reg) bits); + } + } + } + + // Machine Exception Delegation + pub mod medeleg { + use core::arch::asm; + + pub unsafe fn set_all() { + asm!("csrw medeleg, {}", in(reg) 0xffff); + } + } + + // Machine Interrupt Delegation + pub mod mideleg { + use core::arch::asm; + + #[inline] + pub unsafe fn set_all() { + asm!("csrw mideleg, {}", in(reg) 0xffff); + } + } + + // Supervisor Trap-Vector Base Address + // low two bits are mode. + pub mod stvec { + pub use super::mtvec::TrapMode; + use core::arch::asm; + + #[inline] + pub unsafe fn write(addr: usize, mode: TrapMode) { + asm!("csrw stvec, {}", in(reg) addr + mode as usize); + } + } + + // Machine-mode interrupt vector + pub mod mtvec { + use core::arch::asm; + + #[derive(Clone, Copy, Debug, PartialEq, Eq)] + pub enum TrapMode { + Direct = 0, + Vectored = 1, + } + + #[inline] + pub unsafe fn write(addr: usize, mode: TrapMode) { + asm!("csrw mtvec, {}", in(reg) addr + mode as usize); + } + } + + // Physical Memory Protection Configuration + pub mod pmpcfg0 { + use core::arch::asm; + + // Permission enum contains all possible permission modes for pmp registers + #[derive(Clone, Copy, Debug)] + pub enum Permission { + NONE = 0b000, + R = 0b001, + W = 0b010, + RW = 0b011, + X = 0b100, + RX = 0b101, + WX = 0b110, + RWX = 0b111, + } + + // Range enum contains all possible addressing modes for pmp registers + pub enum Range { + OFF = 0b00, + TOR = 0b01, + NA4 = 0b10, + NAPOT = 0b11, + } + + // Set the pmp configuration corresponging to the index + #[inline] + pub unsafe fn set_pmp(index: usize, range: Range, permission: Permission, locked: bool) { + assert!(index < 8); + let mut value = _read(); + let byte = (locked as usize) << 7 | (range as usize) << 3 | (permission as usize); + value |= byte << (8 * index); + _write(value); + } + + #[inline] + unsafe fn _read() -> usize { + let bits: usize; + asm!("csrr {}, pmpcfg0", out(reg) bits); + bits + } + + #[inline] + unsafe fn _write(bits: usize) { + asm!("csrw pmpcfg0, {}", in(reg) bits); + } + } + + // Physical memory protection address register + pub mod pmpaddr0 { + use core::arch::asm; + + pub fn write(bits: usize) { + unsafe { + asm!("csrw pmpaddr0, {}", in(reg) bits); + } + } + } + + // Supervisor address translation and protection; + // holds the address of the page table. + pub mod satp { + use core::arch::asm; + + // stap register + #[derive(Clone, Copy, Debug)] + pub struct Satp { + bits: usize, + } + + // 64-bit satp mode + pub enum Mode { + // No translation or protection + Bare = 0, + // Page-based 39-bit virtual addressing + Sv39 = 8, + // Page-based 48-bit virtual addressing + Sv48 = 9, + // Page-based 57-bit virtual addressing + Sv57 = 10, + // Page-based 64-bit virtual addressing + Sv64 = 11, + } + + impl Satp { + // Return the contents of the register as raw bits + #[inline] + pub fn bits(&self) -> usize { + self.bits + } + } + + #[inline] + pub unsafe fn read() -> Satp { + let bits: usize; + asm!("csrr {}, satp", out(reg) bits); + Satp { bits } + } + + #[inline] + pub unsafe fn write(bits: usize) { + asm!("csrw satp, {}", in(reg) bits); + } + + #[inline] + pub fn make(mode: Mode, asid: usize, ppn: usize) -> usize { + let mut bits: usize = 0; + bits |= (mode as usize) << 60; + bits |= asid << 44; + bits |= ppn >> 12; + bits + } + } + + // mscratch register + pub mod mscratch { + use core::arch::asm; + + #[inline] + pub fn write(bits: usize) { + unsafe { + asm!("csrw mscratch, {}", in(reg) bits); + } + } + } + + // Supervisor Trap Cause + pub mod scause { + use core::{arch::asm, mem::size_of}; + + // scause register + #[derive(Clone, Copy)] + pub struct Scause { + bits: usize, + } + + // Trap Cause + #[derive(Clone, Copy, Debug, PartialEq, Eq)] + pub enum Trap { + Interrupt(Interrupt), + Exception(Exception), + } + + // Interrupt + #[derive(Clone, Copy, Debug, PartialEq, Eq)] + pub enum Interrupt { + UserSoft, + SupervisorSoft, + UserTimer, + SupervisorTimer, + UserExternal, + SupervisorExternal, + Unknown, + } + + // Exception + #[derive(Copy, Clone, Debug, Eq, PartialEq)] + pub enum Exception { + InstructionMisaligned, + InstructionFault, + IllegalInstruction, + Breakpoint, + LoadFault, + StoreMisaligned, + StoreFault, + UserEnvCall, + InstructionPageFault, + LoadPageFault, + StorePageFault, + Unknown, + } + + impl Interrupt { + #[inline] + pub fn from(nr: usize) -> Self { + match nr { + 0 => Interrupt::UserSoft, + 1 => Interrupt::SupervisorSoft, + 4 => Interrupt::UserTimer, + 5 => Interrupt::SupervisorTimer, + 8 => Interrupt::UserExternal, + 9 => Interrupt::SupervisorExternal, + _ => Interrupt::Unknown, + } + } + } + + impl Exception { + #[inline] + pub fn from(nr: usize) -> Self { + match nr { + 0 => Exception::InstructionMisaligned, + 1 => Exception::InstructionFault, + 2 => Exception::IllegalInstruction, + 3 => Exception::Breakpoint, + 5 => Exception::LoadFault, + 6 => Exception::StoreMisaligned, + 7 => Exception::StoreFault, + 8 => Exception::UserEnvCall, + 12 => Exception::InstructionPageFault, + 13 => Exception::LoadPageFault, + 15 => Exception::StorePageFault, + _ => Exception::Unknown, + } + } + } + + impl Scause { + // Returns the contents of the register as raw bits + #[inline] + pub fn bits(&self) -> usize { + self.bits + } + + // Returns the code field + #[inline] + pub fn code(&self) -> usize { + let bit = 1 << (size_of::() * 8 - 1); + self.bits & !bit + } + + // Trap cause + #[inline] + pub fn cause(&self) -> Trap { + if self.is_interrupt() { + Trap::Interrupt(Interrupt::from(self.code())) + } else { + Trap::Exception(Exception::from(self.code())) + } + } + + // Is trap cause an interrupt. + #[inline] + pub fn is_interrupt(&self) -> bool { + self.bits & (1 << (size_of::() * 8 - 1)) != 0 + } + + // Is trap cause an exception. + #[inline] + pub fn is_exception(&self) -> bool { + !self.is_interrupt() + } + } + + #[inline] + pub fn read() -> Scause { + let bits: usize; + unsafe { + asm!("csrr {}, scause", out(reg) bits); + } + Scause { bits } + } + } + + // Supervisor Trap Value + pub mod stval { + use core::arch::asm; + + #[inline] + pub fn read() -> usize { + let bits: usize; + unsafe { asm!("csrr {}, stval", out(reg) bits) } + bits + } + } +} + +use core::arch::asm; + +use registers::*; + +// enable device interrupts +#[inline] +pub fn intr_on() { + unsafe { + sstatus::set_sie(); + } +} + +// disable device interrupts +#[inline] +pub fn intr_off() { + unsafe { + sstatus::clear_sie(); + } +} + +// are device interrupts enabled? +#[inline] +pub fn intr_get() -> bool { + sstatus::read().sie() +} + +// flush the TLB. +#[inline] +pub unsafe fn sfence_vma() { + // the zero, zero means flush all TLB entries + asm!("sfence.vma zero, zero"); +} + +pub const PGSIZE: usize = 4096; // bytes per page +pub const PGSHIFT: usize = 12; // bits of offset within a page + +pub const fn pgroundup(sz: usize) -> usize { + (sz + PGSIZE - 1) & !(PGSIZE - 1) +} + +pub const fn pgrounddown(sz: usize) -> usize { + sz & !(PGSIZE - 1) +} + +// PTE flags +pub mod pteflags { + pub const PTE_V: usize = 1 << 0; // valid + pub const PTE_R: usize = 1 << 1; + pub const PTE_W: usize = 1 << 2; + pub const PTE_X: usize = 1 << 3; + pub const PTE_U: usize = 1 << 4; // user can access +} diff --git a/os/src/start.rs b/os/src/start.rs new file mode 100644 index 0000000..3a6d391 --- /dev/null +++ b/os/src/start.rs @@ -0,0 +1,86 @@ +//use crate::kernelvec::*; +//use crate::memlayout::*; +//use crate::param::NCPU; +//use super::main::*; +//use crate::riscv::registers::{pmpcfg0::*, *}; +use core::arch::asm; +use core::hint::unreachable_unchecked; + +mod riscv; + +#[repr(C, align(16))] +struct Stack([u8; 4096 * 4 * NCPU]); + +#[no_mangle] +static mut STACK0: Stack = Stack([0; 4096 * 4 * NCPU]); + +#[no_mangle] +pub unsafe fn rust_start() -> ! { + // set MPP mode to Supervisor, for mret + mstatus::set_mpp(mstatus::MPP::Supervisor); + + // set MEPC to main, for mret + mepc::write(rust_main as usize); + + // disable paging for now. + satp::write(0); + + // delegate all interrupts and exceptions to supervisor mode. + medeleg::set_all(); + mideleg::set_all(); + sie::set_sext(); + sie::set_ssoft(); + sie::set_stimer(); + + // configure Physical Memory Protection to give supervisor mode + // access to all of physical memory. + pmpaddr0::write(0x3fffffffffffff); + pmpcfg0::set_pmp(0, Range::TOR, Permission::RWX, false); // 0 < addr < pmpaddr0 + + // ask for clock interrupts. + timerinit(); + + // keep each CPU's hartid in its tp register, for cpuid(). + let id = mhartid::read(); + asm!("mv tp, {0}", in(reg) id); + + // switch to supervisor mode and jump to main(). + asm!("mret"); + + extern "C" { + fn rust_main() -> !; + } + unreachable_unchecked(); +} + +// a scratch area per CPU for machine-mode timer interrupts. +static mut TIMER_SCRATCH: [[u64; 5]; 1] = [[0; 5]; 1]; + +unsafe fn timerinit() { + // each CPU has a separate source of timer interrupts + let id = mhartid::read(); + + // ask the CLINT for a timer interrupts + let interval = 1000000u64; // cycles; about 1/10th second in qemu. + let mtimecmp = clint_mtimecmp(id) as *mut u64; + let mtime = CLINT_MTIME as *const u64; + mtimecmp.write_volatile(mtime.read_volatile() + interval); + + // prepare information in scratch[] for timervec. + // scratch[0..2] : space for timervec to save registers. + // scratch[3] : address of CLINT MTIMECMP register. + // scratch[4] : desired interval (in cycles) between timer interrupts. + let scratch = &mut TIMER_SCRATCH[id]; + scratch[3] = mtimecmp as u64; + scratch[4] = interval; + mscratch::write(scratch.as_mut_ptr() as usize); + + // set the machine-mode trap handler + mtvec::write(timervec as usize, mtvec::TrapMode::Direct); + + // enable machine-mode interrupts. + mstatus::set_mie(); + + // enable machime-mode timer interrupts. + mie::set_mtimer(); +} \ No newline at end of file From 2e57ec432a1cedbcec9cbc1c67f0de3b58667fd5 Mon Sep 17 00:00:00 2001 From: Yu Chen Date: Mon, 2 Jan 2023 20:06:03 +0800 Subject: [PATCH 24/68] temp stage --- os/Cargo.toml | 1 + os/Makefile | 12 +++ os/src/boards/qemu.rs | 7 +- os/src/main.rs | 186 ++++++++++++++++++++++++++++++++++-------- os/src/trap/mod.rs | 24 +++++- 5 files changed, 190 insertions(+), 40 deletions(-) diff --git a/os/Cargo.toml b/os/Cargo.toml index f4b2d80..3cae609 100644 --- a/os/Cargo.toml +++ b/os/Cargo.toml @@ -10,6 +10,7 @@ edition = "2021" riscv = { git = "https://github.com/rcore-os/riscv", features = ["inline-asm"] } lazy_static = { version = "1.4.0", features = ["spin_no_std"] } buddy_system_allocator = "0.6" +bit_field = "0.10.0" bitflags = "1.2.1" xmas-elf = "0.7.0" volatile = "0.3" diff --git a/os/Makefile b/os/Makefile index a8f180f..4331ae5 100644 --- a/os/Makefile +++ b/os/Makefile @@ -105,6 +105,18 @@ fdt: @qemu-system-riscv64 -M 128m -machine virt,dumpdtb=virt.out fdtdump virt.out +debug-none: build + @tmux new-session -d \ + "qemu-system-riscv64 -machine virt -nographic -bios none -kernel $(KERNEL_ELF) \ + -drive file=$(FS_IMG),if=none,format=raw,id=x0 \ + -device virtio-blk-device,drive=x0 \ + -device virtio-keyboard-device \ + -device virtio-mouse-device \ + -serial stdio \ + -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 + debug: build @tmux new-session -d \ "qemu-system-riscv64 -machine virt -nographic -bios $(BOOTLOADER) -device loader,file=$(KERNEL_BIN),addr=$(KERNEL_ENTRY_PA) -s -S" && \ diff --git a/os/src/boards/qemu.rs b/os/src/boards/qemu.rs index d68ee2f..6217925 100644 --- a/os/src/boards/qemu.rs +++ b/os/src/boards/qemu.rs @@ -56,10 +56,11 @@ pub fn irq_handler() { // core local interrupter (CLINT), which contains the timer pub const CLINT: usize = 0x2000000; -pub const fn clint_mtimecmp(hartid: usize) -> usize { - CLINT + 0x4000 + 8 * hartid -} +// pub const fn clint_mtimecmp(hartid: usize) -> usize { +// CLINT + 0x4000 + 8 * hartid +// } pub const CLINT_MTIME: usize = CLINT + 0xBFF8; // Cycles since boot. +pub const CLINT_MTIMECMP: usize = CLINT + 0x4000; #[naked] #[repr(align(16))] // if miss this alignment, a load access fault will occur. diff --git a/os/src/main.rs b/os/src/main.rs index 7859560..c720b59 100644 --- a/os/src/main.rs +++ b/os/src/main.rs @@ -14,7 +14,7 @@ extern crate bitflags; #[path = "boards/qemu.rs"] mod board; - +use board::*; #[macro_use] mod console; mod config; @@ -29,10 +29,15 @@ mod syscall; mod task; mod timer; mod trap; -//mod start; -mod riscvregs; -use riscvregs::registers::*; -use riscvregs::registers::pmpcfg0::*; + +use riscv::register::*; +// mod riscvreg; +// use riscvreg::{ +// mstatus, mepc, satp, medeleg, mideleg, sie, mhartid, tp, clint, +// mscratch, mtvec, mie, sstatus +// }; +// use riscvregs::registers::*; +// use riscvregs::registers::pmpcfg0::*; //use syscall::create_desktop; //for test core::arch::global_asm!(include_str!("entry.asm")); @@ -63,6 +68,41 @@ struct Stack([u8; 4096 * 4 * 1]); #[no_mangle] static mut STACK0: Stack = Stack([0; 4096 * 4 * 1]); +#[inline] +pub unsafe fn medeleg_write(medeleg: usize){ + core::arch::asm!("csrw medeleg, {}",in(reg)medeleg); +} + +pub unsafe fn mideleg_write(mideleg: usize) { + core::arch::asm!("csrw mideleg, {}", in(reg)mideleg); +} + +pub enum SIE { + SEIE = 1 << 9, // external + STIE = 1 << 5, // timer + SSIE = 1 << 1, // software +} + +#[inline] +pub unsafe fn sie_read() -> usize { + let ret:usize; + core::arch::asm!("csrr {}, sie", out(reg)ret); + ret +} + +#[inline] +pub unsafe fn sie_write(x:usize) { + core::arch::asm!("csrw sie, {}", in(reg)x); +} + +/// enable all software interrupts +/// still need to set SIE bit in sstatus +pub unsafe fn intr_on() { + let mut sie = sie_read(); + sie |= SIE::SSIE as usize | SIE::STIE as usize | SIE::SEIE as usize; + sie_write(sie); +} + #[no_mangle] pub unsafe fn rust_start() -> ! { // set MPP mode to Supervisor, for mret @@ -75,23 +115,21 @@ pub unsafe fn rust_start() -> ! { satp::write(0); // delegate all interrupts and exceptions to supervisor mode. - medeleg::set_all(); - mideleg::set_all(); - sie::set_sext(); - sie::set_ssoft(); - sie::set_stimer(); + medeleg_write(0xffff); + mideleg_write(0xffff); + intr_on(); // configure Physical Memory Protection to give supervisor mode // access to all of physical memory. - pmpaddr0::write(0x3fffffffffffff); - pmpcfg0::set_pmp(0, Range::TOR, Permission::RWX, false); // 0 < addr < pmpaddr0 + //pmpaddr0::write(0x3fffffffffffff); + //pmpcfg0::set_pmp(0, Range::TOR, Permission::RWX, false); // 0 < addr < pmpaddr0 // ask for clock interrupts. - timerinit(); + timer_init(); // keep each CPU's hartid in its tp register, for cpuid(). - let id = mhartid::read(); - core::arch::asm!("mv tp, {0}", in(reg) id); + // let id = mhartid::read(); + // core::arch::asm!("mv tp, {0}", in(reg) id); // switch to supervisor mode and jump to main(). core::arch::asm!("mret"); @@ -102,49 +140,127 @@ pub unsafe fn rust_start() -> ! { core::hint::unreachable_unchecked(); } -// a scratch area per CPU for machine-mode timer interrupts. -static mut TIMER_SCRATCH: [[u64; 5]; 1] = [[0; 5]; 1]; +use core::convert::Into; +use core::ptr; -unsafe fn timerinit() { +// a scratch area per CPU for machine-mode timer interrupts. +static mut TIMER_SCRATCH: [u64; 5] = [0; 5]; + +#[inline] +unsafe fn read_mtime() -> u64 { + ptr::read_volatile(Into::::into(CLINT_MTIME) as *const u64) +} + +unsafe fn write_mtimecmp(value: u64) { + let offset = Into::::into(CLINT_MTIMECMP); + ptr::write_volatile(offset as *mut u64, value); +} + +pub unsafe fn add_mtimecmp(interval:u64){ + let value = read_mtime(); + write_mtimecmp(value+interval); +} + +pub fn count_mtiecmp() -> usize{ + let ret:usize; + ret = Into::::into(CLINT) + 0x4000; + ret +} + +#[inline] +pub unsafe fn mtvec_write(x:usize){ + core::arch::asm!("csrw mtvec, {}",in(reg)x); +} + +use bit_field::BitField; + +#[inline] +unsafe fn mstatus_read() -> usize { + let ret:usize; + core::arch::asm!("csrr {}, mstatus",out(reg)ret); + ret +} + +#[inline] +unsafe fn mstatus_write(x: usize) { + core::arch::asm!("csrw mstatus, {}",in(reg)x); +} + +// enable machine-mode interrupts. +pub unsafe fn mstatus_enable_interrupt(){ + let mut mstatus = mstatus_read(); + mstatus.set_bit(3, true); + mstatus_write(mstatus); +} + + +pub enum MIE { + MEIE = 1 << 11, // external + MTIE = 1 << 7, // timer + MSIE = 1 << 3 // software +} + +#[inline] +pub unsafe fn mie_read() -> usize { + let ret:usize; + core::arch::asm!("csrr {}, mie", out(reg)ret); + ret +} + +#[inline] +pub unsafe fn mie_write(x:usize){ + core::arch::asm!("csrw mie, {}",in(reg)x); +} + +unsafe fn timer_init() { // each CPU has a separate source of timer interrupts - let id = mhartid::read(); + //let id = mhartid::read(); // ask the CLINT for a timer interrupts let interval = 1000000u64; // cycles; about 1/10th second in qemu. - let mtimecmp = board::clint_mtimecmp(id) as *mut u64; - let mtime = board::CLINT_MTIME as *const u64; - mtimecmp.write_volatile(mtime.read_volatile() + interval); + add_mtimecmp(interval); + // let mtimecmp = board::clint_mtimecmp(0) as *mut u64; + // let mtime = board::CLINT_MTIME as *const u64; + // mtimecmp.write_volatile(mtime.read_volatile() + interval); // prepare information in scratch[] for timervec. // scratch[0..2] : space for timervec to save registers. // scratch[3] : address of CLINT MTIMECMP register. // scratch[4] : desired interval (in cycles) between timer interrupts. - let scratch = &mut TIMER_SCRATCH[id]; - scratch[3] = mtimecmp as u64; + let scratch = &mut TIMER_SCRATCH; + scratch[3] = count_mtiecmp() as u64; scratch[4] = interval; mscratch::write(scratch.as_mut_ptr() as usize); // set the machine-mode trap handler - mtvec::write(board::timervec as usize, mtvec::TrapMode::Direct); + mtvec_write(timervec as usize); + //mtvec::write(board::timervec as usize, mtvec::TrapMode::Direct); // enable machine-mode interrupts. - mstatus::set_mie(); + mstatus_enable_interrupt(); + //mstatus::set_mie(); - // enable machime-mode timer interrupts. - mie::set_mtimer(); + // enable machine-mode timer interrupts. + mie_write(mie_read() | MIE::MTIE as usize); + //mie::set_mtimer(); } #[no_mangle] pub fn rust_main() -> ! { - clear_bss(); + + //clear_bss(); + + //println!("KERN: begin"); + mm::init(); - println!("KERN: init gpu"); - let _gpu = GPU_DEVICE.clone(); - println!("KERN: init keyboard"); - let _keyboard = KEYBOARD_DEVICE.clone(); - println!("KERN: init mouse"); - let _mouse = MOUSE_DEVICE.clone(); + loop{}; + //println!("KERN: init gpu"); + //let _gpu = GPU_DEVICE.clone(); + // println!("KERN: init keyboard"); + // let _keyboard = KEYBOARD_DEVICE.clone(); + //println!("KERN: init mouse"); + //let _mouse = MOUSE_DEVICE.clone(); println!("KERN: init trap"); trap::init(); //trap::enable_timer_interrupt(); diff --git a/os/src/trap/mod.rs b/os/src/trap/mod.rs index cb4a7ad..05a9126 100644 --- a/os/src/trap/mod.rs +++ b/os/src/trap/mod.rs @@ -11,7 +11,7 @@ use core::arch::{asm, global_asm}; use riscv::register::{ mtvec::TrapMode, scause::{self, Exception, Interrupt, Trap}, - sie, sscratch, sstatus, stval, stvec, + sie, sscratch, sstatus, stval, stvec,sip }; global_asm!(include_str!("trap.S")); @@ -100,6 +100,16 @@ pub fn trap_handler() -> ! { check_timer(); suspend_current_and_run_next(); } + Trap::Interrupt(Interrupt::SupervisorSoft) => { + //set_next_trigger(); + const SSIP: usize = 1 << 1; + unsafe { + asm!("csrc sip, {}", in(reg) SSIP); + } + println!("TRAP: ssoft in Kern"); + check_timer(); + // do not schedule now + } Trap::Interrupt(Interrupt::SupervisorExternal) => { crate::board::irq_handler(); } @@ -152,7 +162,17 @@ pub fn trap_from_kernel(_trap_cx: &TrapContext) { crate::board::irq_handler(); } Trap::Interrupt(Interrupt::SupervisorTimer) => { - set_next_trigger(); + //set_next_trigger(); + check_timer(); + // do not schedule now + } + Trap::Interrupt(Interrupt::SupervisorSoft) => { + //set_next_trigger(); + const SSIP: usize = 1 << 1; + unsafe { + asm!("csrc sip, {}", in(reg) SSIP); + } + println!("TRAP: ssoft in Kern"); check_timer(); // do not schedule now } From b1c5751546684e19c2b63a8a130978a5725abd4e Mon Sep 17 00:00:00 2001 From: Yu Chen Date: Tue, 3 Jan 2023 08:45:00 +0800 Subject: [PATCH 25/68] temp stage2:add pmpaddr0/pmpcfg0 setup --- os/src/main.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/os/src/main.rs b/os/src/main.rs index c720b59..56fba0c 100644 --- a/os/src/main.rs +++ b/os/src/main.rs @@ -121,7 +121,8 @@ pub unsafe fn rust_start() -> ! { // configure Physical Memory Protection to give supervisor mode // access to all of physical memory. - //pmpaddr0::write(0x3fffffffffffff); + pmpaddr0::write(0x3fffffffffffff); + pmpcfg0::write(0xf); //pmpcfg0::set_pmp(0, Range::TOR, Permission::RWX, false); // 0 < addr < pmpaddr0 // ask for clock interrupts. @@ -249,12 +250,12 @@ unsafe fn timer_init() { #[no_mangle] pub fn rust_main() -> ! { - //clear_bss(); + clear_bss(); - //println!("KERN: begin"); + println!("KERN: begin"); mm::init(); - loop{}; + //loop{}; //println!("KERN: init gpu"); //let _gpu = GPU_DEVICE.clone(); // println!("KERN: init keyboard"); From 6d1960ecd9b7f7841b1c717012bb359d97020f72 Mon Sep 17 00:00:00 2001 From: Yu Chen Date: Tue, 3 Jan 2023 09:32:36 +0800 Subject: [PATCH 26/68] explicitly UART.init() in rust_main --- os/src/drivers/chardev/mod.rs | 1 + os/src/drivers/chardev/ns16550a.rs | 8 +++++++- os/src/main.rs | 3 +++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/os/src/drivers/chardev/mod.rs b/os/src/drivers/chardev/mod.rs index de1446d..64c168f 100644 --- a/os/src/drivers/chardev/mod.rs +++ b/os/src/drivers/chardev/mod.rs @@ -6,6 +6,7 @@ use lazy_static::*; pub use ns16550a::NS16550a; pub trait CharDevice { + fn init(&self); fn read(&self) -> u8; fn write(&self, ch: u8); fn handle_irq(&self); diff --git a/os/src/drivers/chardev/ns16550a.rs b/os/src/drivers/chardev/ns16550a.rs index da29063..d10dd90 100644 --- a/os/src/drivers/chardev/ns16550a.rs +++ b/os/src/drivers/chardev/ns16550a.rs @@ -135,7 +135,7 @@ impl NS16550a { ns16550a: NS16550aRaw::new(BASE_ADDR), read_buffer: VecDeque::new(), }; - inner.ns16550a.init(); + //inner.ns16550a.init(); Self { inner: unsafe { UPIntrFreeCell::new(inner) }, condvar: Condvar::new(), @@ -144,6 +144,12 @@ impl NS16550a { } impl CharDevice for NS16550a { + fn init(&self){ + let mut inner = self.inner.exclusive_access(); + inner.ns16550a.init(); + drop(inner); + } + fn read(&self) -> u8 { loop { let mut inner = self.inner.exclusive_access(); diff --git a/os/src/main.rs b/os/src/main.rs index 299e4cf..6e91085 100644 --- a/os/src/main.rs +++ b/os/src/main.rs @@ -28,6 +28,8 @@ mod task; mod timer; mod trap; +use crate::drivers::chardev::CharDevice; +use crate::drivers::chardev::UART; //use syscall::create_desktop; //for test core::arch::global_asm!(include_str!("entry.asm")); @@ -55,6 +57,7 @@ lazy_static! { pub fn rust_main() -> ! { clear_bss(); mm::init(); + UART.init(); println!("KERN: init gpu"); let _gpu = GPU_DEVICE.clone(); println!("KERN: init keyboard"); From e71bbcbc8d2f51b89a0efe985be07e8966ffb211 Mon Sep 17 00:00:00 2001 From: Yu Chen Date: Tue, 3 Jan 2023 09:50:56 +0800 Subject: [PATCH 27/68] in gdb mode, OK. For the safety of TIMER_SCRATCH, put clear_bss Fn in rust_start. and explicitly UART.init in rust_main. --- os/src/drivers/chardev/mod.rs | 1 + os/src/drivers/chardev/ns16550a.rs | 7 ++++++- os/src/main.rs | 17 +++++++++-------- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/os/src/drivers/chardev/mod.rs b/os/src/drivers/chardev/mod.rs index de1446d..64c168f 100644 --- a/os/src/drivers/chardev/mod.rs +++ b/os/src/drivers/chardev/mod.rs @@ -6,6 +6,7 @@ use lazy_static::*; pub use ns16550a::NS16550a; pub trait CharDevice { + fn init(&self); fn read(&self) -> u8; fn write(&self, ch: u8); fn handle_irq(&self); diff --git a/os/src/drivers/chardev/ns16550a.rs b/os/src/drivers/chardev/ns16550a.rs index da29063..de53b3e 100644 --- a/os/src/drivers/chardev/ns16550a.rs +++ b/os/src/drivers/chardev/ns16550a.rs @@ -135,7 +135,7 @@ impl NS16550a { ns16550a: NS16550aRaw::new(BASE_ADDR), read_buffer: VecDeque::new(), }; - inner.ns16550a.init(); + //inner.ns16550a.init(); Self { inner: unsafe { UPIntrFreeCell::new(inner) }, condvar: Condvar::new(), @@ -144,6 +144,11 @@ impl NS16550a { } impl CharDevice for NS16550a { + fn init(&self){ + let mut inner = self.inner.exclusive_access(); + inner.ns16550a.init(); + drop(inner); + } fn read(&self) -> u8 { loop { let mut inner = self.inner.exclusive_access(); diff --git a/os/src/main.rs b/os/src/main.rs index 56fba0c..4440253 100644 --- a/os/src/main.rs +++ b/os/src/main.rs @@ -214,6 +214,7 @@ pub unsafe fn mie_write(x:usize){ } unsafe fn timer_init() { + clear_bss(); // each CPU has a separate source of timer interrupts //let id = mhartid::read(); @@ -246,19 +247,19 @@ unsafe fn timer_init() { //mie::set_mtimer(); } - +use crate::drivers::chardev::CharDevice; +use crate::drivers::chardev::UART; #[no_mangle] pub fn rust_main() -> ! { - clear_bss(); - - println!("KERN: begin"); - + //clear_bss(); mm::init(); + UART.init(); + println!("KERN: begin"); //loop{}; - //println!("KERN: init gpu"); - //let _gpu = GPU_DEVICE.clone(); - // println!("KERN: init keyboard"); + println!("KERN: init gpu"); + let _gpu = GPU_DEVICE.clone(); + println!("KERN: init keyboard"); // let _keyboard = KEYBOARD_DEVICE.clone(); //println!("KERN: init mouse"); //let _mouse = MOUSE_DEVICE.clone(); From 4aaa7f9206cbbb766dc8967e720daf75083aba33 Mon Sep 17 00:00:00 2001 From: Yu Chen Date: Tue, 3 Jan 2023 10:05:40 +0800 Subject: [PATCH 28/68] update code, now '-bios none' can get the same result as ch9 --- os/Makefile | 2 +- os/src/main.rs | 6 +++--- os/src/trap/mod.rs | 24 ++++++++++++------------ 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/os/Makefile b/os/Makefile index 4331ae5..6b7e9cf 100644 --- a/os/Makefile +++ b/os/Makefile @@ -71,7 +71,7 @@ disasm-vim: kernel @nvim $(DISASM_TMP) @rm $(DISASM_TMP) -run: run-inner-none +run: run-inner run-inner-none: build @qemu-system-riscv64 \ diff --git a/os/src/main.rs b/os/src/main.rs index 4440253..b9b5f15 100644 --- a/os/src/main.rs +++ b/os/src/main.rs @@ -260,9 +260,9 @@ pub fn rust_main() -> ! { println!("KERN: init gpu"); let _gpu = GPU_DEVICE.clone(); println!("KERN: init keyboard"); - // let _keyboard = KEYBOARD_DEVICE.clone(); - //println!("KERN: init mouse"); - //let _mouse = MOUSE_DEVICE.clone(); + let _keyboard = KEYBOARD_DEVICE.clone(); + println!("KERN: init mouse"); + let _mouse = MOUSE_DEVICE.clone(); println!("KERN: init trap"); trap::init(); //trap::enable_timer_interrupt(); diff --git a/os/src/trap/mod.rs b/os/src/trap/mod.rs index 05a9126..6040c7f 100644 --- a/os/src/trap/mod.rs +++ b/os/src/trap/mod.rs @@ -95,18 +95,18 @@ pub fn trap_handler() -> ! { Trap::Exception(Exception::IllegalInstruction) => { current_add_signal(SignalFlags::SIGILL); } - Trap::Interrupt(Interrupt::SupervisorTimer) => { - set_next_trigger(); - check_timer(); - suspend_current_and_run_next(); - } + // Trap::Interrupt(Interrupt::SupervisorTimer) => { + // set_next_trigger(); + // check_timer(); + // suspend_current_and_run_next(); + // } Trap::Interrupt(Interrupt::SupervisorSoft) => { //set_next_trigger(); const SSIP: usize = 1 << 1; unsafe { asm!("csrc sip, {}", in(reg) SSIP); } - println!("TRAP: ssoft in Kern"); + //println!("TRAP: ssoft in Kern"); check_timer(); // do not schedule now } @@ -161,18 +161,18 @@ pub fn trap_from_kernel(_trap_cx: &TrapContext) { Trap::Interrupt(Interrupt::SupervisorExternal) => { crate::board::irq_handler(); } - Trap::Interrupt(Interrupt::SupervisorTimer) => { - //set_next_trigger(); - check_timer(); - // do not schedule now - } + // Trap::Interrupt(Interrupt::SupervisorTimer) => { + // //set_next_trigger(); + // check_timer(); + // // do not schedule now + // } Trap::Interrupt(Interrupt::SupervisorSoft) => { //set_next_trigger(); const SSIP: usize = 1 << 1; unsafe { asm!("csrc sip, {}", in(reg) SSIP); } - println!("TRAP: ssoft in Kern"); + //println!("TRAP: ssoft in Kern"); check_timer(); // do not schedule now } From 944f114cf8c60adae51c6b3697aafdc8d3fa7f6d Mon Sep 17 00:00:00 2001 From: Yu Chen Date: Tue, 3 Jan 2023 18:34:45 +0800 Subject: [PATCH 29/68] update move_rect Fn --- os/src/gui/paint.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/os/src/gui/paint.rs b/os/src/gui/paint.rs index 0cdf60d..b96d187 100644 --- a/os/src/gui/paint.rs +++ b/os/src/gui/paint.rs @@ -28,7 +28,14 @@ impl DrawingBoard { .draw(&mut self.graphics) .ok(); } + fn unpaint(&mut self) { + Rectangle::with_center(self.latest_pos, Size::new(RECT_SIZE, RECT_SIZE)) + .into_styled(PrimitiveStyle::with_stroke(Rgb888::BLACK, 1)) + .draw(&mut self.graphics) + .ok(); + } pub fn move_rect(&mut self, dx: i32, dy: i32) { + self.unpaint(); self.latest_pos.x += dx; self.latest_pos.y += dy; self.paint(); From beaef1f3041d26ffb42360937d8ee02666948cb8 Mon Sep 17 00:00:00 2001 From: Yu Chen Date: Sat, 7 Jan 2023 16:11:41 +0800 Subject: [PATCH 30/68] simple gui app can run now! --- os/src/gui/graphic.rs | 4 ++++ os/src/mm/address.rs | 1 + os/src/mm/frame_allocator.rs | 3 +++ os/src/mm/memory_set.rs | 14 +++++++++++++- os/src/mm/mod.rs | 4 ++-- os/src/syscall/gui.rs | 37 ++++++++++++++++++++++++++++++++++++ os/src/syscall/mod.rs | 6 ++++++ user/Cargo.toml | 1 + user/src/bin/gui_simple.rs | 35 ++++++++++++++++++++++++++++++++++ user/src/lib.rs | 6 ++++++ user/src/syscall.rs | 11 +++++++++++ 11 files changed, 119 insertions(+), 3 deletions(-) create mode 100644 os/src/syscall/gui.rs create mode 100644 user/src/bin/gui_simple.rs diff --git a/os/src/gui/graphic.rs b/os/src/gui/graphic.rs index d13ad61..4c18a26 100644 --- a/os/src/gui/graphic.rs +++ b/os/src/gui/graphic.rs @@ -27,6 +27,10 @@ impl Graphics { let fb = self.drv.get_framebuffer(); fb.fill(0u8); } + + pub fn get_framebuffer(&self)-> &mut [u8] { + self.drv.get_framebuffer() + } } impl OriginDimensions for Graphics { diff --git a/os/src/mm/address.rs b/os/src/mm/address.rs index cf147a0..8792f62 100644 --- a/os/src/mm/address.rs +++ b/os/src/mm/address.rs @@ -260,3 +260,4 @@ where } } pub type VPNRange = SimpleRange; +pub type PPNRange = SimpleRange; diff --git a/os/src/mm/frame_allocator.rs b/os/src/mm/frame_allocator.rs index 1ecfe99..a280379 100644 --- a/os/src/mm/frame_allocator.rs +++ b/os/src/mm/frame_allocator.rs @@ -18,6 +18,9 @@ impl FrameTracker { } Self { ppn } } + pub fn new_nowrite(ppn: PhysPageNum) -> Self { + Self { ppn } + } } impl Debug for FrameTracker { diff --git a/os/src/mm/memory_set.rs b/os/src/mm/memory_set.rs index 663b68d..8875617 100644 --- a/os/src/mm/memory_set.rs +++ b/os/src/mm/memory_set.rs @@ -1,7 +1,7 @@ use super::{frame_alloc, FrameTracker}; use super::{PTEFlags, PageTable, PageTableEntry}; use super::{PhysAddr, PhysPageNum, VirtAddr, VirtPageNum}; -use super::{StepByOne, VPNRange}; +use super::{StepByOne, VPNRange, PPNRange}; use crate::config::{MEMORY_END, MMIO, PAGE_SIZE, TRAMPOLINE}; use crate::sync::UPIntrFreeCell; use alloc::collections::BTreeMap; @@ -78,6 +78,10 @@ impl MemorySet { } self.areas.push(map_area); } + pub fn push_noalloc(&mut self, mut map_area: MapArea, ppn_range: PPNRange) { + map_area.map_noalloc(&mut self.page_table, ppn_range); + self.areas.push(map_area); + } /// Mention that trampoline is not collected by areas. fn map_trampoline(&mut self) { self.page_table.map( @@ -301,6 +305,14 @@ impl MapArea { self.map_one(page_table, vpn); } } + pub fn map_noalloc(&mut self, page_table: &mut PageTable,ppn_range:PPNRange) { + for (vpn,ppn) in core::iter::zip(self.vpn_range,ppn_range) { + self.data_frames.insert(vpn, FrameTracker::new_nowrite(ppn)); + let pte_flags = PTEFlags::from_bits(self.map_perm.bits).unwrap(); + page_table.map(vpn, ppn, pte_flags); + } + } + pub fn unmap(&mut self, page_table: &mut PageTable) { for vpn in self.vpn_range { self.unmap_one(page_table, vpn); diff --git a/os/src/mm/mod.rs b/os/src/mm/mod.rs index 34220c4..9482a30 100644 --- a/os/src/mm/mod.rs +++ b/os/src/mm/mod.rs @@ -4,11 +4,11 @@ mod heap_allocator; mod memory_set; mod page_table; -use address::VPNRange; +pub use address::{VPNRange, PPNRange}; pub use address::{PhysAddr, PhysPageNum, StepByOne, VirtAddr, VirtPageNum}; pub use frame_allocator::{frame_alloc, frame_dealloc, FrameTracker}; pub use memory_set::remap_test; -pub use memory_set::{kernel_token, MapPermission, MemorySet, KERNEL_SPACE}; +pub use memory_set::{kernel_token, MapPermission, MemorySet, MapArea, MapType, KERNEL_SPACE}; use page_table::PTEFlags; pub use page_table::{ translated_byte_buffer, translated_ref, translated_refmut, translated_str, PageTable, diff --git a/os/src/syscall/gui.rs b/os/src/syscall/gui.rs new file mode 100644 index 0000000..0018604 --- /dev/null +++ b/os/src/syscall/gui.rs @@ -0,0 +1,37 @@ +use crate::mm::{MapArea, MapPermission, MapType, PPNRange, PhysAddr}; +use crate::task::current_process; + +//use crate::gui::*; +use crate::drivers::GPU_DEVICE; + +const FB_VADDR: usize = 0x10000000; + +pub fn sys_framebuffer() -> isize { + let gpu = GPU_DEVICE.clone(); + let fb = gpu.get_framebuffer(); + let len = fb.len(); + println!("[kernel] FrameBuffer: addr 0x{:X}, len {}", fb.as_ptr() as usize , len); + let fb_ppn = PhysAddr::from(fb.as_ptr() as usize).floor(); + let fb_end_ppn = PhysAddr::from(fb.as_ptr() as usize + len).ceil(); + + let current_process = current_process(); + let mut inner = current_process.inner_exclusive_access(); + let mem_set = &mut inner.memory_set; + + mem_set.push_noalloc( + MapArea::new( + (FB_VADDR as usize).into(), + (FB_VADDR + len as usize).into(), + MapType::Framed, + MapPermission::R | MapPermission::W | MapPermission::U, + ), + PPNRange::new(fb_ppn, fb_end_ppn), + ); + FB_VADDR as isize +} + +pub fn sys_framebuffer_flush() -> isize { + let gpu = GPU_DEVICE.clone(); + gpu.flush(); + 0 +} \ No newline at end of file diff --git a/os/src/syscall/mod.rs b/os/src/syscall/mod.rs index fa4a4cf..3f95b94 100644 --- a/os/src/syscall/mod.rs +++ b/os/src/syscall/mod.rs @@ -25,16 +25,20 @@ const SYSCALL_SEMAPHORE_DOWN: usize = 1022; const SYSCALL_CONDVAR_CREATE: usize = 1030; const SYSCALL_CONDVAR_SIGNAL: usize = 1031; const SYSCALL_CONDVAR_WAIT: usize = 1032; +const SYSCALL_FRAMEBUFFER: usize = 2000; +const SYSCALL_FRAMEBUFFER_FLUSH: usize = 2001; mod fs; mod process; mod sync; mod thread; +mod gui; use fs::*; use process::*; use sync::*; use thread::*; +use gui::*; pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize { match syscall_id { @@ -65,6 +69,8 @@ pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize { SYSCALL_CONDVAR_CREATE => sys_condvar_create(args[0]), SYSCALL_CONDVAR_SIGNAL => sys_condvar_signal(args[0]), SYSCALL_CONDVAR_WAIT => sys_condvar_wait(args[0], args[1]), + SYSCALL_FRAMEBUFFER => sys_framebuffer(), + SYSCALL_FRAMEBUFFER_FLUSH => sys_framebuffer_flush(), _ => panic!("Unsupported syscall_id: {}", syscall_id), } } diff --git a/user/Cargo.toml b/user/Cargo.toml index a609f4d..d8d10cc 100644 --- a/user/Cargo.toml +++ b/user/Cargo.toml @@ -10,6 +10,7 @@ edition = "2018" buddy_system_allocator = "0.6" bitflags = "1.2.1" riscv = { git = "https://github.com/rcore-os/riscv", features = ["inline-asm"] } +embedded-graphics = "0.7.1" [profile.release] debug = true diff --git a/user/src/bin/gui_simple.rs b/user/src/bin/gui_simple.rs new file mode 100644 index 0000000..df4cfbb --- /dev/null +++ b/user/src/bin/gui_simple.rs @@ -0,0 +1,35 @@ +#![no_std] +#![no_main] + +use user_lib::{framebuffer, framebuffer_flush}; + +#[macro_use] +extern crate user_lib; + +// use embedded_graphics::pixelcolor::Rgb888; +// use embedded_graphics::prelude::{Drawable, Point, RgbColor, Size}; +// use embedded_graphics::primitives::Primitive; +// use embedded_graphics::primitives::{PrimitiveStyle, Rectangle}; +// use embedded_graphics::{ +// draw_target::DrawTarget, +// prelude::{OriginDimensions}, +// }; +pub const VIRTGPU_XRES: usize = 1280; +pub const VIRTGPU_YRES: usize = 800; + +#[no_mangle] +pub fn main() -> i32 { + let fb_ptr =framebuffer() as *mut u8; + println!("Hello world from user mode program! 0x{:X} , len {}", fb_ptr as usize, VIRTGPU_XRES*VIRTGPU_YRES*4); + let fb= unsafe {core::slice::from_raw_parts_mut(fb_ptr as *mut u8, VIRTGPU_XRES*VIRTGPU_YRES*4 as usize)}; + for y in 0..800 { + for x in 0..1280 { + let idx = (y * 1280 + x) * 4; + fb[idx] = x as u8; + fb[idx + 1] = y as u8; + fb[idx + 2] = (x + y) as u8; + } + } + framebuffer_flush(); + 0 +} diff --git a/user/src/lib.rs b/user/src/lib.rs index 729eaef..16d4abd 100644 --- a/user/src/lib.rs +++ b/user/src/lib.rs @@ -198,6 +198,12 @@ pub fn condvar_signal(condvar_id: usize) { pub fn condvar_wait(condvar_id: usize, mutex_id: usize) { sys_condvar_wait(condvar_id, mutex_id); } +pub fn framebuffer() -> isize { + sys_framebuffer() +} +pub fn framebuffer_flush() -> isize { + sys_framebuffer_flush() +} #[macro_export] macro_rules! vstore { diff --git a/user/src/syscall.rs b/user/src/syscall.rs index b4bb67a..330388c 100644 --- a/user/src/syscall.rs +++ b/user/src/syscall.rs @@ -25,6 +25,8 @@ const SYSCALL_SEMAPHORE_DOWN: usize = 1022; const SYSCALL_CONDVAR_CREATE: usize = 1030; const SYSCALL_CONDVAR_SIGNAL: usize = 1031; const SYSCALL_CONDVAR_WAIT: usize = 1032; +const SYSCALL_FRAMEBUFFER: usize = 2000; +const SYSCALL_FRAMEBUFFER_FLUSH: usize = 2001; fn syscall(id: usize, args: [usize; 3]) -> isize { let mut ret: isize; @@ -154,3 +156,12 @@ pub fn sys_condvar_signal(condvar_id: usize) -> isize { pub fn sys_condvar_wait(condvar_id: usize, mutex_id: usize) -> isize { syscall(SYSCALL_CONDVAR_WAIT, [condvar_id, mutex_id, 0]) } + + +pub fn sys_framebuffer() -> isize { + syscall(SYSCALL_FRAMEBUFFER, [0, 0, 0]) +} + +pub fn sys_framebuffer_flush() -> isize { + syscall(SYSCALL_FRAMEBUFFER_FLUSH, [0, 0, 0]) +} \ No newline at end of file From e0eb517517fd124e6f49f59b4a68260ebc9b2ecd Mon Sep 17 00:00:00 2001 From: Yu Chen Date: Sat, 7 Jan 2023 18:17:43 +0800 Subject: [PATCH 31/68] add embedded-graphics crate, but compiling error --- user/Cargo.toml | 1 + user/src/bin/embed_graph.rs | 173 ++++++++++++++++++++++++++++++++++++ 2 files changed, 174 insertions(+) create mode 100644 user/src/bin/embed_graph.rs diff --git a/user/Cargo.toml b/user/Cargo.toml index d8d10cc..6666a5a 100644 --- a/user/Cargo.toml +++ b/user/Cargo.toml @@ -11,6 +11,7 @@ buddy_system_allocator = "0.6" bitflags = "1.2.1" riscv = { git = "https://github.com/rcore-os/riscv", features = ["inline-asm"] } embedded-graphics = "0.7.1" +# lazy_static = { version = "1.4.0", features = ["spin_no_std"] } [profile.release] debug = true diff --git a/user/src/bin/embed_graph.rs b/user/src/bin/embed_graph.rs new file mode 100644 index 0000000..bbe4faf --- /dev/null +++ b/user/src/bin/embed_graph.rs @@ -0,0 +1,173 @@ +#![no_std] +#![no_main] + +use user_lib::{framebuffer, framebuffer_flush}; + +#[macro_use] +extern crate user_lib; + +extern crate alloc; + +use alloc::sync::Arc; +use embedded_graphics::pixelcolor::Rgb888; +use embedded_graphics::prelude::{Drawable, Point, RgbColor, Size}; +use embedded_graphics::primitives::Primitive; +use embedded_graphics::primitives::{PrimitiveStyle, Rectangle}; +use embedded_graphics::{draw_target::DrawTarget, prelude::OriginDimensions}; + +pub const VIRTGPU_XRES: usize = 1280; +pub const VIRTGPU_YRES: usize = 800; +pub const VIRTGPU_LEN: usize = VIRTGPU_XRES * VIRTGPU_YRES * 4; + +const INIT_X: i32 = 640; +const INIT_Y: i32 = 400; +const RECT_SIZE: u32 = 40; + +// lazy_static::lazy_static! { +// pub static ref FB: Arc = Arc::new(Display::new(Size::new(VIRTGPU_XRES as u32, VIRTGPU_YRES as u32), Point::new(INIT_X, INIT_Y))); +// } + +#[derive(Clone)] +pub struct Display { + pub size: Size, + pub point: Point, + pub fb: Arc<&'static mut [u8]>, +} + +impl Display { + pub fn new(size: Size, point: Point) -> Self { + let fb_ptr = framebuffer() as *mut u8; + println!( + "Hello world from user mode program! 0x{:X} , len {}", + fb_ptr as usize, VIRTGPU_LEN + ); + let fb = + unsafe { Arc::new(core::slice::from_raw_parts_mut(fb_ptr as *mut u8, VIRTGPU_LEN as usize)) }; + + Self { size, point, fb } + } + // pub fn reset(&self) { + // let fb = self.drv.get_framebuffer(); + // fb.fill(0u8); + // } +} + +impl OriginDimensions for Display { + fn size(&self) -> Size { + self.size + } +} + +impl DrawTarget for Display { + type Color = Rgb888; + + type Error = core::convert::Infallible; + + fn draw_iter(&mut self, pixels: I) -> Result<(), Self::Error> + where + I: IntoIterator>, + { + let fb = self.fb.clone(); + //let mut arc_data_mut = Arc::make_mut(fb); + pixels.into_iter().for_each(|px| { + let idx = ((self.point.y + px.0.y) * VIRTGPU_XRES as i32 + self.point.x + px.0.x) + as usize + * 4; + if idx + 2 >= fb.len() { + return; + } + fb[idx] = px.1.b(); + fb[idx + 1] = px.1.g(); + fb[idx + 2] = px.1.r(); + }); + framebuffer_flush(); + Ok(()) + } +} + +pub struct DrawingBoard { + disp: Display, + latest_pos: Point, +} + +impl DrawingBoard { + pub fn new() -> Self { + Self { + disp: Display::new(Size::new(1280, 800), Point::new(0, 0)), + latest_pos: Point::new(INIT_X, INIT_Y), + } + } + fn paint(&mut self) { + Rectangle::with_center(self.latest_pos, Size::new(RECT_SIZE, RECT_SIZE)) + .into_styled(PrimitiveStyle::with_stroke(Rgb888::WHITE, 1)) + .draw(&mut self.disp) + .ok(); + } + fn unpaint(&mut self) { + Rectangle::with_center(self.latest_pos, Size::new(RECT_SIZE, RECT_SIZE)) + .into_styled(PrimitiveStyle::with_stroke(Rgb888::BLACK, 1)) + .draw(&mut self.disp) + .ok(); + } + pub fn move_rect(&mut self, dx: i32, dy: i32) { + self.unpaint(); + self.latest_pos.x += dx; + self.latest_pos.y += dy; + self.paint(); + } + + // pub fn reset(&mut self) { + // self.latest_pos = Point::new(INIT_X, INIT_Y); + // self.disp.reset(); + // } +} + +// lazy_static! { +// pub static ref DRAWING_BOARD: UPIntrFreeCell = +// unsafe { UPIntrFreeCell::new(DrawingBoard::new()) }; +// } + +// pub fn init_paint() { +// DRAWING_BOARD.exclusive_session(|ripple| { +// ripple.paint(); +// }); +// } + +// pub fn move_rect(dx: i32, dy: i32) { +// DRAWING_BOARD.exclusive_session(|ripple| { +// ripple.move_rect(dx, dy); +// }); +// } + +// pub fn reset() { +// DRAWING_BOARD.exclusive_session(|ripple| { +// ripple.reset(); +// }); +// } + +#[no_mangle] +pub fn main() -> i32 { + // let fb_ptr = framebuffer() as *mut u8; + let mut board=DrawingBoard::new(); + board.paint(); + for i in 0..100 { + board.latest_pos.x += i; + board.latest_pos.y += i; + board.paint(); + } + // println!( + // "Hello world from user mode program! 0x{:X} , len {}", + // fb_ptr as usize, VIRTGPU_LEN + // ); + // let fb = unsafe { core::slice::from_raw_parts_mut(fb_ptr as *mut u8, VIRTGPU_LEN as usize) }; + // for y in 0..800 { + // for x in 0..1280 { + // let idx = (y * 1280 + x) * 4; + // fb[idx] = x as u8; + // fb[idx + 1] = y as u8; + // fb[idx + 2] = (x + y) as u8; + // } + // } + // framebuffer_flush(); + 0 +} From f2635c2dba575b64d365331020f3fb6a496c9bd3 Mon Sep 17 00:00:00 2001 From: Yu Chen Date: Sat, 7 Jan 2023 18:53:48 +0800 Subject: [PATCH 32/68] fix compiling err in usr/src/bin/embed_graph.rs --- user/src/bin/embed_graph.rs | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/user/src/bin/embed_graph.rs b/user/src/bin/embed_graph.rs index bbe4faf..b7886a7 100644 --- a/user/src/bin/embed_graph.rs +++ b/user/src/bin/embed_graph.rs @@ -27,11 +27,12 @@ const RECT_SIZE: u32 = 40; // pub static ref FB: Arc = Arc::new(Display::new(Size::new(VIRTGPU_XRES as u32, VIRTGPU_YRES as u32), Point::new(INIT_X, INIT_Y))); // } -#[derive(Clone)] +//#[derive(Clone)] pub struct Display { pub size: Size, pub point: Point, - pub fb: Arc<&'static mut [u8]>, + //pub fb: Arc<&'static mut [u8]>, + pub fb: &'static mut [u8], } impl Display { @@ -41,9 +42,9 @@ impl Display { "Hello world from user mode program! 0x{:X} , len {}", fb_ptr as usize, VIRTGPU_LEN ); - let fb = - unsafe { Arc::new(core::slice::from_raw_parts_mut(fb_ptr as *mut u8, VIRTGPU_LEN as usize)) }; - + // let fb = + // unsafe { Arc::new(core::slice::from_raw_parts_mut(fb_ptr as *mut u8, VIRTGPU_LEN as usize)) }; + let fb= unsafe { core::slice::from_raw_parts_mut(fb_ptr as *mut u8, VIRTGPU_LEN as usize) }; Self { size, point, fb } } // pub fn reset(&self) { @@ -67,18 +68,19 @@ impl DrawTarget for Display { where I: IntoIterator>, { - let fb = self.fb.clone(); + //let fb = self.fb.clone(); + //let fb = self.fb; //let mut arc_data_mut = Arc::make_mut(fb); pixels.into_iter().for_each(|px| { let idx = ((self.point.y + px.0.y) * VIRTGPU_XRES as i32 + self.point.x + px.0.x) as usize * 4; - if idx + 2 >= fb.len() { + if idx + 2 >= self.fb.len() { return; } - fb[idx] = px.1.b(); - fb[idx + 1] = px.1.g(); - fb[idx + 2] = px.1.r(); + self.fb[idx] = px.1.b(); + self.fb[idx + 1] = px.1.g(); + self.fb[idx + 2] = px.1.r(); }); framebuffer_flush(); Ok(()) From 2dfd1958413963cdea29b5403057ddca025a9ad7 Mon Sep 17 00:00:00 2001 From: Yu Chen Date: Sat, 7 Jan 2023 19:14:20 +0800 Subject: [PATCH 33/68] clean os/user codes for graph show --- os/src/drivers/input/mod.rs | 20 +---------- os/src/gui/graphic.rs | 67 ----------------------------------- os/src/gui/mod.rs | 5 --- os/src/gui/paint.rs | 69 ------------------------------------- os/src/main.rs | 3 +- user/src/bin/embed_graph.rs | 67 +++-------------------------------- 6 files changed, 7 insertions(+), 224 deletions(-) delete mode 100644 os/src/gui/graphic.rs delete mode 100644 os/src/gui/mod.rs delete mode 100644 os/src/gui/paint.rs diff --git a/os/src/drivers/input/mod.rs b/os/src/drivers/input/mod.rs index cbe8933..0db7603 100644 --- a/os/src/drivers/input/mod.rs +++ b/os/src/drivers/input/mod.rs @@ -1,8 +1,5 @@ use crate::drivers::bus::virtio::VirtioHal; -use crate::{ - gui::{move_rect, reset}, - sync::UPIntrFreeCell, -}; +use crate::sync::UPIntrFreeCell; use alloc::sync::Arc; use core::any::Any; use virtio_drivers::{VirtIOHeader, VirtIOInput}; @@ -49,21 +46,6 @@ impl InputDevice for VirtIOInputWrapper { virtio_input_decoder::DecodeType::Key(key, r#type) => { if r#type == KeyType::Press { match key { - Key::C | Key::MouseLeft => { - reset(); - } - Key::W => { - move_rect(0, -10); - } - Key::S => { - move_rect(0, 10); - } - Key::A => { - move_rect(-10, 0); - } - Key::D => { - move_rect(10, 0); - } _ => {} } } diff --git a/os/src/gui/graphic.rs b/os/src/gui/graphic.rs deleted file mode 100644 index 4c18a26..0000000 --- a/os/src/gui/graphic.rs +++ /dev/null @@ -1,67 +0,0 @@ -use alloc::sync::Arc; -use embedded_graphics::{ - draw_target::DrawTarget, - pixelcolor::Rgb888, - prelude::{OriginDimensions, Point, RgbColor, Size}, -}; - -use crate::board::VIRTGPU_XRES; -use crate::drivers::{GpuDevice, GPU_DEVICE}; - -#[derive(Clone)] -pub struct Graphics { - pub size: Size, - pub point: Point, - pub drv: Arc, -} - -impl Graphics { - pub fn new(size: Size, point: Point) -> Self { - Self { - size, - point, - drv: GPU_DEVICE.clone(), - } - } - pub fn reset(&self) { - let fb = self.drv.get_framebuffer(); - fb.fill(0u8); - } - - pub fn get_framebuffer(&self)-> &mut [u8] { - self.drv.get_framebuffer() - } -} - -impl OriginDimensions for Graphics { - fn size(&self) -> Size { - self.size - } -} - -impl DrawTarget for Graphics { - type Color = Rgb888; - - type Error = core::convert::Infallible; - - fn draw_iter(&mut self, pixels: I) -> Result<(), Self::Error> - where - I: IntoIterator>, - { - let fb = self.drv.get_framebuffer(); - - pixels.into_iter().for_each(|px| { - let idx = ((self.point.y + px.0.y) * VIRTGPU_XRES as i32 + self.point.x + px.0.x) - as usize - * 4; - if idx + 2 >= fb.len() { - return; - } - fb[idx] = px.1.b(); - fb[idx + 1] = px.1.g(); - fb[idx + 2] = px.1.r(); - }); - self.drv.flush(); - Ok(()) - } -} diff --git a/os/src/gui/mod.rs b/os/src/gui/mod.rs deleted file mode 100644 index 766ded8..0000000 --- a/os/src/gui/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -mod graphic; -mod paint; - -use graphic::Graphics; -pub use paint::{init_paint, move_rect, reset}; diff --git a/os/src/gui/paint.rs b/os/src/gui/paint.rs deleted file mode 100644 index b96d187..0000000 --- a/os/src/gui/paint.rs +++ /dev/null @@ -1,69 +0,0 @@ -use super::Graphics; -use crate::sync::UPIntrFreeCell; -use embedded_graphics::pixelcolor::Rgb888; -use embedded_graphics::prelude::{Drawable, Point, RgbColor, Size}; -use embedded_graphics::primitives::Primitive; -use embedded_graphics::primitives::{PrimitiveStyle, Rectangle}; -use lazy_static::*; - -const INIT_X: i32 = 640; -const INIT_Y: i32 = 400; -const RECT_SIZE: u32 = 40; - -pub struct DrawingBoard { - graphics: Graphics, - latest_pos: Point, -} - -impl DrawingBoard { - pub fn new() -> Self { - Self { - graphics: Graphics::new(Size::new(1280, 800), Point::new(0, 0)), - latest_pos: Point::new(INIT_X, INIT_Y), - } - } - fn paint(&mut self) { - Rectangle::with_center(self.latest_pos, Size::new(RECT_SIZE, RECT_SIZE)) - .into_styled(PrimitiveStyle::with_stroke(Rgb888::WHITE, 1)) - .draw(&mut self.graphics) - .ok(); - } - fn unpaint(&mut self) { - Rectangle::with_center(self.latest_pos, Size::new(RECT_SIZE, RECT_SIZE)) - .into_styled(PrimitiveStyle::with_stroke(Rgb888::BLACK, 1)) - .draw(&mut self.graphics) - .ok(); - } - pub fn move_rect(&mut self, dx: i32, dy: i32) { - self.unpaint(); - self.latest_pos.x += dx; - self.latest_pos.y += dy; - self.paint(); - } - pub fn reset(&mut self) { - self.latest_pos = Point::new(INIT_X, INIT_Y); - self.graphics.reset(); - } -} - -lazy_static! { - pub static ref DRAWING_BOARD: UPIntrFreeCell = unsafe { UPIntrFreeCell::new(DrawingBoard::new()) }; -} - -pub fn init_paint() { - DRAWING_BOARD.exclusive_session(|ripple| { - ripple.paint(); - }); -} - -pub fn move_rect(dx: i32, dy: i32) { - DRAWING_BOARD.exclusive_session(|ripple| { - ripple.move_rect(dx, dy); - }); -} - -pub fn reset() { - DRAWING_BOARD.exclusive_session(|ripple| { - ripple.reset(); - }); -} diff --git a/os/src/main.rs b/os/src/main.rs index 6e91085..a220bd7 100644 --- a/os/src/main.rs +++ b/os/src/main.rs @@ -18,7 +18,6 @@ mod console; mod config; mod drivers; mod fs; -mod gui; mod lang_items; mod mm; mod sbi; @@ -70,7 +69,7 @@ pub fn rust_main() -> ! { timer::set_next_trigger(); board::device_init(); fs::list_apps(); - gui::init_paint(); + //gui::init_paint(); task::add_initproc(); *DEV_NON_BLOCKING_ACCESS.exclusive_access() = true; task::run_tasks(); diff --git a/user/src/bin/embed_graph.rs b/user/src/bin/embed_graph.rs index b7886a7..3866994 100644 --- a/user/src/bin/embed_graph.rs +++ b/user/src/bin/embed_graph.rs @@ -8,7 +8,6 @@ extern crate user_lib; extern crate alloc; -use alloc::sync::Arc; use embedded_graphics::pixelcolor::Rgb888; use embedded_graphics::prelude::{Drawable, Point, RgbColor, Size}; use embedded_graphics::primitives::Primitive; @@ -23,11 +22,6 @@ const INIT_X: i32 = 640; const INIT_Y: i32 = 400; const RECT_SIZE: u32 = 40; -// lazy_static::lazy_static! { -// pub static ref FB: Arc = Arc::new(Display::new(Size::new(VIRTGPU_XRES as u32, VIRTGPU_YRES as u32), Point::new(INIT_X, INIT_Y))); -// } - -//#[derive(Clone)] pub struct Display { pub size: Size, pub point: Point, @@ -42,15 +36,10 @@ impl Display { "Hello world from user mode program! 0x{:X} , len {}", fb_ptr as usize, VIRTGPU_LEN ); - // let fb = - // unsafe { Arc::new(core::slice::from_raw_parts_mut(fb_ptr as *mut u8, VIRTGPU_LEN as usize)) }; - let fb= unsafe { core::slice::from_raw_parts_mut(fb_ptr as *mut u8, VIRTGPU_LEN as usize) }; + let fb = + unsafe { core::slice::from_raw_parts_mut(fb_ptr as *mut u8, VIRTGPU_LEN as usize) }; Self { size, point, fb } } - // pub fn reset(&self) { - // let fb = self.drv.get_framebuffer(); - // fb.fill(0u8); - // } } impl OriginDimensions for Display { @@ -68,9 +57,6 @@ impl DrawTarget for Display { where I: IntoIterator>, { - //let fb = self.fb.clone(); - //let fb = self.fb; - //let mut arc_data_mut = Arc::make_mut(fb); pixels.into_iter().for_each(|px| { let idx = ((self.point.y + px.0.y) * VIRTGPU_XRES as i32 + self.point.x + px.0.x) as usize @@ -117,59 +103,16 @@ impl DrawingBoard { self.latest_pos.y += dy; self.paint(); } - - // pub fn reset(&mut self) { - // self.latest_pos = Point::new(INIT_X, INIT_Y); - // self.disp.reset(); - // } } -// lazy_static! { -// pub static ref DRAWING_BOARD: UPIntrFreeCell = -// unsafe { UPIntrFreeCell::new(DrawingBoard::new()) }; -// } - -// pub fn init_paint() { -// DRAWING_BOARD.exclusive_session(|ripple| { -// ripple.paint(); -// }); -// } - -// pub fn move_rect(dx: i32, dy: i32) { -// DRAWING_BOARD.exclusive_session(|ripple| { -// ripple.move_rect(dx, dy); -// }); -// } - -// pub fn reset() { -// DRAWING_BOARD.exclusive_session(|ripple| { -// ripple.reset(); -// }); -// } - #[no_mangle] pub fn main() -> i32 { // let fb_ptr = framebuffer() as *mut u8; - let mut board=DrawingBoard::new(); - board.paint(); - for i in 0..100 { + let mut board = DrawingBoard::new(); + for i in 0..20 { board.latest_pos.x += i; board.latest_pos.y += i; - board.paint(); + board.paint(); } - // println!( - // "Hello world from user mode program! 0x{:X} , len {}", - // fb_ptr as usize, VIRTGPU_LEN - // ); - // let fb = unsafe { core::slice::from_raw_parts_mut(fb_ptr as *mut u8, VIRTGPU_LEN as usize) }; - // for y in 0..800 { - // for x in 0..1280 { - // let idx = (y * 1280 + x) * 4; - // fb[idx] = x as u8; - // fb[idx + 1] = y as u8; - // fb[idx + 2] = (x + y) as u8; - // } - // } - // framebuffer_flush(); 0 } From a67f3f0d2f80003c7a883e4417cf9109aaa71332 Mon Sep 17 00:00:00 2001 From: Yu Chen Date: Sat, 7 Jan 2023 23:35:11 +0800 Subject: [PATCH 34/68] add get input_dev events in user app, but still have some problems --- os/Cargo.toml | 4 +- os/src/drivers/input/mod.rs | 122 +++++++++++++++++++++++++-------- os/src/main.rs | 3 +- os/src/syscall/input.rs | 17 +++++ os/src/syscall/mod.rs | 4 ++ user/src/bin/inputdev_event.rs | 21 ++++++ user/src/lib.rs | 5 ++ user/src/syscall.rs | 5 ++ 8 files changed, 151 insertions(+), 30 deletions(-) create mode 100644 os/src/syscall/input.rs create mode 100644 user/src/bin/inputdev_event.rs diff --git a/os/Cargo.toml b/os/Cargo.toml index f4b2d80..633ec10 100644 --- a/os/Cargo.toml +++ b/os/Cargo.toml @@ -13,7 +13,9 @@ buddy_system_allocator = "0.6" bitflags = "1.2.1" xmas-elf = "0.7.0" volatile = "0.3" -virtio-drivers = { git = "https://github.com/rcore-os/virtio-drivers", rev = "4ee80e5" } +#virtio-drivers = { git = "https://github.com/rcore-os/virtio-drivers", rev = "4ee80e5" } +virtio-drivers = { git = "https://github.com/rcore-os/virtio-drivers", rev = "70b5850" } + easy-fs = { path = "../easy-fs" } virtio-input-decoder = "0.1.4" embedded-graphics = "0.7.1" diff --git a/os/src/drivers/input/mod.rs b/os/src/drivers/input/mod.rs index 0db7603..76c64f7 100644 --- a/os/src/drivers/input/mod.rs +++ b/os/src/drivers/input/mod.rs @@ -1,5 +1,8 @@ use crate::drivers::bus::virtio::VirtioHal; -use crate::sync::UPIntrFreeCell; +use crate::sync::{Condvar, UPIntrFreeCell}; +use crate::task::schedule; +use alloc::collections::BTreeMap; +use alloc::collections::VecDeque; use alloc::sync::Arc; use core::any::Any; use virtio_drivers::{VirtIOHeader, VirtIOInput}; @@ -8,50 +11,113 @@ use virtio_input_decoder::{Decoder, Key, KeyType}; const VIRTIO5: usize = 0x10005000; const VIRTIO6: usize = 0x10006000; -struct VirtIOInputWrapper(UPIntrFreeCell>); +struct VirtIOInputInner { + virtio_input: VirtIOInput<'static, VirtioHal>, + events: VecDeque, +} + +struct VirtIOInputWrapper { + inner: UPIntrFreeCell, + //condvars: BTreeMap, + //condvar: Arc:: , + condvar:Condvar, +} pub trait InputDevice: Send + Sync + Any { + fn read_event(&self) -> u64; fn handle_irq(&self); + // fn events(&self) -> &VecDeque; + fn is_empty(&self) -> bool; } lazy_static::lazy_static!( pub static ref KEYBOARD_DEVICE: Arc = Arc::new(VirtIOInputWrapper::new(VIRTIO5)); pub static ref MOUSE_DEVICE: Arc = Arc::new(VirtIOInputWrapper::new(VIRTIO6)); + // pub static ref INPUT_CONDVAR: Arc:: = Arc::new(Condvar::new()); ); +// from virtio-drivers/src/input.rs +//const QUEUE_SIZE: u16 = 32; +// pub fn read_input_event() -> u64 { +// loop { + +// //let mut inner = self.inner.exclusive_access(); +// let kb=KEYBOARD_DEVICE.clone(); +// let evs = kb.events(); +// if let Some(event) = evs.pop_front() { +// return event; +// } else { +// let task_cx_ptr = INPUT_CONDVAR.clone().wait_no_sched(); +// drop(inner); +// schedule(task_cx_ptr); +// } +// } +// } impl VirtIOInputWrapper { pub fn new(addr: usize) -> Self { - Self(unsafe { - UPIntrFreeCell::new( - VirtIOInput::::new(&mut *(addr as *mut VirtIOHeader)).unwrap(), - ) - }) + let inner = VirtIOInputInner { + virtio_input: unsafe { + VirtIOInput::::new(&mut *(addr as *mut VirtIOHeader)).unwrap() + }, + events: VecDeque::new(), + }; + + // let mut condvars = BTreeMap::new(); + // let channels = QUEUE_SIZE; + // for i in 0..channels { + // let condvar = Condvar::new(); + // condvars.insert(i, condvar); + // } + + Self { + inner: unsafe { UPIntrFreeCell::new(inner) }, + //condvar: INPUT_CONDVAR.clone(), + condvar: Condvar::new(), + } } } impl InputDevice for VirtIOInputWrapper { - fn handle_irq(&self) { - let mut input = self.0.exclusive_access(); - input.ack_interrupt(); - while let Some(event) = input.pop_pending_event() { - let dtype = match Decoder::decode( - event.event_type as usize, - event.code as usize, - event.value as usize, - ) { - Ok(dtype) => dtype, - Err(_) => break, - }; - match dtype { - virtio_input_decoder::DecodeType::Key(key, r#type) => { - if r#type == KeyType::Press { - match key { - _ => {} - } - } - } - _ => {} + fn is_empty(&self) -> bool { + self.inner.exclusive_access().events.is_empty() + } + + fn read_event(&self) -> u64 { + loop { + let mut inner = self.inner.exclusive_access(); + if let Some(event) = inner.events.pop_front() { + return event; + } else { + let task_cx_ptr = self.condvar.wait_no_sched(); + drop(inner); + schedule(task_cx_ptr); } } } + + // fn events(&self) -> &VecDeque { + // &self.inner.exclusive_access().events + // } + + fn handle_irq(&self) { + let mut count = 0; + let mut result = 0; + let mut key = 0; + self.inner.exclusive_session(|inner| { + inner.virtio_input.ack_interrupt(); + while let Some((token, event)) = inner.virtio_input.pop_pending_event() { + count += 1; + key = token; + result = (event.event_type as u64) << 48 + | (event.code as u64) << 32 + | (event.value) as u64; + inner.events.push_back(result); + println!("[KERN] inputdev_handle_irq: event: {:x}", result); + } + }); + if count > 0 { + //self.condvars.get(&key).unwrap().signal(); + self.condvar.signal(); + }; + } } diff --git a/os/src/main.rs b/os/src/main.rs index a220bd7..7e5a20a 100644 --- a/os/src/main.rs +++ b/os/src/main.rs @@ -3,8 +3,8 @@ #![feature(panic_info_message)] #![feature(alloc_error_handler)] +//use crate::drivers::{GPU_DEVICE, KEYBOARD_DEVICE, MOUSE_DEVICE, INPUT_CONDVAR}; use crate::drivers::{GPU_DEVICE, KEYBOARD_DEVICE, MOUSE_DEVICE}; - extern crate alloc; #[macro_use] @@ -59,6 +59,7 @@ pub fn rust_main() -> ! { UART.init(); println!("KERN: init gpu"); let _gpu = GPU_DEVICE.clone(); + //let _input_condvar = INPUT_CONDVAR.clone(); println!("KERN: init keyboard"); let _keyboard = KEYBOARD_DEVICE.clone(); println!("KERN: init mouse"); diff --git a/os/src/syscall/input.rs b/os/src/syscall/input.rs new file mode 100644 index 0000000..9f59710 --- /dev/null +++ b/os/src/syscall/input.rs @@ -0,0 +1,17 @@ +//use crate::drivers::{KEYBOARD_DEVICE,MOUSE_DEVICE,INPUT_CONDVAR,read_input_event}; +use crate::drivers::{KEYBOARD_DEVICE,MOUSE_DEVICE}; + +pub fn sys_event_get() ->isize { + let kb = KEYBOARD_DEVICE.clone(); + let mouse = MOUSE_DEVICE.clone(); + //let input=INPUT_CONDVAR.clone(); + //read_input_event() as isize + if !kb.is_empty(){ + kb.read_event() as isize + } else if !mouse.is_empty() { + mouse.read_event() as isize + } else { + 0 + } + +} \ No newline at end of file diff --git a/os/src/syscall/mod.rs b/os/src/syscall/mod.rs index 3f95b94..729caa0 100644 --- a/os/src/syscall/mod.rs +++ b/os/src/syscall/mod.rs @@ -27,18 +27,21 @@ const SYSCALL_CONDVAR_SIGNAL: usize = 1031; const SYSCALL_CONDVAR_WAIT: usize = 1032; const SYSCALL_FRAMEBUFFER: usize = 2000; const SYSCALL_FRAMEBUFFER_FLUSH: usize = 2001; +const SYSCALL_EVENT_GET: usize = 3000; mod fs; mod process; mod sync; mod thread; mod gui; +mod input; use fs::*; use process::*; use sync::*; use thread::*; use gui::*; +use input::*; pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize { match syscall_id { @@ -71,6 +74,7 @@ pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize { SYSCALL_CONDVAR_WAIT => sys_condvar_wait(args[0], args[1]), SYSCALL_FRAMEBUFFER => sys_framebuffer(), SYSCALL_FRAMEBUFFER_FLUSH => sys_framebuffer_flush(), + SYSCALL_EVENT_GET => sys_event_get(), _ => panic!("Unsupported syscall_id: {}", syscall_id), } } diff --git a/user/src/bin/inputdev_event.rs b/user/src/bin/inputdev_event.rs new file mode 100644 index 0000000..1e5b5a1 --- /dev/null +++ b/user/src/bin/inputdev_event.rs @@ -0,0 +1,21 @@ +#![no_std] +#![no_main] + +use user_lib::{event_get}; + +#[macro_use] +extern crate user_lib; + +#[no_mangle] +pub fn main() -> i32 { + println!("Input device event test"); + let mut event=0; + for _ in 0..3 { + while event==0 { + event = event_get(); + } + println!("event: {:?}", event); + } + + 0 +} \ No newline at end of file diff --git a/user/src/lib.rs b/user/src/lib.rs index 16d4abd..dd7261e 100644 --- a/user/src/lib.rs +++ b/user/src/lib.rs @@ -205,6 +205,11 @@ pub fn framebuffer_flush() -> isize { sys_framebuffer_flush() } +pub fn event_get() -> isize { + sys_event_get() +} + + #[macro_export] macro_rules! vstore { ($var_ref: expr, $value: expr) => { diff --git a/user/src/syscall.rs b/user/src/syscall.rs index 330388c..6d97b7e 100644 --- a/user/src/syscall.rs +++ b/user/src/syscall.rs @@ -27,6 +27,7 @@ const SYSCALL_CONDVAR_SIGNAL: usize = 1031; const SYSCALL_CONDVAR_WAIT: usize = 1032; const SYSCALL_FRAMEBUFFER: usize = 2000; const SYSCALL_FRAMEBUFFER_FLUSH: usize = 2001; +const SYSCALL_EVENT_GET: usize = 3000; fn syscall(id: usize, args: [usize; 3]) -> isize { let mut ret: isize; @@ -164,4 +165,8 @@ pub fn sys_framebuffer() -> isize { pub fn sys_framebuffer_flush() -> isize { syscall(SYSCALL_FRAMEBUFFER_FLUSH, [0, 0, 0]) +} + +pub fn sys_event_get() -> isize { + syscall(SYSCALL_EVENT_GET, [0, 0, 0]) } \ No newline at end of file From b40120f8ff541613328e2385d044ad80f70caf34 Mon Sep 17 00:00:00 2001 From: Yu Chen Date: Sat, 7 Jan 2023 23:36:05 +0800 Subject: [PATCH 35/68] udpate gui apps, uart and gpu can work together --- user/src/bin/embed_graph.rs | 5 +- user/src/bin/embed_graph_uart.rs | 124 +++++++++++++++++++++++++++++++ user/src/bin/gui_simple.rs | 12 +-- 3 files changed, 128 insertions(+), 13 deletions(-) create mode 100644 user/src/bin/embed_graph_uart.rs diff --git a/user/src/bin/embed_graph.rs b/user/src/bin/embed_graph.rs index 3866994..e1b3ea8 100644 --- a/user/src/bin/embed_graph.rs +++ b/user/src/bin/embed_graph.rs @@ -1,13 +1,12 @@ #![no_std] #![no_main] -use user_lib::{framebuffer, framebuffer_flush}; - #[macro_use] extern crate user_lib; - extern crate alloc; +use user_lib::{framebuffer, framebuffer_flush}; + use embedded_graphics::pixelcolor::Rgb888; use embedded_graphics::prelude::{Drawable, Point, RgbColor, Size}; use embedded_graphics::primitives::Primitive; diff --git a/user/src/bin/embed_graph_uart.rs b/user/src/bin/embed_graph_uart.rs new file mode 100644 index 0000000..9e0933b --- /dev/null +++ b/user/src/bin/embed_graph_uart.rs @@ -0,0 +1,124 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; +extern crate alloc; + +use user_lib::console::getchar; +use user_lib::{framebuffer, framebuffer_flush}; + +use embedded_graphics::pixelcolor::Rgb888; +use embedded_graphics::prelude::{Drawable, Point, RgbColor, Size}; +use embedded_graphics::primitives::Primitive; +use embedded_graphics::primitives::{PrimitiveStyle, Rectangle}; +use embedded_graphics::{draw_target::DrawTarget, prelude::OriginDimensions}; + +pub const VIRTGPU_XRES: usize = 1280; +pub const VIRTGPU_YRES: usize = 800; +pub const VIRTGPU_LEN: usize = VIRTGPU_XRES * VIRTGPU_YRES * 4; + +const INIT_X: i32 = 640; +const INIT_Y: i32 = 400; +const RECT_SIZE: u32 = 40; + +pub struct Display { + pub size: Size, + pub point: Point, + //pub fb: Arc<&'static mut [u8]>, + pub fb: &'static mut [u8], +} + +impl Display { + pub fn new(size: Size, point: Point) -> Self { + let fb_ptr = framebuffer() as *mut u8; + println!( + "Hello world from user mode program! 0x{:X} , len {}", + fb_ptr as usize, VIRTGPU_LEN + ); + let fb = + unsafe { core::slice::from_raw_parts_mut(fb_ptr as *mut u8, VIRTGPU_LEN as usize) }; + Self { size, point, fb } + } +} + +impl OriginDimensions for Display { + fn size(&self) -> Size { + self.size + } +} + +impl DrawTarget for Display { + type Color = Rgb888; + + type Error = core::convert::Infallible; + + fn draw_iter(&mut self, pixels: I) -> Result<(), Self::Error> + where + I: IntoIterator>, + { + pixels.into_iter().for_each(|px| { + let idx = ((self.point.y + px.0.y) * VIRTGPU_XRES as i32 + self.point.x + px.0.x) + as usize + * 4; + if idx + 2 >= self.fb.len() { + return; + } + self.fb[idx] = px.1.b(); + self.fb[idx + 1] = px.1.g(); + self.fb[idx + 2] = px.1.r(); + }); + framebuffer_flush(); + Ok(()) + } +} + +pub struct DrawingBoard { + disp: Display, + latest_pos: Point, +} + +impl DrawingBoard { + pub fn new() -> Self { + Self { + disp: Display::new(Size::new(1280, 800), Point::new(0, 0)), + latest_pos: Point::new(INIT_X, INIT_Y), + } + } + fn paint(&mut self) { + Rectangle::with_center(self.latest_pos, Size::new(RECT_SIZE, RECT_SIZE)) + .into_styled(PrimitiveStyle::with_stroke(Rgb888::WHITE, 1)) + .draw(&mut self.disp) + .ok(); + } + fn unpaint(&mut self) { + Rectangle::with_center(self.latest_pos, Size::new(RECT_SIZE, RECT_SIZE)) + .into_styled(PrimitiveStyle::with_stroke(Rgb888::BLACK, 1)) + .draw(&mut self.disp) + .ok(); + } + pub fn move_rect(&mut self, dx: i32, dy: i32) { + self.unpaint(); + self.latest_pos.x += dx; + self.latest_pos.y += dy; + self.paint(); + } +} + +const LF: u8 = 0x0au8; +const CR: u8 = 0x0du8; +#[no_mangle] +pub fn main() -> i32 { + // let fb_ptr = framebuffer() as *mut u8; + let mut board = DrawingBoard::new(); + for i in 0..20 { + let c=getchar(); + if c == LF || c == CR { + break; + } + board.latest_pos.x += i; + board.latest_pos.y += i; + board.paint(); + } + 0 +} diff --git a/user/src/bin/gui_simple.rs b/user/src/bin/gui_simple.rs index df4cfbb..83fb721 100644 --- a/user/src/bin/gui_simple.rs +++ b/user/src/bin/gui_simple.rs @@ -1,19 +1,11 @@ #![no_std] #![no_main] -use user_lib::{framebuffer, framebuffer_flush}; - #[macro_use] extern crate user_lib; -// use embedded_graphics::pixelcolor::Rgb888; -// use embedded_graphics::prelude::{Drawable, Point, RgbColor, Size}; -// use embedded_graphics::primitives::Primitive; -// use embedded_graphics::primitives::{PrimitiveStyle, Rectangle}; -// use embedded_graphics::{ -// draw_target::DrawTarget, -// prelude::{OriginDimensions}, -// }; +use user_lib::{framebuffer, framebuffer_flush}; + pub const VIRTGPU_XRES: usize = 1280; pub const VIRTGPU_YRES: usize = 800; From 2cbd23726002c371e15d57e20a8dc3a38a70f9b5 Mon Sep 17 00:00:00 2001 From: Yu Chen Date: Sun, 8 Jan 2023 22:41:41 +0800 Subject: [PATCH 36/68] Add snake gui app and update os/usr parts. Now snake can run! --- os/Cargo.toml | 3 +- os/src/boards/qemu.rs | 2 +- os/src/drivers/chardev/ns16550a.rs | 6 +- os/src/drivers/input/mod.rs | 5 +- os/src/syscall/fs.rs | 2 +- os/src/syscall/input.rs | 12 + os/src/syscall/mod.rs | 2 + user/Cargo.toml | 9 +- user/src/bin/{embed_graph.rs => gui_rect.rs} | 0 user/src/bin/gui_snake.rs | 403 ++++++++++++++++++ .../bin/{embed_graph_uart.rs => gui_uart.rs} | 0 user/src/bin/random_num.rs | 16 + user/src/lib.rs | 7 + user/src/syscall.rs | 5 + 14 files changed, 457 insertions(+), 15 deletions(-) rename user/src/bin/{embed_graph.rs => gui_rect.rs} (100%) create mode 100644 user/src/bin/gui_snake.rs rename user/src/bin/{embed_graph_uart.rs => gui_uart.rs} (100%) create mode 100644 user/src/bin/random_num.rs diff --git a/os/Cargo.toml b/os/Cargo.toml index 633ec10..ded2765 100644 --- a/os/Cargo.toml +++ b/os/Cargo.toml @@ -15,9 +15,8 @@ xmas-elf = "0.7.0" volatile = "0.3" #virtio-drivers = { git = "https://github.com/rcore-os/virtio-drivers", rev = "4ee80e5" } virtio-drivers = { git = "https://github.com/rcore-os/virtio-drivers", rev = "70b5850" } - easy-fs = { path = "../easy-fs" } -virtio-input-decoder = "0.1.4" +#virtio-input-decoder = "0.1.4" embedded-graphics = "0.7.1" tinybmp = "0.3.1" diff --git a/os/src/boards/qemu.rs b/os/src/boards/qemu.rs index ffabff6..0bc0f4c 100644 --- a/os/src/boards/qemu.rs +++ b/os/src/boards/qemu.rs @@ -12,7 +12,7 @@ pub type CharDeviceImpl = crate::drivers::chardev::NS16550a; pub const VIRT_PLIC: usize = 0xC00_0000; pub const VIRT_UART: usize = 0x1000_0000; - +#[allow(unused)] pub const VIRTGPU_XRES: u32 = 1280; #[allow(unused)] pub const VIRTGPU_YRES: u32 = 800; diff --git a/os/src/drivers/chardev/ns16550a.rs b/os/src/drivers/chardev/ns16550a.rs index d10dd90..127a4ce 100644 --- a/os/src/drivers/chardev/ns16550a.rs +++ b/os/src/drivers/chardev/ns16550a.rs @@ -131,7 +131,7 @@ pub struct NS16550a { impl NS16550a { pub fn new() -> Self { - let mut inner = NS16550aInner { + let inner = NS16550aInner { ns16550a: NS16550aRaw::new(BASE_ADDR), read_buffer: VecDeque::new(), }; @@ -141,6 +141,10 @@ impl NS16550a { condvar: Condvar::new(), } } + + pub fn read_buffer_is_empty(&self) -> bool { + self.inner.exclusive_session(|inner| inner.read_buffer.is_empty()) + } } impl CharDevice for NS16550a { diff --git a/os/src/drivers/input/mod.rs b/os/src/drivers/input/mod.rs index 76c64f7..857f12a 100644 --- a/os/src/drivers/input/mod.rs +++ b/os/src/drivers/input/mod.rs @@ -1,12 +1,10 @@ use crate::drivers::bus::virtio::VirtioHal; use crate::sync::{Condvar, UPIntrFreeCell}; use crate::task::schedule; -use alloc::collections::BTreeMap; use alloc::collections::VecDeque; use alloc::sync::Arc; use core::any::Any; use virtio_drivers::{VirtIOHeader, VirtIOInput}; -use virtio_input_decoder::{Decoder, Key, KeyType}; const VIRTIO5: usize = 0x10005000; const VIRTIO6: usize = 0x10006000; @@ -112,7 +110,8 @@ impl InputDevice for VirtIOInputWrapper { | (event.code as u64) << 32 | (event.value) as u64; inner.events.push_back(result); - println!("[KERN] inputdev_handle_irq: event: {:x}", result); + // for test + //println!("[KERN] inputdev_handle_irq: event: {:x}", result); } }); if count > 0 { diff --git a/os/src/syscall/fs.rs b/os/src/syscall/fs.rs index 2758825..af1585c 100644 --- a/os/src/syscall/fs.rs +++ b/os/src/syscall/fs.rs @@ -96,4 +96,4 @@ pub fn sys_dup(fd: usize) -> isize { let new_fd = inner.alloc_fd(); inner.fd_table[new_fd] = Some(Arc::clone(inner.fd_table[fd].as_ref().unwrap())); new_fd as isize -} +} \ No newline at end of file diff --git a/os/src/syscall/input.rs b/os/src/syscall/input.rs index 9f59710..7a28259 100644 --- a/os/src/syscall/input.rs +++ b/os/src/syscall/input.rs @@ -14,4 +14,16 @@ pub fn sys_event_get() ->isize { 0 } +} + +use crate::drivers::chardev::UART; + +/// check UART's read-buffer is empty or not +pub fn sys_key_pressed() -> isize { + let res =!UART.read_buffer_is_empty(); + if res { + 1 + } else { + 0 + } } \ No newline at end of file diff --git a/os/src/syscall/mod.rs b/os/src/syscall/mod.rs index 729caa0..d883d52 100644 --- a/os/src/syscall/mod.rs +++ b/os/src/syscall/mod.rs @@ -28,6 +28,7 @@ const SYSCALL_CONDVAR_WAIT: usize = 1032; const SYSCALL_FRAMEBUFFER: usize = 2000; const SYSCALL_FRAMEBUFFER_FLUSH: usize = 2001; const SYSCALL_EVENT_GET: usize = 3000; +const SYSCALL_KEY_PRESSED: usize = 3001; mod fs; mod process; @@ -75,6 +76,7 @@ pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize { SYSCALL_FRAMEBUFFER => sys_framebuffer(), SYSCALL_FRAMEBUFFER_FLUSH => sys_framebuffer_flush(), SYSCALL_EVENT_GET => sys_event_get(), + SYSCALL_KEY_PRESSED => sys_key_pressed(), _ => panic!("Unsupported syscall_id: {}", syscall_id), } } diff --git a/user/Cargo.toml b/user/Cargo.toml index 6666a5a..35e06d5 100644 --- a/user/Cargo.toml +++ b/user/Cargo.toml @@ -11,11 +11,6 @@ buddy_system_allocator = "0.6" bitflags = "1.2.1" riscv = { git = "https://github.com/rcore-os/riscv", features = ["inline-asm"] } embedded-graphics = "0.7.1" -# lazy_static = { version = "1.4.0", features = ["spin_no_std"] } - +oorandom ="11" [profile.release] -debug = true - -# [features] -# board_qemu = [] -# board_k210 = [] \ No newline at end of file +debug = true \ No newline at end of file diff --git a/user/src/bin/embed_graph.rs b/user/src/bin/gui_rect.rs similarity index 100% rename from user/src/bin/embed_graph.rs rename to user/src/bin/gui_rect.rs diff --git a/user/src/bin/gui_snake.rs b/user/src/bin/gui_snake.rs new file mode 100644 index 0000000..c014872 --- /dev/null +++ b/user/src/bin/gui_snake.rs @@ -0,0 +1,403 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; +extern crate alloc; + +use user_lib::console::getchar; +use user_lib::{framebuffer, framebuffer_flush, key_pressed, sleep}; + +use embedded_graphics::pixelcolor::*; +use embedded_graphics::prelude::{Drawable, Point, RgbColor, Size}; +use embedded_graphics::primitives::Primitive; +use embedded_graphics::primitives::{PrimitiveStyle, Rectangle}; +use embedded_graphics::Pixel; +use embedded_graphics::{draw_target::DrawTarget, prelude::OriginDimensions}; +use oorandom; //random generator + +pub const VIRTGPU_XRES: usize = 1280; +pub const VIRTGPU_YRES: usize = 800; +pub const VIRTGPU_LEN: usize = VIRTGPU_XRES * VIRTGPU_YRES * 4; + +pub struct Display { + pub size: Size, + pub point: Point, + pub fb: &'static mut [u8], +} + +impl Display { + pub fn new(size: Size, point: Point) -> Self { + let fb_ptr = framebuffer() as *mut u8; + println!( + "Hello world from user mode program! 0x{:X} , len {}", + fb_ptr as usize, VIRTGPU_LEN + ); + let fb = + unsafe { core::slice::from_raw_parts_mut(fb_ptr as *mut u8, VIRTGPU_LEN as usize) }; + Self { size, point, fb } + } +} + +impl OriginDimensions for Display { + fn size(&self) -> Size { + self.size + } +} + +impl DrawTarget for Display { + type Color = Rgb888; + type Error = core::convert::Infallible; + + fn draw_iter(&mut self, pixels: I) -> Result<(), Self::Error> + where + I: IntoIterator>, + { + pixels.into_iter().for_each(|px| { + let idx = ((self.point.y + px.0.y) * VIRTGPU_XRES as i32 + self.point.x + px.0.x) + as usize + * 4; + if idx + 2 >= self.fb.len() { + return; + } + self.fb[idx] = px.1.b(); + self.fb[idx + 1] = px.1.g(); + self.fb[idx + 2] = px.1.r(); + }); + framebuffer_flush(); + Ok(()) + } +} +struct Snake { + parts: [Pixel; MAX_SIZE], + len: usize, + direction: Direction, + size_x: u32, + size_y: u32, +} + +struct SnakeIntoIterator<'a, T: PixelColor, const MAX_SIZE: usize> { + snake: &'a Snake, + index: usize, +} + +impl<'a, T: PixelColor, const MAX_SIZE: usize> IntoIterator for &'a Snake { + type Item = Pixel; + type IntoIter = SnakeIntoIterator<'a, T, MAX_SIZE>; + + fn into_iter(self) -> Self::IntoIter { + SnakeIntoIterator { + snake: self, + index: 0, + } + } +} + +impl<'a, T: PixelColor, const MAX_SIZE: usize> Iterator for SnakeIntoIterator<'a, T, MAX_SIZE> { + type Item = Pixel; + + fn next(&mut self) -> Option { + let cur = self.snake.parts[self.index]; + if self.index < self.snake.len { + self.index += 1; + return Some(cur); + } + None + } +} + +impl Snake { + fn new(color: T, size_x: u32, size_y: u32) -> Snake { + Snake { + parts: [Pixel::(Point { x: 0, y: 0 }, color); MAX_SIZE], + len: 1, + direction: Direction::None, + size_x, + size_y, + } + } + fn set_direction(&mut self, direction: Direction) { + self.direction = direction; + } + fn contains(&self, this: Point) -> bool { + for part in self.into_iter() { + if part.0 == this { + return true; + }; + } + false + } + fn grow(&mut self) { + if self.len < MAX_SIZE - 1 { + self.len += 1; + } + } + fn make_step(&mut self) { + let mut i = self.len; + while i > 0 { + self.parts[i] = self.parts[i - 1]; + i -= 1; + } + match self.direction { + Direction::Left => { + if self.parts[0].0.x == 0 { + self.parts[0].0.x = (self.size_x - 1) as i32; + } else { + self.parts[0].0.x -= 1; + } + } + Direction::Right => { + if self.parts[0].0.x == (self.size_x - 1) as i32 { + self.parts[0].0.x = 0; + } else { + self.parts[0].0.x += 1; + } + } + Direction::Up => { + if self.parts[0].0.y == 0 { + self.parts[0].0.y = (self.size_y - 1) as i32; + } else { + self.parts[0].0.y -= 1; + } + } + Direction::Down => { + if self.parts[0].0.y == (self.size_y - 1) as i32 { + self.parts[0].0.y = 0; + } else { + self.parts[0].0.y += 1; + } + } + Direction::None => {} + } + } +} + +struct Food { + size_x: u32, + size_y: u32, + place: Pixel, + rng: oorandom::Rand32, +} + +impl Food { + pub fn new(color: T, size_x: u32, size_y: u32) -> Self { + let seed = 4; + let rng = oorandom::Rand32::new(seed); + Food { + size_x, + size_y, + place: Pixel(Point { x: 0, y: 0 }, color), + rng, + } + } + fn replace<'a, const MAX_SIZE: usize>(&mut self, iter_source: &Snake) { + let mut p: Point; + 'outer: loop { + let random_number = self.rng.rand_u32(); + let blocked_positions = iter_source.into_iter(); + p = Point { + x: ((random_number >> 24) as u16 % self.size_x as u16).into(), + y: ((random_number >> 16) as u16 % self.size_y as u16).into(), + }; + for blocked_position in blocked_positions { + if p == blocked_position.0 { + continue 'outer; + } + } + break; + } + self.place = Pixel:: { + 0: p, + 1: self.place.1, + } + } + fn get_pixel(&self) -> Pixel { + self.place + } +} + +#[derive(PartialEq, Debug, Clone, Copy)] +pub enum Direction { + Left, + Right, + Up, + Down, + None, +} + +pub struct SnakeGame { + snake: Snake, + food: Food, + food_age: u32, + food_lifetime: u32, + size_x: u32, + size_y: u32, + scale_x: u32, + scale_y: u32, +} + +impl SnakeGame { + pub fn new( + size_x: u32, + size_y: u32, + scale_x: u32, + scale_y: u32, + snake_color: T, + food_color: T, + food_lifetime: u32, + ) -> Self { + let snake = Snake::::new(snake_color, size_x / scale_x, size_y / scale_y); + let mut food = Food::::new(food_color, size_x / scale_x, size_y / scale_y); + food.replace(&snake); + SnakeGame { + snake, + food, + food_age: 0, + food_lifetime, + size_x, + size_y, + scale_x, + scale_y, + } + } + pub fn set_direction(&mut self, direction: Direction) { + self.snake.set_direction(direction); + } + pub fn draw(&mut self, target: &mut D) -> () + where + D: DrawTarget, + { + self.snake.make_step(); + let hit = self.snake.contains(self.food.get_pixel().0); + if hit { + self.snake.grow(); + } + self.food_age += 1; + if self.food_age >= self.food_lifetime || hit { + self.food.replace(&self.snake); + self.food_age = 0; + } + + let mut scaled_display = ScaledDisplay:: { + real_display: target, + size_x: self.size_x / self.scale_x, + size_y: self.size_y / self.scale_y, + scale_x: self.scale_x, + scale_y: self.scale_y, + }; + + for part in self.snake.into_iter() { + _ = part.draw(&mut scaled_display); + } + _ = self.food.get_pixel().draw(&mut scaled_display); + } +} + +/// A dummy DrawTarget implementation that can magnify each pixel so the user code does not need to adapt for scaling things +struct ScaledDisplay<'a, T: DrawTarget> { + real_display: &'a mut T, + size_x: u32, + size_y: u32, + scale_x: u32, + scale_y: u32, +} + +impl<'a, T: DrawTarget> DrawTarget for ScaledDisplay<'a, T> { + type Color = T::Color; + type Error = T::Error; + + fn draw_iter(&mut self, pixels: I) -> Result<(), Self::Error> + where + I: IntoIterator>, + { + for pixel in pixels { + let style = PrimitiveStyle::with_fill(pixel.1); + Rectangle::new( + Point::new( + pixel.0.x * self.scale_x as i32, + pixel.0.y * self.scale_y as i32, + ), + Size::new(self.scale_x as u32, self.scale_y as u32), + ) + .into_styled(style) + .draw(self.real_display)?; + } + Ok(()) + } +} + +impl<'a, T: DrawTarget> OriginDimensions for ScaledDisplay<'a, T> { + fn size(&self) -> Size { + Size::new(self.size_x as u32, self.size_y as u32) + } +} + +#[cfg(test)] +mod tests { + + use crate::Snake; + use embedded_graphics::pixelcolor::*; + use embedded_graphics::prelude::*; + + #[test] + fn snake_basic() { + let mut snake = Snake::::new(Rgb888::RED, 8, 8); + snake.set_direction(crate::Direction::Right); + assert_eq!( + Pixel::(Point { x: 0, y: 0 }, Rgb888::RED), + snake.into_iter().next().unwrap() + ); + snake.make_step(); + assert_eq!( + Pixel::(Point { x: 1, y: 0 }, Rgb888::RED), + snake.into_iter().nth(0).unwrap() + ); + assert_eq!( + Pixel::(Point { x: 0, y: 0 }, Rgb888::RED), + snake.into_iter().nth(1).unwrap() + ); + snake.set_direction(crate::Direction::Down); + snake.make_step(); + assert_eq!( + Pixel::(Point { x: 1, y: 1 }, Rgb888::RED), + snake.into_iter().nth(0).unwrap() + ); + assert_eq!( + Pixel::(Point { x: 1, y: 0 }, Rgb888::RED), + snake.into_iter().nth(1).unwrap() + ); + assert_eq!( + Pixel::(Point { x: 0, y: 0 }, Rgb888::RED), + snake.into_iter().nth(2).unwrap() + ); + assert_eq!(true, snake.contains(Point { x: 0, y: 0 })); + assert_eq!(true, snake.contains(Point { x: 1, y: 0 })); + assert_eq!(true, snake.contains(Point { x: 1, y: 1 })); + } +} + +const LF: u8 = 0x0au8; +const CR: u8 = 0x0du8; +#[no_mangle] +pub fn main() -> i32 { + let mut disp = Display::new(Size::new(1280, 800), Point::new(0, 0)); + let mut game = SnakeGame::<20, Rgb888>::new(1280, 800, 20, 20, Rgb888::RED, Rgb888::YELLOW, 50); + loop { + if key_pressed() { + let c = getchar(); + match c { + LF => break, + CR => break, + b'w' => game.set_direction(Direction::Up), + b's' => game.set_direction(Direction::Down), + b'a' => game.set_direction(Direction::Left), + b'd' => game.set_direction(Direction::Right), + _ => (), + } + } + let _ = disp.clear(Rgb888::BLACK).unwrap(); + game.draw(&mut disp); + sleep(10); + } + 0 +} diff --git a/user/src/bin/embed_graph_uart.rs b/user/src/bin/gui_uart.rs similarity index 100% rename from user/src/bin/embed_graph_uart.rs rename to user/src/bin/gui_uart.rs diff --git a/user/src/bin/random_num.rs b/user/src/bin/random_num.rs new file mode 100644 index 0000000..dd9ac00 --- /dev/null +++ b/user/src/bin/random_num.rs @@ -0,0 +1,16 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; +use oorandom; + +#[no_mangle] +pub fn main() -> i32 { + println!("random num program!"); + let seed = 4; + let mut rng = oorandom::Rand32::new(seed); + println!("OORandom: Random number 32bit: {}", rng.rand_i32()); + println!("OORandom: Random number range: {}", rng.rand_range(1..100)); + 0 +} \ No newline at end of file diff --git a/user/src/lib.rs b/user/src/lib.rs index dd7261e..31ce9ba 100644 --- a/user/src/lib.rs +++ b/user/src/lib.rs @@ -209,6 +209,13 @@ pub fn event_get() -> isize { sys_event_get() } +pub fn key_pressed() -> bool { + if sys_key_pressed() == 1 { + true + } else { + false + } +} #[macro_export] macro_rules! vstore { diff --git a/user/src/syscall.rs b/user/src/syscall.rs index 6d97b7e..530ea20 100644 --- a/user/src/syscall.rs +++ b/user/src/syscall.rs @@ -28,6 +28,7 @@ const SYSCALL_CONDVAR_WAIT: usize = 1032; const SYSCALL_FRAMEBUFFER: usize = 2000; const SYSCALL_FRAMEBUFFER_FLUSH: usize = 2001; const SYSCALL_EVENT_GET: usize = 3000; +const SYSCALL_KEY_PRESSED: usize = 3001; fn syscall(id: usize, args: [usize; 3]) -> isize { let mut ret: isize; @@ -169,4 +170,8 @@ pub fn sys_framebuffer_flush() -> isize { pub fn sys_event_get() -> isize { syscall(SYSCALL_EVENT_GET, [0, 0, 0]) +} + +pub fn sys_key_pressed() -> isize { + syscall(SYSCALL_KEY_PRESSED, [0, 0, 0]) } \ No newline at end of file From 73fcb72cbbd17f342bd52f413dc803061aa3535d Mon Sep 17 00:00:00 2001 From: Yu Chen Date: Tue, 10 Jan 2023 16:29:36 +0800 Subject: [PATCH 37/68] fix bug in impl Drop for FrameTracker, for the correctly mapping/unmapping display buffer in app --- os/src/mm/frame_allocator.rs | 10 +++++++--- os/src/mm/memory_set.rs | 6 +++++- os/src/syscall/gui.rs | 2 +- user/src/bin/gui_rect.rs | 1 + user/src/bin/gui_snake.rs | 1 + user/src/bin/gui_uart.rs | 1 + 6 files changed, 16 insertions(+), 5 deletions(-) diff --git a/os/src/mm/frame_allocator.rs b/os/src/mm/frame_allocator.rs index a280379..275fb17 100644 --- a/os/src/mm/frame_allocator.rs +++ b/os/src/mm/frame_allocator.rs @@ -7,6 +7,7 @@ use lazy_static::*; pub struct FrameTracker { pub ppn: PhysPageNum, + pub nodrop: bool, } impl FrameTracker { @@ -16,10 +17,10 @@ impl FrameTracker { for i in bytes_array { *i = 0; } - Self { ppn } + Self { ppn, nodrop: false } } - pub fn new_nowrite(ppn: PhysPageNum) -> Self { - Self { ppn } + pub fn new_noalloc(ppn: PhysPageNum) -> Self { + Self { ppn, nodrop: true } } } @@ -31,6 +32,9 @@ impl Debug for FrameTracker { impl Drop for FrameTracker { fn drop(&mut self) { + if self.nodrop { + return; + } frame_dealloc(self.ppn); } } diff --git a/os/src/mm/memory_set.rs b/os/src/mm/memory_set.rs index 8875617..bec0b93 100644 --- a/os/src/mm/memory_set.rs +++ b/os/src/mm/memory_set.rs @@ -290,6 +290,9 @@ impl MapArea { ppn = frame.ppn; self.data_frames.insert(vpn, frame); } + MapType::Noalloc => { + panic!("Noalloc should not be mapped"); + } } let pte_flags = PTEFlags::from_bits(self.map_perm.bits).unwrap(); page_table.map(vpn, ppn, pte_flags); @@ -307,7 +310,7 @@ impl MapArea { } pub fn map_noalloc(&mut self, page_table: &mut PageTable,ppn_range:PPNRange) { for (vpn,ppn) in core::iter::zip(self.vpn_range,ppn_range) { - self.data_frames.insert(vpn, FrameTracker::new_nowrite(ppn)); + self.data_frames.insert(vpn, FrameTracker::new_noalloc(ppn)); let pte_flags = PTEFlags::from_bits(self.map_perm.bits).unwrap(); page_table.map(vpn, ppn, pte_flags); } @@ -346,6 +349,7 @@ impl MapArea { pub enum MapType { Identical, Framed, + Noalloc, } bitflags! { diff --git a/os/src/syscall/gui.rs b/os/src/syscall/gui.rs index 0018604..5d41c0c 100644 --- a/os/src/syscall/gui.rs +++ b/os/src/syscall/gui.rs @@ -22,7 +22,7 @@ pub fn sys_framebuffer() -> isize { MapArea::new( (FB_VADDR as usize).into(), (FB_VADDR + len as usize).into(), - MapType::Framed, + MapType::Noalloc, MapPermission::R | MapPermission::W | MapPermission::U, ), PPNRange::new(fb_ppn, fb_end_ppn), diff --git a/user/src/bin/gui_rect.rs b/user/src/bin/gui_rect.rs index e1b3ea8..e9007f6 100644 --- a/user/src/bin/gui_rect.rs +++ b/user/src/bin/gui_rect.rs @@ -108,6 +108,7 @@ impl DrawingBoard { pub fn main() -> i32 { // let fb_ptr = framebuffer() as *mut u8; let mut board = DrawingBoard::new(); + let _ = board.disp.clear(Rgb888::BLACK).unwrap(); for i in 0..20 { board.latest_pos.x += i; board.latest_pos.y += i; diff --git a/user/src/bin/gui_snake.rs b/user/src/bin/gui_snake.rs index c014872..ce36b2e 100644 --- a/user/src/bin/gui_snake.rs +++ b/user/src/bin/gui_snake.rs @@ -382,6 +382,7 @@ const CR: u8 = 0x0du8; pub fn main() -> i32 { let mut disp = Display::new(Size::new(1280, 800), Point::new(0, 0)); let mut game = SnakeGame::<20, Rgb888>::new(1280, 800, 20, 20, Rgb888::RED, Rgb888::YELLOW, 50); + let _ = disp.clear(Rgb888::BLACK).unwrap(); loop { if key_pressed() { let c = getchar(); diff --git a/user/src/bin/gui_uart.rs b/user/src/bin/gui_uart.rs index 9e0933b..c9577a4 100644 --- a/user/src/bin/gui_uart.rs +++ b/user/src/bin/gui_uart.rs @@ -111,6 +111,7 @@ const CR: u8 = 0x0du8; pub fn main() -> i32 { // let fb_ptr = framebuffer() as *mut u8; let mut board = DrawingBoard::new(); + let _ = board.disp.clear(Rgb888::BLACK).unwrap(); for i in 0..20 { let c=getchar(); if c == LF || c == CR { From 4022cc3ed75e04c05d7e9a778e799d31b5f81d48 Mon Sep 17 00:00:00 2001 From: Yifan Wu Date: Wed, 11 Jan 2023 09:02:54 -0800 Subject: [PATCH 38/68] Split user_lib into modules && provide Display in user_lib --- user/src/bin/gui_rect.rs | 66 +-------------- user/src/bin/gui_simple.rs | 27 +++--- user/src/bin/gui_snake.rs | 56 +------------ user/src/file.rs | 30 +++++++ user/src/io.rs | 78 +++++++++++++++++ user/src/lib.rs | 166 ++----------------------------------- user/src/sync.rs | 32 +++++++ user/src/task.rs | 82 ++++++++++++++++++ 8 files changed, 248 insertions(+), 289 deletions(-) create mode 100644 user/src/file.rs create mode 100644 user/src/io.rs create mode 100644 user/src/sync.rs create mode 100644 user/src/task.rs diff --git a/user/src/bin/gui_rect.rs b/user/src/bin/gui_rect.rs index e9007f6..39f8173 100644 --- a/user/src/bin/gui_rect.rs +++ b/user/src/bin/gui_rect.rs @@ -1,77 +1,19 @@ #![no_std] #![no_main] -#[macro_use] extern crate user_lib; extern crate alloc; -use user_lib::{framebuffer, framebuffer_flush}; +use user_lib::{VIRTGPU_XRES, VIRTGPU_YRES, Display}; use embedded_graphics::pixelcolor::Rgb888; -use embedded_graphics::prelude::{Drawable, Point, RgbColor, Size}; -use embedded_graphics::primitives::Primitive; -use embedded_graphics::primitives::{PrimitiveStyle, Rectangle}; -use embedded_graphics::{draw_target::DrawTarget, prelude::OriginDimensions}; - -pub const VIRTGPU_XRES: usize = 1280; -pub const VIRTGPU_YRES: usize = 800; -pub const VIRTGPU_LEN: usize = VIRTGPU_XRES * VIRTGPU_YRES * 4; +use embedded_graphics::prelude::{DrawTarget, Drawable, Point, RgbColor, Size}; +use embedded_graphics::primitives::{Primitive, PrimitiveStyle, Rectangle}; const INIT_X: i32 = 640; const INIT_Y: i32 = 400; const RECT_SIZE: u32 = 40; -pub struct Display { - pub size: Size, - pub point: Point, - //pub fb: Arc<&'static mut [u8]>, - pub fb: &'static mut [u8], -} - -impl Display { - pub fn new(size: Size, point: Point) -> Self { - let fb_ptr = framebuffer() as *mut u8; - println!( - "Hello world from user mode program! 0x{:X} , len {}", - fb_ptr as usize, VIRTGPU_LEN - ); - let fb = - unsafe { core::slice::from_raw_parts_mut(fb_ptr as *mut u8, VIRTGPU_LEN as usize) }; - Self { size, point, fb } - } -} - -impl OriginDimensions for Display { - fn size(&self) -> Size { - self.size - } -} - -impl DrawTarget for Display { - type Color = Rgb888; - - type Error = core::convert::Infallible; - - fn draw_iter(&mut self, pixels: I) -> Result<(), Self::Error> - where - I: IntoIterator>, - { - pixels.into_iter().for_each(|px| { - let idx = ((self.point.y + px.0.y) * VIRTGPU_XRES as i32 + self.point.x + px.0.x) - as usize - * 4; - if idx + 2 >= self.fb.len() { - return; - } - self.fb[idx] = px.1.b(); - self.fb[idx + 1] = px.1.g(); - self.fb[idx + 2] = px.1.r(); - }); - framebuffer_flush(); - Ok(()) - } -} - pub struct DrawingBoard { disp: Display, latest_pos: Point, @@ -80,7 +22,7 @@ pub struct DrawingBoard { impl DrawingBoard { pub fn new() -> Self { Self { - disp: Display::new(Size::new(1280, 800), Point::new(0, 0)), + disp: Display::new(Size::new(VIRTGPU_XRES, VIRTGPU_YRES)), latest_pos: Point::new(INIT_X, INIT_Y), } } diff --git a/user/src/bin/gui_simple.rs b/user/src/bin/gui_simple.rs index 83fb721..e55232d 100644 --- a/user/src/bin/gui_simple.rs +++ b/user/src/bin/gui_simple.rs @@ -4,24 +4,21 @@ #[macro_use] extern crate user_lib; -use user_lib::{framebuffer, framebuffer_flush}; - -pub const VIRTGPU_XRES: usize = 1280; -pub const VIRTGPU_YRES: usize = 800; +use user_lib::{VIRTGPU_XRES, VIRTGPU_YRES, Display}; +use embedded_graphics::prelude::Size; #[no_mangle] pub fn main() -> i32 { - let fb_ptr =framebuffer() as *mut u8; - println!("Hello world from user mode program! 0x{:X} , len {}", fb_ptr as usize, VIRTGPU_XRES*VIRTGPU_YRES*4); - let fb= unsafe {core::slice::from_raw_parts_mut(fb_ptr as *mut u8, VIRTGPU_XRES*VIRTGPU_YRES*4 as usize)}; - for y in 0..800 { - for x in 0..1280 { - let idx = (y * 1280 + x) * 4; - fb[idx] = x as u8; - fb[idx + 1] = y as u8; - fb[idx + 2] = (x + y) as u8; + let mut disp = Display::new(Size::new(VIRTGPU_XRES, VIRTGPU_YRES)); + disp.paint_on_framebuffer(|fb| { + for y in 0..VIRTGPU_YRES as usize { + for x in 0..VIRTGPU_XRES as usize { + let idx = (y * VIRTGPU_XRES as usize + x) * 4; + fb[idx] = x as u8; + fb[idx + 1] = y as u8; + fb[idx + 2] = (x + y) as u8; + } } - } - framebuffer_flush(); + }); 0 } diff --git a/user/src/bin/gui_snake.rs b/user/src/bin/gui_snake.rs index ce36b2e..b28fd9c 100644 --- a/user/src/bin/gui_snake.rs +++ b/user/src/bin/gui_snake.rs @@ -6,7 +6,7 @@ extern crate user_lib; extern crate alloc; use user_lib::console::getchar; -use user_lib::{framebuffer, framebuffer_flush, key_pressed, sleep}; +use user_lib::{Display, key_pressed, sleep, VIRTGPU_XRES, VIRTGPU_YRES}; use embedded_graphics::pixelcolor::*; use embedded_graphics::prelude::{Drawable, Point, RgbColor, Size}; @@ -16,58 +16,6 @@ use embedded_graphics::Pixel; use embedded_graphics::{draw_target::DrawTarget, prelude::OriginDimensions}; use oorandom; //random generator -pub const VIRTGPU_XRES: usize = 1280; -pub const VIRTGPU_YRES: usize = 800; -pub const VIRTGPU_LEN: usize = VIRTGPU_XRES * VIRTGPU_YRES * 4; - -pub struct Display { - pub size: Size, - pub point: Point, - pub fb: &'static mut [u8], -} - -impl Display { - pub fn new(size: Size, point: Point) -> Self { - let fb_ptr = framebuffer() as *mut u8; - println!( - "Hello world from user mode program! 0x{:X} , len {}", - fb_ptr as usize, VIRTGPU_LEN - ); - let fb = - unsafe { core::slice::from_raw_parts_mut(fb_ptr as *mut u8, VIRTGPU_LEN as usize) }; - Self { size, point, fb } - } -} - -impl OriginDimensions for Display { - fn size(&self) -> Size { - self.size - } -} - -impl DrawTarget for Display { - type Color = Rgb888; - type Error = core::convert::Infallible; - - fn draw_iter(&mut self, pixels: I) -> Result<(), Self::Error> - where - I: IntoIterator>, - { - pixels.into_iter().for_each(|px| { - let idx = ((self.point.y + px.0.y) * VIRTGPU_XRES as i32 + self.point.x + px.0.x) - as usize - * 4; - if idx + 2 >= self.fb.len() { - return; - } - self.fb[idx] = px.1.b(); - self.fb[idx + 1] = px.1.g(); - self.fb[idx + 2] = px.1.r(); - }); - framebuffer_flush(); - Ok(()) - } -} struct Snake { parts: [Pixel; MAX_SIZE], len: usize, @@ -380,7 +328,7 @@ const LF: u8 = 0x0au8; const CR: u8 = 0x0du8; #[no_mangle] pub fn main() -> i32 { - let mut disp = Display::new(Size::new(1280, 800), Point::new(0, 0)); + let mut disp = Display::new(Size::new(VIRTGPU_XRES, VIRTGPU_YRES)); let mut game = SnakeGame::<20, Rgb888>::new(1280, 800, 20, 20, Rgb888::RED, Rgb888::YELLOW, 50); let _ = disp.clear(Rgb888::BLACK).unwrap(); loop { diff --git a/user/src/file.rs b/user/src/file.rs new file mode 100644 index 0000000..bf77667 --- /dev/null +++ b/user/src/file.rs @@ -0,0 +1,30 @@ +use super::*; + +bitflags! { + pub struct OpenFlags: u32 { + const RDONLY = 0; + const WRONLY = 1 << 0; + const RDWR = 1 << 1; + const CREATE = 1 << 9; + const TRUNC = 1 << 10; + } +} + +pub fn dup(fd: usize) -> isize { + sys_dup(fd) +} +pub fn open(path: &str, flags: OpenFlags) -> isize { + sys_open(path, flags.bits) +} +pub fn close(fd: usize) -> isize { + sys_close(fd) +} +pub fn pipe(pipe_fd: &mut [usize]) -> isize { + sys_pipe(pipe_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) +} \ No newline at end of file diff --git a/user/src/io.rs b/user/src/io.rs new file mode 100644 index 0000000..6cc2e66 --- /dev/null +++ b/user/src/io.rs @@ -0,0 +1,78 @@ +use super::*; +use embedded_graphics::prelude::{RgbColor, Size}; +use embedded_graphics::{draw_target::DrawTarget, prelude::OriginDimensions}; +use embedded_graphics::pixelcolor::Rgb888; + +pub const VIRTGPU_XRES: u32 = 1280; +pub const VIRTGPU_YRES: u32 = 800; +pub const VIRTGPU_LEN: usize = (VIRTGPU_XRES * VIRTGPU_YRES * 4) as usize; + +pub fn framebuffer() -> isize { + sys_framebuffer() +} +pub fn framebuffer_flush() -> isize { + sys_framebuffer_flush() +} + +pub fn event_get() -> isize { + sys_event_get() +} + +pub fn key_pressed() -> bool { + if sys_key_pressed() == 1 { + true + } else { + false + } +} +pub struct Display { + pub size: Size, + pub fb: &'static mut [u8], +} + +impl Display { + pub fn new(size: Size) -> Self { + let fb_ptr = framebuffer() as *mut u8; + let fb = + unsafe { core::slice::from_raw_parts_mut(fb_ptr, VIRTGPU_LEN as usize) }; + Self { size, fb} + } + pub fn framebuffer(&mut self) -> &mut [u8] { + self.fb + } + pub fn paint_on_framebuffer(&mut self, p: impl FnOnce(&mut [u8]) -> ()) { + p(self.framebuffer()); + framebuffer_flush(); + } +} + +impl OriginDimensions for Display { + fn size(&self) -> Size { + self.size + } +} + +impl DrawTarget for Display { + type Color = Rgb888; + + type Error = core::convert::Infallible; + + fn draw_iter(&mut self, pixels: I) -> Result<(), Self::Error> + where + I: IntoIterator>, + { + pixels.into_iter().for_each(|px| { + let idx = (px.0.y * VIRTGPU_XRES as i32 + px.0.x) + as usize + * 4; + if idx + 2 >= self.fb.len() { + return; + } + self.fb[idx] = px.1.b(); + self.fb[idx + 1] = px.1.g(); + self.fb[idx + 2] = px.1.r(); + }); + framebuffer_flush(); + Ok(()) + } +} diff --git a/user/src/lib.rs b/user/src/lib.rs index 31ce9ba..0d0db85 100644 --- a/user/src/lib.rs +++ b/user/src/lib.rs @@ -8,6 +8,10 @@ pub mod console; mod lang_items; mod syscall; +mod file; +mod task; +mod sync; +mod io; extern crate alloc; #[macro_use] @@ -16,6 +20,10 @@ extern crate bitflags; use alloc::vec::Vec; use buddy_system_allocator::LockedHeap; use syscall::*; +pub use file::*; +pub use task::*; +pub use sync::*; +pub use io::*; const USER_HEAP_SIZE: usize = 32768; @@ -59,164 +67,6 @@ fn main(_argc: usize, _argv: &[&str]) -> 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; - } -} - -pub fn dup(fd: usize) -> isize { - sys_dup(fd) -} -pub fn open(path: &str, flags: OpenFlags) -> isize { - sys_open(path, flags.bits) -} -pub fn close(fd: usize) -> isize { - sys_close(fd) -} -pub fn pipe(pipe_fd: &mut [usize]) -> isize { - sys_pipe(pipe_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 exit(exit_code: i32) -> ! { - sys_exit(exit_code); -} -pub fn yield_() -> isize { - sys_yield() -} -pub fn get_time() -> isize { - sys_get_time() -} -pub fn getpid() -> isize { - sys_getpid() -} -pub fn fork() -> isize { - sys_fork() -} -pub fn exec(path: &str, args: &[*const u8]) -> isize { - sys_exec(path, args) -} -pub fn wait(exit_code: &mut i32) -> isize { - loop { - match sys_waitpid(-1, exit_code as *mut _) { - -2 => { - yield_(); - } - // -1 or a real pid - exit_pid => return exit_pid, - } - } -} - -pub fn waitpid(pid: usize, exit_code: &mut i32) -> isize { - loop { - match sys_waitpid(pid as isize, exit_code as *mut _) { - -2 => { - yield_(); - } - // -1 or a real pid - exit_pid => return exit_pid, - } - } -} - -pub fn waitpid_nb(pid: usize, exit_code: &mut i32) -> isize { - sys_waitpid(pid as isize, exit_code as *mut _) -} - -bitflags! { - pub struct SignalFlags: i32 { - const SIGINT = 1 << 2; - const SIGILL = 1 << 4; - const SIGABRT = 1 << 6; - const SIGFPE = 1 << 8; - const SIGSEGV = 1 << 11; - } -} - -pub fn kill(pid: usize, signal: i32) -> isize { - sys_kill(pid, signal) -} - -pub fn sleep(sleep_ms: usize) { - sys_sleep(sleep_ms); -} - -pub fn thread_create(entry: usize, arg: usize) -> isize { - sys_thread_create(entry, arg) -} -pub fn gettid() -> isize { - sys_gettid() -} -pub fn waittid(tid: usize) -> isize { - loop { - match sys_waittid(tid) { - -2 => { - yield_(); - } - exit_code => return exit_code, - } - } -} - -pub fn mutex_create() -> isize { - sys_mutex_create(false) -} -pub fn mutex_blocking_create() -> isize { - sys_mutex_create(true) -} -pub fn mutex_lock(mutex_id: usize) { - sys_mutex_lock(mutex_id); -} -pub fn mutex_unlock(mutex_id: usize) { - sys_mutex_unlock(mutex_id); -} -pub fn semaphore_create(res_count: usize) -> isize { - sys_semaphore_create(res_count) -} -pub fn semaphore_up(sem_id: usize) { - sys_semaphore_up(sem_id); -} -pub fn semaphore_down(sem_id: usize) { - sys_semaphore_down(sem_id); -} -pub fn condvar_create() -> isize { - sys_condvar_create(0) -} -pub fn condvar_signal(condvar_id: usize) { - sys_condvar_signal(condvar_id); -} -pub fn condvar_wait(condvar_id: usize, mutex_id: usize) { - sys_condvar_wait(condvar_id, mutex_id); -} -pub fn framebuffer() -> isize { - sys_framebuffer() -} -pub fn framebuffer_flush() -> isize { - sys_framebuffer_flush() -} - -pub fn event_get() -> isize { - sys_event_get() -} - -pub fn key_pressed() -> bool { - if sys_key_pressed() == 1 { - true - } else { - false - } -} - #[macro_export] macro_rules! vstore { ($var_ref: expr, $value: expr) => { diff --git a/user/src/sync.rs b/user/src/sync.rs new file mode 100644 index 0000000..fbed4e3 --- /dev/null +++ b/user/src/sync.rs @@ -0,0 +1,32 @@ +use super::*; + +pub fn mutex_create() -> isize { + sys_mutex_create(false) +} +pub fn mutex_blocking_create() -> isize { + sys_mutex_create(true) +} +pub fn mutex_lock(mutex_id: usize) { + sys_mutex_lock(mutex_id); +} +pub fn mutex_unlock(mutex_id: usize) { + sys_mutex_unlock(mutex_id); +} +pub fn semaphore_create(res_count: usize) -> isize { + sys_semaphore_create(res_count) +} +pub fn semaphore_up(sem_id: usize) { + sys_semaphore_up(sem_id); +} +pub fn semaphore_down(sem_id: usize) { + sys_semaphore_down(sem_id); +} +pub fn condvar_create() -> isize { + sys_condvar_create(0) +} +pub fn condvar_signal(condvar_id: usize) { + sys_condvar_signal(condvar_id); +} +pub fn condvar_wait(condvar_id: usize, mutex_id: usize) { + sys_condvar_wait(condvar_id, mutex_id); +} \ No newline at end of file diff --git a/user/src/task.rs b/user/src/task.rs new file mode 100644 index 0000000..87d0dda --- /dev/null +++ b/user/src/task.rs @@ -0,0 +1,82 @@ +use super::*; + +pub fn exit(exit_code: i32) -> ! { + sys_exit(exit_code); +} +pub fn yield_() -> isize { + sys_yield() +} +pub fn get_time() -> isize { + sys_get_time() +} +pub fn getpid() -> isize { + sys_getpid() +} +pub fn fork() -> isize { + sys_fork() +} +pub fn exec(path: &str, args: &[*const u8]) -> isize { + sys_exec(path, args) +} +pub fn wait(exit_code: &mut i32) -> isize { + loop { + match sys_waitpid(-1, exit_code as *mut _) { + -2 => { + yield_(); + } + // -1 or a real pid + exit_pid => return exit_pid, + } + } +} + +pub fn waitpid(pid: usize, exit_code: &mut i32) -> isize { + loop { + match sys_waitpid(pid as isize, exit_code as *mut _) { + -2 => { + yield_(); + } + // -1 or a real pid + exit_pid => return exit_pid, + } + } +} + +pub fn waitpid_nb(pid: usize, exit_code: &mut i32) -> isize { + sys_waitpid(pid as isize, exit_code as *mut _) +} + +bitflags! { + pub struct SignalFlags: i32 { + const SIGINT = 1 << 2; + const SIGILL = 1 << 4; + const SIGABRT = 1 << 6; + const SIGFPE = 1 << 8; + const SIGSEGV = 1 << 11; + } +} + +pub fn kill(pid: usize, signal: i32) -> isize { + sys_kill(pid, signal) +} + +pub fn sleep(sleep_ms: usize) { + sys_sleep(sleep_ms); +} + +pub fn thread_create(entry: usize, arg: usize) -> isize { + sys_thread_create(entry, arg) +} +pub fn gettid() -> isize { + sys_gettid() +} +pub fn waittid(tid: usize) -> isize { + loop { + match sys_waittid(tid) { + -2 => { + yield_(); + } + exit_code => return exit_code, + } + } +} \ No newline at end of file From 4430e86d5ad48c40f5c88fe1eebbe700a083d9ca Mon Sep 17 00:00:00 2001 From: Yifan Wu Date: Wed, 11 Jan 2023 19:37:36 -0800 Subject: [PATCH 39/68] Added MapType::Linear for framebuffer mapping & cargo fmt --- os/src/drivers/chardev/ns16550a.rs | 5 +++-- os/src/drivers/input/mod.rs | 4 ++-- os/src/fs/pipe.rs | 2 +- os/src/main.rs | 1 - os/src/mm/address.rs | 1 - os/src/mm/frame_allocator.rs | 9 +-------- os/src/mm/memory_set.rs | 28 +++++++++++---------------- os/src/mm/mod.rs | 4 ++-- os/src/syscall/fs.rs | 2 +- os/src/syscall/gui.rs | 31 ++++++++++++++---------------- os/src/syscall/input.rs | 17 ++++++++-------- os/src/syscall/mod.rs | 8 ++++---- 12 files changed, 47 insertions(+), 65 deletions(-) diff --git a/os/src/drivers/chardev/ns16550a.rs b/os/src/drivers/chardev/ns16550a.rs index 127a4ce..7122cec 100644 --- a/os/src/drivers/chardev/ns16550a.rs +++ b/os/src/drivers/chardev/ns16550a.rs @@ -143,12 +143,13 @@ impl NS16550a { } pub fn read_buffer_is_empty(&self) -> bool { - self.inner.exclusive_session(|inner| inner.read_buffer.is_empty()) + self.inner + .exclusive_session(|inner| inner.read_buffer.is_empty()) } } impl CharDevice for NS16550a { - fn init(&self){ + fn init(&self) { let mut inner = self.inner.exclusive_access(); inner.ns16550a.init(); drop(inner); diff --git a/os/src/drivers/input/mod.rs b/os/src/drivers/input/mod.rs index 857f12a..d7c40fc 100644 --- a/os/src/drivers/input/mod.rs +++ b/os/src/drivers/input/mod.rs @@ -18,7 +18,7 @@ struct VirtIOInputWrapper { inner: UPIntrFreeCell, //condvars: BTreeMap, //condvar: Arc:: , - condvar:Condvar, + condvar: Condvar, } pub trait InputDevice: Send + Sync + Any { @@ -38,7 +38,7 @@ lazy_static::lazy_static!( //const QUEUE_SIZE: u16 = 32; // pub fn read_input_event() -> u64 { // loop { - + // //let mut inner = self.inner.exclusive_access(); // let kb=KEYBOARD_DEVICE.clone(); // let evs = kb.events(); diff --git a/os/src/fs/pipe.rs b/os/src/fs/pipe.rs index 531eec4..d10dc33 100644 --- a/os/src/fs/pipe.rs +++ b/os/src/fs/pipe.rs @@ -170,4 +170,4 @@ impl File for Pipe { } } } -} \ No newline at end of file +} diff --git a/os/src/main.rs b/os/src/main.rs index 7e5a20a..4819ea6 100644 --- a/os/src/main.rs +++ b/os/src/main.rs @@ -70,7 +70,6 @@ pub fn rust_main() -> ! { timer::set_next_trigger(); board::device_init(); fs::list_apps(); - //gui::init_paint(); task::add_initproc(); *DEV_NON_BLOCKING_ACCESS.exclusive_access() = true; task::run_tasks(); diff --git a/os/src/mm/address.rs b/os/src/mm/address.rs index 8792f62..cf147a0 100644 --- a/os/src/mm/address.rs +++ b/os/src/mm/address.rs @@ -260,4 +260,3 @@ where } } pub type VPNRange = SimpleRange; -pub type PPNRange = SimpleRange; diff --git a/os/src/mm/frame_allocator.rs b/os/src/mm/frame_allocator.rs index 275fb17..1ecfe99 100644 --- a/os/src/mm/frame_allocator.rs +++ b/os/src/mm/frame_allocator.rs @@ -7,7 +7,6 @@ use lazy_static::*; pub struct FrameTracker { pub ppn: PhysPageNum, - pub nodrop: bool, } impl FrameTracker { @@ -17,10 +16,7 @@ impl FrameTracker { for i in bytes_array { *i = 0; } - Self { ppn, nodrop: false } - } - pub fn new_noalloc(ppn: PhysPageNum) -> Self { - Self { ppn, nodrop: true } + Self { ppn } } } @@ -32,9 +28,6 @@ impl Debug for FrameTracker { impl Drop for FrameTracker { fn drop(&mut self) { - if self.nodrop { - return; - } frame_dealloc(self.ppn); } } diff --git a/os/src/mm/memory_set.rs b/os/src/mm/memory_set.rs index bec0b93..7cdd394 100644 --- a/os/src/mm/memory_set.rs +++ b/os/src/mm/memory_set.rs @@ -1,7 +1,7 @@ use super::{frame_alloc, FrameTracker}; use super::{PTEFlags, PageTable, PageTableEntry}; use super::{PhysAddr, PhysPageNum, VirtAddr, VirtPageNum}; -use super::{StepByOne, VPNRange, PPNRange}; +use super::{StepByOne, VPNRange}; use crate::config::{MEMORY_END, MMIO, PAGE_SIZE, TRAMPOLINE}; use crate::sync::UPIntrFreeCell; use alloc::collections::BTreeMap; @@ -71,17 +71,16 @@ impl MemorySet { self.areas.remove(idx); } } - fn push(&mut self, mut map_area: MapArea, data: Option<&[u8]>) { + /// Add a new MapArea into this MemorySet. + /// Assuming that there are no conflicts in the virtual address + /// space. + pub fn push(&mut self, mut map_area: MapArea, data: Option<&[u8]>) { map_area.map(&mut self.page_table); if let Some(data) = data { map_area.copy_data(&mut self.page_table, data); } self.areas.push(map_area); } - pub fn push_noalloc(&mut self, mut map_area: MapArea, ppn_range: PPNRange) { - map_area.map_noalloc(&mut self.page_table, ppn_range); - self.areas.push(map_area); - } /// Mention that trampoline is not collected by areas. fn map_trampoline(&mut self) { self.page_table.map( @@ -290,8 +289,10 @@ impl MapArea { ppn = frame.ppn; self.data_frames.insert(vpn, frame); } - MapType::Noalloc => { - panic!("Noalloc should not be mapped"); + MapType::Linear(pn_offset) => { + // check for sv39 + assert!(vpn.0 < (1usize << 27)); + ppn = PhysPageNum((vpn.0 as isize + pn_offset) as usize); } } let pte_flags = PTEFlags::from_bits(self.map_perm.bits).unwrap(); @@ -308,14 +309,6 @@ impl MapArea { self.map_one(page_table, vpn); } } - pub fn map_noalloc(&mut self, page_table: &mut PageTable,ppn_range:PPNRange) { - for (vpn,ppn) in core::iter::zip(self.vpn_range,ppn_range) { - self.data_frames.insert(vpn, FrameTracker::new_noalloc(ppn)); - let pte_flags = PTEFlags::from_bits(self.map_perm.bits).unwrap(); - page_table.map(vpn, ppn, pte_flags); - } - } - pub fn unmap(&mut self, page_table: &mut PageTable) { for vpn in self.vpn_range { self.unmap_one(page_table, vpn); @@ -349,7 +342,8 @@ impl MapArea { pub enum MapType { Identical, Framed, - Noalloc, + /// offset of page num + Linear(isize), } bitflags! { diff --git a/os/src/mm/mod.rs b/os/src/mm/mod.rs index 9482a30..77d62f4 100644 --- a/os/src/mm/mod.rs +++ b/os/src/mm/mod.rs @@ -4,11 +4,11 @@ mod heap_allocator; mod memory_set; mod page_table; -pub use address::{VPNRange, PPNRange}; +pub use address::VPNRange; pub use address::{PhysAddr, PhysPageNum, StepByOne, VirtAddr, VirtPageNum}; pub use frame_allocator::{frame_alloc, frame_dealloc, FrameTracker}; pub use memory_set::remap_test; -pub use memory_set::{kernel_token, MapPermission, MemorySet, MapArea, MapType, KERNEL_SPACE}; +pub use memory_set::{kernel_token, MapArea, MapPermission, MapType, MemorySet, KERNEL_SPACE}; use page_table::PTEFlags; pub use page_table::{ translated_byte_buffer, translated_ref, translated_refmut, translated_str, PageTable, diff --git a/os/src/syscall/fs.rs b/os/src/syscall/fs.rs index af1585c..2758825 100644 --- a/os/src/syscall/fs.rs +++ b/os/src/syscall/fs.rs @@ -96,4 +96,4 @@ pub fn sys_dup(fd: usize) -> isize { let new_fd = inner.alloc_fd(); inner.fd_table[new_fd] = Some(Arc::clone(inner.fd_table[fd].as_ref().unwrap())); new_fd as isize -} \ No newline at end of file +} diff --git a/os/src/syscall/gui.rs b/os/src/syscall/gui.rs index 5d41c0c..c5ba8a4 100644 --- a/os/src/syscall/gui.rs +++ b/os/src/syscall/gui.rs @@ -1,37 +1,34 @@ -use crate::mm::{MapArea, MapPermission, MapType, PPNRange, PhysAddr}; -use crate::task::current_process; - -//use crate::gui::*; use crate::drivers::GPU_DEVICE; +use crate::mm::{MapArea, MapPermission, MapType, PhysAddr, VirtAddr}; +use crate::task::current_process; const FB_VADDR: usize = 0x10000000; pub fn sys_framebuffer() -> isize { - let gpu = GPU_DEVICE.clone(); - let fb = gpu.get_framebuffer(); + let fb = GPU_DEVICE.get_framebuffer(); let len = fb.len(); - println!("[kernel] FrameBuffer: addr 0x{:X}, len {}", fb.as_ptr() as usize , len); - let fb_ppn = PhysAddr::from(fb.as_ptr() as usize).floor(); - let fb_end_ppn = PhysAddr::from(fb.as_ptr() as usize + len).ceil(); + // println!("[kernel] FrameBuffer: addr 0x{:X}, len {}", fb.as_ptr() as usize , len); + let fb_start_pa = PhysAddr::from(fb.as_ptr() as usize); + assert!(fb_start_pa.aligned()); + let fb_start_ppn = fb_start_pa.floor(); + let fb_start_vpn = VirtAddr::from(FB_VADDR).floor(); + let pn_offset = fb_start_ppn.0 as isize - fb_start_vpn.0 as isize; let current_process = current_process(); let mut inner = current_process.inner_exclusive_access(); - let mem_set = &mut inner.memory_set; - - mem_set.push_noalloc( + inner.memory_set.push( MapArea::new( (FB_VADDR as usize).into(), (FB_VADDR + len as usize).into(), - MapType::Noalloc, + MapType::Linear(pn_offset), MapPermission::R | MapPermission::W | MapPermission::U, ), - PPNRange::new(fb_ppn, fb_end_ppn), + None, ); FB_VADDR as isize } pub fn sys_framebuffer_flush() -> isize { - let gpu = GPU_DEVICE.clone(); - gpu.flush(); + GPU_DEVICE.flush(); 0 -} \ No newline at end of file +} diff --git a/os/src/syscall/input.rs b/os/src/syscall/input.rs index 7a28259..ee86bd3 100644 --- a/os/src/syscall/input.rs +++ b/os/src/syscall/input.rs @@ -1,29 +1,28 @@ //use crate::drivers::{KEYBOARD_DEVICE,MOUSE_DEVICE,INPUT_CONDVAR,read_input_event}; -use crate::drivers::{KEYBOARD_DEVICE,MOUSE_DEVICE}; +use crate::drivers::{KEYBOARD_DEVICE, MOUSE_DEVICE}; -pub fn sys_event_get() ->isize { +pub fn sys_event_get() -> isize { let kb = KEYBOARD_DEVICE.clone(); let mouse = MOUSE_DEVICE.clone(); //let input=INPUT_CONDVAR.clone(); //read_input_event() as isize - if !kb.is_empty(){ + if !kb.is_empty() { kb.read_event() as isize - } else if !mouse.is_empty() { + } else if !mouse.is_empty() { mouse.read_event() as isize } else { 0 } - } use crate::drivers::chardev::UART; /// check UART's read-buffer is empty or not -pub fn sys_key_pressed() -> isize { - let res =!UART.read_buffer_is_empty(); +pub fn sys_key_pressed() -> isize { + let res = !UART.read_buffer_is_empty(); if res { 1 } else { 0 - } -} \ No newline at end of file + } +} diff --git a/os/src/syscall/mod.rs b/os/src/syscall/mod.rs index d883d52..d28073f 100644 --- a/os/src/syscall/mod.rs +++ b/os/src/syscall/mod.rs @@ -31,18 +31,18 @@ const SYSCALL_EVENT_GET: usize = 3000; const SYSCALL_KEY_PRESSED: usize = 3001; mod fs; +mod gui; +mod input; mod process; mod sync; mod thread; -mod gui; -mod input; use fs::*; +use gui::*; +use input::*; use process::*; use sync::*; use thread::*; -use gui::*; -use input::*; pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize { match syscall_id { From f0cecc49409bfecd4c99cf2bcee0408cd5532e44 Mon Sep 17 00:00:00 2001 From: Yifan Wu Date: Thu, 12 Jan 2023 00:21:57 -0800 Subject: [PATCH 40/68] Decode input events in inputdev_event.rs --- os/Cargo.toml | 4 +-- os/src/drivers/input/mod.rs | 41 +--------------------- os/src/main.rs | 2 -- user/Cargo.toml | 2 ++ user/src/bin/gui_rect.rs | 1 - user/src/bin/gui_simple.rs | 1 - user/src/bin/gui_snake.rs | 1 - user/src/bin/inputdev_event.rs | 20 ++++++----- user/src/io.rs | 62 ++++++++++++++++++++++++++++------ 9 files changed, 67 insertions(+), 67 deletions(-) diff --git a/os/Cargo.toml b/os/Cargo.toml index ded2765..d8f4216 100644 --- a/os/Cargo.toml +++ b/os/Cargo.toml @@ -13,10 +13,8 @@ buddy_system_allocator = "0.6" bitflags = "1.2.1" xmas-elf = "0.7.0" volatile = "0.3" -#virtio-drivers = { git = "https://github.com/rcore-os/virtio-drivers", rev = "4ee80e5" } -virtio-drivers = { git = "https://github.com/rcore-os/virtio-drivers", rev = "70b5850" } +virtio-drivers = { git = "https://github.com/rcore-os/virtio-drivers", rev = "4ee80e5" } easy-fs = { path = "../easy-fs" } -#virtio-input-decoder = "0.1.4" embedded-graphics = "0.7.1" tinybmp = "0.3.1" diff --git a/os/src/drivers/input/mod.rs b/os/src/drivers/input/mod.rs index d7c40fc..a9f5f0b 100644 --- a/os/src/drivers/input/mod.rs +++ b/os/src/drivers/input/mod.rs @@ -16,41 +16,20 @@ struct VirtIOInputInner { struct VirtIOInputWrapper { inner: UPIntrFreeCell, - //condvars: BTreeMap, - //condvar: Arc:: , condvar: Condvar, } pub trait InputDevice: Send + Sync + Any { fn read_event(&self) -> u64; fn handle_irq(&self); - // fn events(&self) -> &VecDeque; fn is_empty(&self) -> bool; } lazy_static::lazy_static!( pub static ref KEYBOARD_DEVICE: Arc = Arc::new(VirtIOInputWrapper::new(VIRTIO5)); pub static ref MOUSE_DEVICE: Arc = Arc::new(VirtIOInputWrapper::new(VIRTIO6)); - // pub static ref INPUT_CONDVAR: Arc:: = Arc::new(Condvar::new()); ); -// from virtio-drivers/src/input.rs -//const QUEUE_SIZE: u16 = 32; -// pub fn read_input_event() -> u64 { -// loop { - -// //let mut inner = self.inner.exclusive_access(); -// let kb=KEYBOARD_DEVICE.clone(); -// let evs = kb.events(); -// if let Some(event) = evs.pop_front() { -// return event; -// } else { -// let task_cx_ptr = INPUT_CONDVAR.clone().wait_no_sched(); -// drop(inner); -// schedule(task_cx_ptr); -// } -// } -// } impl VirtIOInputWrapper { pub fn new(addr: usize) -> Self { let inner = VirtIOInputInner { @@ -59,17 +38,8 @@ impl VirtIOInputWrapper { }, events: VecDeque::new(), }; - - // let mut condvars = BTreeMap::new(); - // let channels = QUEUE_SIZE; - // for i in 0..channels { - // let condvar = Condvar::new(); - // condvars.insert(i, condvar); - // } - Self { inner: unsafe { UPIntrFreeCell::new(inner) }, - //condvar: INPUT_CONDVAR.clone(), condvar: Condvar::new(), } } @@ -93,29 +63,20 @@ impl InputDevice for VirtIOInputWrapper { } } - // fn events(&self) -> &VecDeque { - // &self.inner.exclusive_access().events - // } - fn handle_irq(&self) { let mut count = 0; let mut result = 0; - let mut key = 0; self.inner.exclusive_session(|inner| { inner.virtio_input.ack_interrupt(); - while let Some((token, event)) = inner.virtio_input.pop_pending_event() { + while let Some(event) = inner.virtio_input.pop_pending_event() { count += 1; - key = token; result = (event.event_type as u64) << 48 | (event.code as u64) << 32 | (event.value) as u64; inner.events.push_back(result); - // for test - //println!("[KERN] inputdev_handle_irq: event: {:x}", result); } }); if count > 0 { - //self.condvars.get(&key).unwrap().signal(); self.condvar.signal(); }; } diff --git a/os/src/main.rs b/os/src/main.rs index 4819ea6..1103c57 100644 --- a/os/src/main.rs +++ b/os/src/main.rs @@ -29,7 +29,6 @@ mod trap; use crate::drivers::chardev::CharDevice; use crate::drivers::chardev::UART; -//use syscall::create_desktop; //for test core::arch::global_asm!(include_str!("entry.asm")); @@ -59,7 +58,6 @@ pub fn rust_main() -> ! { UART.init(); println!("KERN: init gpu"); let _gpu = GPU_DEVICE.clone(); - //let _input_condvar = INPUT_CONDVAR.clone(); println!("KERN: init keyboard"); let _keyboard = KEYBOARD_DEVICE.clone(); println!("KERN: init mouse"); diff --git a/user/Cargo.toml b/user/Cargo.toml index 35e06d5..7b1233e 100644 --- a/user/Cargo.toml +++ b/user/Cargo.toml @@ -12,5 +12,7 @@ bitflags = "1.2.1" riscv = { git = "https://github.com/rcore-os/riscv", features = ["inline-asm"] } embedded-graphics = "0.7.1" oorandom ="11" +virtio-input-decoder = "0.1.4" + [profile.release] debug = true \ No newline at end of file diff --git a/user/src/bin/gui_rect.rs b/user/src/bin/gui_rect.rs index 39f8173..c8696be 100644 --- a/user/src/bin/gui_rect.rs +++ b/user/src/bin/gui_rect.rs @@ -48,7 +48,6 @@ impl DrawingBoard { #[no_mangle] pub fn main() -> i32 { - // let fb_ptr = framebuffer() as *mut u8; let mut board = DrawingBoard::new(); let _ = board.disp.clear(Rgb888::BLACK).unwrap(); for i in 0..20 { diff --git a/user/src/bin/gui_simple.rs b/user/src/bin/gui_simple.rs index e55232d..ccf5b89 100644 --- a/user/src/bin/gui_simple.rs +++ b/user/src/bin/gui_simple.rs @@ -1,7 +1,6 @@ #![no_std] #![no_main] -#[macro_use] extern crate user_lib; use user_lib::{VIRTGPU_XRES, VIRTGPU_YRES, Display}; diff --git a/user/src/bin/gui_snake.rs b/user/src/bin/gui_snake.rs index b28fd9c..080c472 100644 --- a/user/src/bin/gui_snake.rs +++ b/user/src/bin/gui_snake.rs @@ -1,7 +1,6 @@ #![no_std] #![no_main] -#[macro_use] extern crate user_lib; extern crate alloc; diff --git a/user/src/bin/inputdev_event.rs b/user/src/bin/inputdev_event.rs index 1e5b5a1..5b820d8 100644 --- a/user/src/bin/inputdev_event.rs +++ b/user/src/bin/inputdev_event.rs @@ -1,7 +1,7 @@ #![no_std] #![no_main] -use user_lib::{event_get}; +use user_lib::{event_get, DecodeType, Key, KeyType}; #[macro_use] extern crate user_lib; @@ -9,13 +9,17 @@ extern crate user_lib; #[no_mangle] pub fn main() -> i32 { println!("Input device event test"); - let mut event=0; - for _ in 0..3 { - while event==0 { - event = event_get(); - } - println!("event: {:?}", event); + loop { + if let Some(event) = event_get() { + if let Some(decoder_type) = event.decode() { + println!("{:?}", decoder_type); + if let DecodeType::Key(key, keytype) = decoder_type { + if key == Key::Enter && keytype == KeyType::Press { + break; + } + } + } + } } - 0 } \ No newline at end of file diff --git a/user/src/io.rs b/user/src/io.rs index 6cc2e66..baaa338 100644 --- a/user/src/io.rs +++ b/user/src/io.rs @@ -2,6 +2,8 @@ use super::*; use embedded_graphics::prelude::{RgbColor, Size}; use embedded_graphics::{draw_target::DrawTarget, prelude::OriginDimensions}; use embedded_graphics::pixelcolor::Rgb888; +use virtio_input_decoder::Decoder; +pub use virtio_input_decoder::{DecodeType, Key, KeyType, Mouse}; pub const VIRTGPU_XRES: u32 = 1280; pub const VIRTGPU_YRES: u32 = 800; @@ -14,17 +16,6 @@ pub fn framebuffer_flush() -> isize { sys_framebuffer_flush() } -pub fn event_get() -> isize { - sys_event_get() -} - -pub fn key_pressed() -> bool { - if sys_key_pressed() == 1 { - true - } else { - false - } -} pub struct Display { pub size: Size, pub fb: &'static mut [u8], @@ -76,3 +67,52 @@ impl DrawTarget for Display { Ok(()) } } + +pub fn event_get() -> Option { + let raw_value = sys_event_get(); + if raw_value == 0 { + None + } else { + Some((raw_value as u64).into()) + } +} + +pub fn key_pressed() -> bool { + if sys_key_pressed() == 1 { + true + } else { + false + } +} + +#[repr(C)] +pub struct InputEvent { + pub event_type: u16, + pub code: u16, + pub value: u32, +} + +impl From for InputEvent { + fn from(mut v: u64) -> Self { + let value = v as u32; + v >>= 32; + let code = v as u16; + v >>= 16; + let event_type = v as u16; + Self { + event_type, + code, + value, + } + } +} + +impl InputEvent { + pub fn decode(&self) -> Option { + Decoder::decode( + self.event_type as usize, + self.code as usize, + self.value as usize, + ).ok() + } +} \ No newline at end of file From 3183b81f8770262c6c62f75e2da9fdb07c4fccff Mon Sep 17 00:00:00 2001 From: Yifan Wu Date: Fri, 13 Jan 2023 08:55:42 +0800 Subject: [PATCH 41/68] updates from ch9 --- os/Cargo.toml | 4 +- os/src/drivers/chardev/ns16550a.rs | 5 +- os/src/drivers/input/mod.rs | 43 +------- os/src/fs/pipe.rs | 2 +- os/src/main.rs | 3 - os/src/mm/address.rs | 1 - os/src/mm/frame_allocator.rs | 9 +- os/src/mm/memory_set.rs | 28 ++--- os/src/mm/mod.rs | 4 +- os/src/syscall/fs.rs | 2 +- os/src/syscall/gui.rs | 31 +++--- os/src/syscall/input.rs | 17 ++- os/src/syscall/mod.rs | 8 +- user/Cargo.toml | 2 + user/src/bin/gui_rect.rs | 67 +----------- user/src/bin/gui_simple.rs | 28 +++-- user/src/bin/gui_snake.rs | 57 +--------- user/src/bin/inputdev_event.rs | 20 ++-- user/src/file.rs | 30 ++++++ user/src/io.rs | 118 ++++++++++++++++++++ user/src/lib.rs | 166 ++--------------------------- user/src/sync.rs | 32 ++++++ user/src/task.rs | 82 ++++++++++++++ 23 files changed, 350 insertions(+), 409 deletions(-) create mode 100644 user/src/file.rs create mode 100644 user/src/io.rs create mode 100644 user/src/sync.rs create mode 100644 user/src/task.rs diff --git a/os/Cargo.toml b/os/Cargo.toml index ded2765..d8f4216 100644 --- a/os/Cargo.toml +++ b/os/Cargo.toml @@ -13,10 +13,8 @@ buddy_system_allocator = "0.6" bitflags = "1.2.1" xmas-elf = "0.7.0" volatile = "0.3" -#virtio-drivers = { git = "https://github.com/rcore-os/virtio-drivers", rev = "4ee80e5" } -virtio-drivers = { git = "https://github.com/rcore-os/virtio-drivers", rev = "70b5850" } +virtio-drivers = { git = "https://github.com/rcore-os/virtio-drivers", rev = "4ee80e5" } easy-fs = { path = "../easy-fs" } -#virtio-input-decoder = "0.1.4" embedded-graphics = "0.7.1" tinybmp = "0.3.1" diff --git a/os/src/drivers/chardev/ns16550a.rs b/os/src/drivers/chardev/ns16550a.rs index 127a4ce..7122cec 100644 --- a/os/src/drivers/chardev/ns16550a.rs +++ b/os/src/drivers/chardev/ns16550a.rs @@ -143,12 +143,13 @@ impl NS16550a { } pub fn read_buffer_is_empty(&self) -> bool { - self.inner.exclusive_session(|inner| inner.read_buffer.is_empty()) + self.inner + .exclusive_session(|inner| inner.read_buffer.is_empty()) } } impl CharDevice for NS16550a { - fn init(&self){ + fn init(&self) { let mut inner = self.inner.exclusive_access(); inner.ns16550a.init(); drop(inner); diff --git a/os/src/drivers/input/mod.rs b/os/src/drivers/input/mod.rs index 857f12a..a9f5f0b 100644 --- a/os/src/drivers/input/mod.rs +++ b/os/src/drivers/input/mod.rs @@ -16,41 +16,20 @@ struct VirtIOInputInner { struct VirtIOInputWrapper { inner: UPIntrFreeCell, - //condvars: BTreeMap, - //condvar: Arc:: , - condvar:Condvar, + condvar: Condvar, } pub trait InputDevice: Send + Sync + Any { fn read_event(&self) -> u64; fn handle_irq(&self); - // fn events(&self) -> &VecDeque; fn is_empty(&self) -> bool; } lazy_static::lazy_static!( pub static ref KEYBOARD_DEVICE: Arc = Arc::new(VirtIOInputWrapper::new(VIRTIO5)); pub static ref MOUSE_DEVICE: Arc = Arc::new(VirtIOInputWrapper::new(VIRTIO6)); - // pub static ref INPUT_CONDVAR: Arc:: = Arc::new(Condvar::new()); ); -// from virtio-drivers/src/input.rs -//const QUEUE_SIZE: u16 = 32; -// pub fn read_input_event() -> u64 { -// loop { - -// //let mut inner = self.inner.exclusive_access(); -// let kb=KEYBOARD_DEVICE.clone(); -// let evs = kb.events(); -// if let Some(event) = evs.pop_front() { -// return event; -// } else { -// let task_cx_ptr = INPUT_CONDVAR.clone().wait_no_sched(); -// drop(inner); -// schedule(task_cx_ptr); -// } -// } -// } impl VirtIOInputWrapper { pub fn new(addr: usize) -> Self { let inner = VirtIOInputInner { @@ -59,17 +38,8 @@ impl VirtIOInputWrapper { }, events: VecDeque::new(), }; - - // let mut condvars = BTreeMap::new(); - // let channels = QUEUE_SIZE; - // for i in 0..channels { - // let condvar = Condvar::new(); - // condvars.insert(i, condvar); - // } - Self { inner: unsafe { UPIntrFreeCell::new(inner) }, - //condvar: INPUT_CONDVAR.clone(), condvar: Condvar::new(), } } @@ -93,29 +63,20 @@ impl InputDevice for VirtIOInputWrapper { } } - // fn events(&self) -> &VecDeque { - // &self.inner.exclusive_access().events - // } - fn handle_irq(&self) { let mut count = 0; let mut result = 0; - let mut key = 0; self.inner.exclusive_session(|inner| { inner.virtio_input.ack_interrupt(); - while let Some((token, event)) = inner.virtio_input.pop_pending_event() { + while let Some(event) = inner.virtio_input.pop_pending_event() { count += 1; - key = token; result = (event.event_type as u64) << 48 | (event.code as u64) << 32 | (event.value) as u64; inner.events.push_back(result); - // for test - //println!("[KERN] inputdev_handle_irq: event: {:x}", result); } }); if count > 0 { - //self.condvars.get(&key).unwrap().signal(); self.condvar.signal(); }; } diff --git a/os/src/fs/pipe.rs b/os/src/fs/pipe.rs index 531eec4..d10dc33 100644 --- a/os/src/fs/pipe.rs +++ b/os/src/fs/pipe.rs @@ -170,4 +170,4 @@ impl File for Pipe { } } } -} \ No newline at end of file +} diff --git a/os/src/main.rs b/os/src/main.rs index 7e5a20a..1103c57 100644 --- a/os/src/main.rs +++ b/os/src/main.rs @@ -29,7 +29,6 @@ mod trap; use crate::drivers::chardev::CharDevice; use crate::drivers::chardev::UART; -//use syscall::create_desktop; //for test core::arch::global_asm!(include_str!("entry.asm")); @@ -59,7 +58,6 @@ pub fn rust_main() -> ! { UART.init(); println!("KERN: init gpu"); let _gpu = GPU_DEVICE.clone(); - //let _input_condvar = INPUT_CONDVAR.clone(); println!("KERN: init keyboard"); let _keyboard = KEYBOARD_DEVICE.clone(); println!("KERN: init mouse"); @@ -70,7 +68,6 @@ pub fn rust_main() -> ! { timer::set_next_trigger(); board::device_init(); fs::list_apps(); - //gui::init_paint(); task::add_initproc(); *DEV_NON_BLOCKING_ACCESS.exclusive_access() = true; task::run_tasks(); diff --git a/os/src/mm/address.rs b/os/src/mm/address.rs index 8792f62..cf147a0 100644 --- a/os/src/mm/address.rs +++ b/os/src/mm/address.rs @@ -260,4 +260,3 @@ where } } pub type VPNRange = SimpleRange; -pub type PPNRange = SimpleRange; diff --git a/os/src/mm/frame_allocator.rs b/os/src/mm/frame_allocator.rs index 275fb17..1ecfe99 100644 --- a/os/src/mm/frame_allocator.rs +++ b/os/src/mm/frame_allocator.rs @@ -7,7 +7,6 @@ use lazy_static::*; pub struct FrameTracker { pub ppn: PhysPageNum, - pub nodrop: bool, } impl FrameTracker { @@ -17,10 +16,7 @@ impl FrameTracker { for i in bytes_array { *i = 0; } - Self { ppn, nodrop: false } - } - pub fn new_noalloc(ppn: PhysPageNum) -> Self { - Self { ppn, nodrop: true } + Self { ppn } } } @@ -32,9 +28,6 @@ impl Debug for FrameTracker { impl Drop for FrameTracker { fn drop(&mut self) { - if self.nodrop { - return; - } frame_dealloc(self.ppn); } } diff --git a/os/src/mm/memory_set.rs b/os/src/mm/memory_set.rs index bec0b93..7cdd394 100644 --- a/os/src/mm/memory_set.rs +++ b/os/src/mm/memory_set.rs @@ -1,7 +1,7 @@ use super::{frame_alloc, FrameTracker}; use super::{PTEFlags, PageTable, PageTableEntry}; use super::{PhysAddr, PhysPageNum, VirtAddr, VirtPageNum}; -use super::{StepByOne, VPNRange, PPNRange}; +use super::{StepByOne, VPNRange}; use crate::config::{MEMORY_END, MMIO, PAGE_SIZE, TRAMPOLINE}; use crate::sync::UPIntrFreeCell; use alloc::collections::BTreeMap; @@ -71,17 +71,16 @@ impl MemorySet { self.areas.remove(idx); } } - fn push(&mut self, mut map_area: MapArea, data: Option<&[u8]>) { + /// Add a new MapArea into this MemorySet. + /// Assuming that there are no conflicts in the virtual address + /// space. + pub fn push(&mut self, mut map_area: MapArea, data: Option<&[u8]>) { map_area.map(&mut self.page_table); if let Some(data) = data { map_area.copy_data(&mut self.page_table, data); } self.areas.push(map_area); } - pub fn push_noalloc(&mut self, mut map_area: MapArea, ppn_range: PPNRange) { - map_area.map_noalloc(&mut self.page_table, ppn_range); - self.areas.push(map_area); - } /// Mention that trampoline is not collected by areas. fn map_trampoline(&mut self) { self.page_table.map( @@ -290,8 +289,10 @@ impl MapArea { ppn = frame.ppn; self.data_frames.insert(vpn, frame); } - MapType::Noalloc => { - panic!("Noalloc should not be mapped"); + MapType::Linear(pn_offset) => { + // check for sv39 + assert!(vpn.0 < (1usize << 27)); + ppn = PhysPageNum((vpn.0 as isize + pn_offset) as usize); } } let pte_flags = PTEFlags::from_bits(self.map_perm.bits).unwrap(); @@ -308,14 +309,6 @@ impl MapArea { self.map_one(page_table, vpn); } } - pub fn map_noalloc(&mut self, page_table: &mut PageTable,ppn_range:PPNRange) { - for (vpn,ppn) in core::iter::zip(self.vpn_range,ppn_range) { - self.data_frames.insert(vpn, FrameTracker::new_noalloc(ppn)); - let pte_flags = PTEFlags::from_bits(self.map_perm.bits).unwrap(); - page_table.map(vpn, ppn, pte_flags); - } - } - pub fn unmap(&mut self, page_table: &mut PageTable) { for vpn in self.vpn_range { self.unmap_one(page_table, vpn); @@ -349,7 +342,8 @@ impl MapArea { pub enum MapType { Identical, Framed, - Noalloc, + /// offset of page num + Linear(isize), } bitflags! { diff --git a/os/src/mm/mod.rs b/os/src/mm/mod.rs index 9482a30..77d62f4 100644 --- a/os/src/mm/mod.rs +++ b/os/src/mm/mod.rs @@ -4,11 +4,11 @@ mod heap_allocator; mod memory_set; mod page_table; -pub use address::{VPNRange, PPNRange}; +pub use address::VPNRange; pub use address::{PhysAddr, PhysPageNum, StepByOne, VirtAddr, VirtPageNum}; pub use frame_allocator::{frame_alloc, frame_dealloc, FrameTracker}; pub use memory_set::remap_test; -pub use memory_set::{kernel_token, MapPermission, MemorySet, MapArea, MapType, KERNEL_SPACE}; +pub use memory_set::{kernel_token, MapArea, MapPermission, MapType, MemorySet, KERNEL_SPACE}; use page_table::PTEFlags; pub use page_table::{ translated_byte_buffer, translated_ref, translated_refmut, translated_str, PageTable, diff --git a/os/src/syscall/fs.rs b/os/src/syscall/fs.rs index af1585c..2758825 100644 --- a/os/src/syscall/fs.rs +++ b/os/src/syscall/fs.rs @@ -96,4 +96,4 @@ pub fn sys_dup(fd: usize) -> isize { let new_fd = inner.alloc_fd(); inner.fd_table[new_fd] = Some(Arc::clone(inner.fd_table[fd].as_ref().unwrap())); new_fd as isize -} \ No newline at end of file +} diff --git a/os/src/syscall/gui.rs b/os/src/syscall/gui.rs index 5d41c0c..c5ba8a4 100644 --- a/os/src/syscall/gui.rs +++ b/os/src/syscall/gui.rs @@ -1,37 +1,34 @@ -use crate::mm::{MapArea, MapPermission, MapType, PPNRange, PhysAddr}; -use crate::task::current_process; - -//use crate::gui::*; use crate::drivers::GPU_DEVICE; +use crate::mm::{MapArea, MapPermission, MapType, PhysAddr, VirtAddr}; +use crate::task::current_process; const FB_VADDR: usize = 0x10000000; pub fn sys_framebuffer() -> isize { - let gpu = GPU_DEVICE.clone(); - let fb = gpu.get_framebuffer(); + let fb = GPU_DEVICE.get_framebuffer(); let len = fb.len(); - println!("[kernel] FrameBuffer: addr 0x{:X}, len {}", fb.as_ptr() as usize , len); - let fb_ppn = PhysAddr::from(fb.as_ptr() as usize).floor(); - let fb_end_ppn = PhysAddr::from(fb.as_ptr() as usize + len).ceil(); + // println!("[kernel] FrameBuffer: addr 0x{:X}, len {}", fb.as_ptr() as usize , len); + let fb_start_pa = PhysAddr::from(fb.as_ptr() as usize); + assert!(fb_start_pa.aligned()); + let fb_start_ppn = fb_start_pa.floor(); + let fb_start_vpn = VirtAddr::from(FB_VADDR).floor(); + let pn_offset = fb_start_ppn.0 as isize - fb_start_vpn.0 as isize; let current_process = current_process(); let mut inner = current_process.inner_exclusive_access(); - let mem_set = &mut inner.memory_set; - - mem_set.push_noalloc( + inner.memory_set.push( MapArea::new( (FB_VADDR as usize).into(), (FB_VADDR + len as usize).into(), - MapType::Noalloc, + MapType::Linear(pn_offset), MapPermission::R | MapPermission::W | MapPermission::U, ), - PPNRange::new(fb_ppn, fb_end_ppn), + None, ); FB_VADDR as isize } pub fn sys_framebuffer_flush() -> isize { - let gpu = GPU_DEVICE.clone(); - gpu.flush(); + GPU_DEVICE.flush(); 0 -} \ No newline at end of file +} diff --git a/os/src/syscall/input.rs b/os/src/syscall/input.rs index 7a28259..ee86bd3 100644 --- a/os/src/syscall/input.rs +++ b/os/src/syscall/input.rs @@ -1,29 +1,28 @@ //use crate::drivers::{KEYBOARD_DEVICE,MOUSE_DEVICE,INPUT_CONDVAR,read_input_event}; -use crate::drivers::{KEYBOARD_DEVICE,MOUSE_DEVICE}; +use crate::drivers::{KEYBOARD_DEVICE, MOUSE_DEVICE}; -pub fn sys_event_get() ->isize { +pub fn sys_event_get() -> isize { let kb = KEYBOARD_DEVICE.clone(); let mouse = MOUSE_DEVICE.clone(); //let input=INPUT_CONDVAR.clone(); //read_input_event() as isize - if !kb.is_empty(){ + if !kb.is_empty() { kb.read_event() as isize - } else if !mouse.is_empty() { + } else if !mouse.is_empty() { mouse.read_event() as isize } else { 0 } - } use crate::drivers::chardev::UART; /// check UART's read-buffer is empty or not -pub fn sys_key_pressed() -> isize { - let res =!UART.read_buffer_is_empty(); +pub fn sys_key_pressed() -> isize { + let res = !UART.read_buffer_is_empty(); if res { 1 } else { 0 - } -} \ No newline at end of file + } +} diff --git a/os/src/syscall/mod.rs b/os/src/syscall/mod.rs index d883d52..d28073f 100644 --- a/os/src/syscall/mod.rs +++ b/os/src/syscall/mod.rs @@ -31,18 +31,18 @@ const SYSCALL_EVENT_GET: usize = 3000; const SYSCALL_KEY_PRESSED: usize = 3001; mod fs; +mod gui; +mod input; mod process; mod sync; mod thread; -mod gui; -mod input; use fs::*; +use gui::*; +use input::*; use process::*; use sync::*; use thread::*; -use gui::*; -use input::*; pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize { match syscall_id { diff --git a/user/Cargo.toml b/user/Cargo.toml index 35e06d5..7b1233e 100644 --- a/user/Cargo.toml +++ b/user/Cargo.toml @@ -12,5 +12,7 @@ bitflags = "1.2.1" riscv = { git = "https://github.com/rcore-os/riscv", features = ["inline-asm"] } embedded-graphics = "0.7.1" oorandom ="11" +virtio-input-decoder = "0.1.4" + [profile.release] debug = true \ No newline at end of file diff --git a/user/src/bin/gui_rect.rs b/user/src/bin/gui_rect.rs index e9007f6..c8696be 100644 --- a/user/src/bin/gui_rect.rs +++ b/user/src/bin/gui_rect.rs @@ -1,77 +1,19 @@ #![no_std] #![no_main] -#[macro_use] extern crate user_lib; extern crate alloc; -use user_lib::{framebuffer, framebuffer_flush}; +use user_lib::{VIRTGPU_XRES, VIRTGPU_YRES, Display}; use embedded_graphics::pixelcolor::Rgb888; -use embedded_graphics::prelude::{Drawable, Point, RgbColor, Size}; -use embedded_graphics::primitives::Primitive; -use embedded_graphics::primitives::{PrimitiveStyle, Rectangle}; -use embedded_graphics::{draw_target::DrawTarget, prelude::OriginDimensions}; - -pub const VIRTGPU_XRES: usize = 1280; -pub const VIRTGPU_YRES: usize = 800; -pub const VIRTGPU_LEN: usize = VIRTGPU_XRES * VIRTGPU_YRES * 4; +use embedded_graphics::prelude::{DrawTarget, Drawable, Point, RgbColor, Size}; +use embedded_graphics::primitives::{Primitive, PrimitiveStyle, Rectangle}; const INIT_X: i32 = 640; const INIT_Y: i32 = 400; const RECT_SIZE: u32 = 40; -pub struct Display { - pub size: Size, - pub point: Point, - //pub fb: Arc<&'static mut [u8]>, - pub fb: &'static mut [u8], -} - -impl Display { - pub fn new(size: Size, point: Point) -> Self { - let fb_ptr = framebuffer() as *mut u8; - println!( - "Hello world from user mode program! 0x{:X} , len {}", - fb_ptr as usize, VIRTGPU_LEN - ); - let fb = - unsafe { core::slice::from_raw_parts_mut(fb_ptr as *mut u8, VIRTGPU_LEN as usize) }; - Self { size, point, fb } - } -} - -impl OriginDimensions for Display { - fn size(&self) -> Size { - self.size - } -} - -impl DrawTarget for Display { - type Color = Rgb888; - - type Error = core::convert::Infallible; - - fn draw_iter(&mut self, pixels: I) -> Result<(), Self::Error> - where - I: IntoIterator>, - { - pixels.into_iter().for_each(|px| { - let idx = ((self.point.y + px.0.y) * VIRTGPU_XRES as i32 + self.point.x + px.0.x) - as usize - * 4; - if idx + 2 >= self.fb.len() { - return; - } - self.fb[idx] = px.1.b(); - self.fb[idx + 1] = px.1.g(); - self.fb[idx + 2] = px.1.r(); - }); - framebuffer_flush(); - Ok(()) - } -} - pub struct DrawingBoard { disp: Display, latest_pos: Point, @@ -80,7 +22,7 @@ pub struct DrawingBoard { impl DrawingBoard { pub fn new() -> Self { Self { - disp: Display::new(Size::new(1280, 800), Point::new(0, 0)), + disp: Display::new(Size::new(VIRTGPU_XRES, VIRTGPU_YRES)), latest_pos: Point::new(INIT_X, INIT_Y), } } @@ -106,7 +48,6 @@ impl DrawingBoard { #[no_mangle] pub fn main() -> i32 { - // let fb_ptr = framebuffer() as *mut u8; let mut board = DrawingBoard::new(); let _ = board.disp.clear(Rgb888::BLACK).unwrap(); for i in 0..20 { diff --git a/user/src/bin/gui_simple.rs b/user/src/bin/gui_simple.rs index 83fb721..ccf5b89 100644 --- a/user/src/bin/gui_simple.rs +++ b/user/src/bin/gui_simple.rs @@ -1,27 +1,23 @@ #![no_std] #![no_main] -#[macro_use] extern crate user_lib; -use user_lib::{framebuffer, framebuffer_flush}; - -pub const VIRTGPU_XRES: usize = 1280; -pub const VIRTGPU_YRES: usize = 800; +use user_lib::{VIRTGPU_XRES, VIRTGPU_YRES, Display}; +use embedded_graphics::prelude::Size; #[no_mangle] pub fn main() -> i32 { - let fb_ptr =framebuffer() as *mut u8; - println!("Hello world from user mode program! 0x{:X} , len {}", fb_ptr as usize, VIRTGPU_XRES*VIRTGPU_YRES*4); - let fb= unsafe {core::slice::from_raw_parts_mut(fb_ptr as *mut u8, VIRTGPU_XRES*VIRTGPU_YRES*4 as usize)}; - for y in 0..800 { - for x in 0..1280 { - let idx = (y * 1280 + x) * 4; - fb[idx] = x as u8; - fb[idx + 1] = y as u8; - fb[idx + 2] = (x + y) as u8; + let mut disp = Display::new(Size::new(VIRTGPU_XRES, VIRTGPU_YRES)); + disp.paint_on_framebuffer(|fb| { + for y in 0..VIRTGPU_YRES as usize { + for x in 0..VIRTGPU_XRES as usize { + let idx = (y * VIRTGPU_XRES as usize + x) * 4; + fb[idx] = x as u8; + fb[idx + 1] = y as u8; + fb[idx + 2] = (x + y) as u8; + } } - } - framebuffer_flush(); + }); 0 } diff --git a/user/src/bin/gui_snake.rs b/user/src/bin/gui_snake.rs index ce36b2e..080c472 100644 --- a/user/src/bin/gui_snake.rs +++ b/user/src/bin/gui_snake.rs @@ -1,12 +1,11 @@ #![no_std] #![no_main] -#[macro_use] extern crate user_lib; extern crate alloc; use user_lib::console::getchar; -use user_lib::{framebuffer, framebuffer_flush, key_pressed, sleep}; +use user_lib::{Display, key_pressed, sleep, VIRTGPU_XRES, VIRTGPU_YRES}; use embedded_graphics::pixelcolor::*; use embedded_graphics::prelude::{Drawable, Point, RgbColor, Size}; @@ -16,58 +15,6 @@ use embedded_graphics::Pixel; use embedded_graphics::{draw_target::DrawTarget, prelude::OriginDimensions}; use oorandom; //random generator -pub const VIRTGPU_XRES: usize = 1280; -pub const VIRTGPU_YRES: usize = 800; -pub const VIRTGPU_LEN: usize = VIRTGPU_XRES * VIRTGPU_YRES * 4; - -pub struct Display { - pub size: Size, - pub point: Point, - pub fb: &'static mut [u8], -} - -impl Display { - pub fn new(size: Size, point: Point) -> Self { - let fb_ptr = framebuffer() as *mut u8; - println!( - "Hello world from user mode program! 0x{:X} , len {}", - fb_ptr as usize, VIRTGPU_LEN - ); - let fb = - unsafe { core::slice::from_raw_parts_mut(fb_ptr as *mut u8, VIRTGPU_LEN as usize) }; - Self { size, point, fb } - } -} - -impl OriginDimensions for Display { - fn size(&self) -> Size { - self.size - } -} - -impl DrawTarget for Display { - type Color = Rgb888; - type Error = core::convert::Infallible; - - fn draw_iter(&mut self, pixels: I) -> Result<(), Self::Error> - where - I: IntoIterator>, - { - pixels.into_iter().for_each(|px| { - let idx = ((self.point.y + px.0.y) * VIRTGPU_XRES as i32 + self.point.x + px.0.x) - as usize - * 4; - if idx + 2 >= self.fb.len() { - return; - } - self.fb[idx] = px.1.b(); - self.fb[idx + 1] = px.1.g(); - self.fb[idx + 2] = px.1.r(); - }); - framebuffer_flush(); - Ok(()) - } -} struct Snake { parts: [Pixel; MAX_SIZE], len: usize, @@ -380,7 +327,7 @@ const LF: u8 = 0x0au8; const CR: u8 = 0x0du8; #[no_mangle] pub fn main() -> i32 { - let mut disp = Display::new(Size::new(1280, 800), Point::new(0, 0)); + let mut disp = Display::new(Size::new(VIRTGPU_XRES, VIRTGPU_YRES)); let mut game = SnakeGame::<20, Rgb888>::new(1280, 800, 20, 20, Rgb888::RED, Rgb888::YELLOW, 50); let _ = disp.clear(Rgb888::BLACK).unwrap(); loop { diff --git a/user/src/bin/inputdev_event.rs b/user/src/bin/inputdev_event.rs index 1e5b5a1..5b820d8 100644 --- a/user/src/bin/inputdev_event.rs +++ b/user/src/bin/inputdev_event.rs @@ -1,7 +1,7 @@ #![no_std] #![no_main] -use user_lib::{event_get}; +use user_lib::{event_get, DecodeType, Key, KeyType}; #[macro_use] extern crate user_lib; @@ -9,13 +9,17 @@ extern crate user_lib; #[no_mangle] pub fn main() -> i32 { println!("Input device event test"); - let mut event=0; - for _ in 0..3 { - while event==0 { - event = event_get(); - } - println!("event: {:?}", event); + loop { + if let Some(event) = event_get() { + if let Some(decoder_type) = event.decode() { + println!("{:?}", decoder_type); + if let DecodeType::Key(key, keytype) = decoder_type { + if key == Key::Enter && keytype == KeyType::Press { + break; + } + } + } + } } - 0 } \ No newline at end of file diff --git a/user/src/file.rs b/user/src/file.rs new file mode 100644 index 0000000..bf77667 --- /dev/null +++ b/user/src/file.rs @@ -0,0 +1,30 @@ +use super::*; + +bitflags! { + pub struct OpenFlags: u32 { + const RDONLY = 0; + const WRONLY = 1 << 0; + const RDWR = 1 << 1; + const CREATE = 1 << 9; + const TRUNC = 1 << 10; + } +} + +pub fn dup(fd: usize) -> isize { + sys_dup(fd) +} +pub fn open(path: &str, flags: OpenFlags) -> isize { + sys_open(path, flags.bits) +} +pub fn close(fd: usize) -> isize { + sys_close(fd) +} +pub fn pipe(pipe_fd: &mut [usize]) -> isize { + sys_pipe(pipe_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) +} \ No newline at end of file diff --git a/user/src/io.rs b/user/src/io.rs new file mode 100644 index 0000000..baaa338 --- /dev/null +++ b/user/src/io.rs @@ -0,0 +1,118 @@ +use super::*; +use embedded_graphics::prelude::{RgbColor, Size}; +use embedded_graphics::{draw_target::DrawTarget, prelude::OriginDimensions}; +use embedded_graphics::pixelcolor::Rgb888; +use virtio_input_decoder::Decoder; +pub use virtio_input_decoder::{DecodeType, Key, KeyType, Mouse}; + +pub const VIRTGPU_XRES: u32 = 1280; +pub const VIRTGPU_YRES: u32 = 800; +pub const VIRTGPU_LEN: usize = (VIRTGPU_XRES * VIRTGPU_YRES * 4) as usize; + +pub fn framebuffer() -> isize { + sys_framebuffer() +} +pub fn framebuffer_flush() -> isize { + sys_framebuffer_flush() +} + +pub struct Display { + pub size: Size, + pub fb: &'static mut [u8], +} + +impl Display { + pub fn new(size: Size) -> Self { + let fb_ptr = framebuffer() as *mut u8; + let fb = + unsafe { core::slice::from_raw_parts_mut(fb_ptr, VIRTGPU_LEN as usize) }; + Self { size, fb} + } + pub fn framebuffer(&mut self) -> &mut [u8] { + self.fb + } + pub fn paint_on_framebuffer(&mut self, p: impl FnOnce(&mut [u8]) -> ()) { + p(self.framebuffer()); + framebuffer_flush(); + } +} + +impl OriginDimensions for Display { + fn size(&self) -> Size { + self.size + } +} + +impl DrawTarget for Display { + type Color = Rgb888; + + type Error = core::convert::Infallible; + + fn draw_iter(&mut self, pixels: I) -> Result<(), Self::Error> + where + I: IntoIterator>, + { + pixels.into_iter().for_each(|px| { + let idx = (px.0.y * VIRTGPU_XRES as i32 + px.0.x) + as usize + * 4; + if idx + 2 >= self.fb.len() { + return; + } + self.fb[idx] = px.1.b(); + self.fb[idx + 1] = px.1.g(); + self.fb[idx + 2] = px.1.r(); + }); + framebuffer_flush(); + Ok(()) + } +} + +pub fn event_get() -> Option { + let raw_value = sys_event_get(); + if raw_value == 0 { + None + } else { + Some((raw_value as u64).into()) + } +} + +pub fn key_pressed() -> bool { + if sys_key_pressed() == 1 { + true + } else { + false + } +} + +#[repr(C)] +pub struct InputEvent { + pub event_type: u16, + pub code: u16, + pub value: u32, +} + +impl From for InputEvent { + fn from(mut v: u64) -> Self { + let value = v as u32; + v >>= 32; + let code = v as u16; + v >>= 16; + let event_type = v as u16; + Self { + event_type, + code, + value, + } + } +} + +impl InputEvent { + pub fn decode(&self) -> Option { + Decoder::decode( + self.event_type as usize, + self.code as usize, + self.value as usize, + ).ok() + } +} \ No newline at end of file diff --git a/user/src/lib.rs b/user/src/lib.rs index 31ce9ba..0d0db85 100644 --- a/user/src/lib.rs +++ b/user/src/lib.rs @@ -8,6 +8,10 @@ pub mod console; mod lang_items; mod syscall; +mod file; +mod task; +mod sync; +mod io; extern crate alloc; #[macro_use] @@ -16,6 +20,10 @@ extern crate bitflags; use alloc::vec::Vec; use buddy_system_allocator::LockedHeap; use syscall::*; +pub use file::*; +pub use task::*; +pub use sync::*; +pub use io::*; const USER_HEAP_SIZE: usize = 32768; @@ -59,164 +67,6 @@ fn main(_argc: usize, _argv: &[&str]) -> 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; - } -} - -pub fn dup(fd: usize) -> isize { - sys_dup(fd) -} -pub fn open(path: &str, flags: OpenFlags) -> isize { - sys_open(path, flags.bits) -} -pub fn close(fd: usize) -> isize { - sys_close(fd) -} -pub fn pipe(pipe_fd: &mut [usize]) -> isize { - sys_pipe(pipe_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 exit(exit_code: i32) -> ! { - sys_exit(exit_code); -} -pub fn yield_() -> isize { - sys_yield() -} -pub fn get_time() -> isize { - sys_get_time() -} -pub fn getpid() -> isize { - sys_getpid() -} -pub fn fork() -> isize { - sys_fork() -} -pub fn exec(path: &str, args: &[*const u8]) -> isize { - sys_exec(path, args) -} -pub fn wait(exit_code: &mut i32) -> isize { - loop { - match sys_waitpid(-1, exit_code as *mut _) { - -2 => { - yield_(); - } - // -1 or a real pid - exit_pid => return exit_pid, - } - } -} - -pub fn waitpid(pid: usize, exit_code: &mut i32) -> isize { - loop { - match sys_waitpid(pid as isize, exit_code as *mut _) { - -2 => { - yield_(); - } - // -1 or a real pid - exit_pid => return exit_pid, - } - } -} - -pub fn waitpid_nb(pid: usize, exit_code: &mut i32) -> isize { - sys_waitpid(pid as isize, exit_code as *mut _) -} - -bitflags! { - pub struct SignalFlags: i32 { - const SIGINT = 1 << 2; - const SIGILL = 1 << 4; - const SIGABRT = 1 << 6; - const SIGFPE = 1 << 8; - const SIGSEGV = 1 << 11; - } -} - -pub fn kill(pid: usize, signal: i32) -> isize { - sys_kill(pid, signal) -} - -pub fn sleep(sleep_ms: usize) { - sys_sleep(sleep_ms); -} - -pub fn thread_create(entry: usize, arg: usize) -> isize { - sys_thread_create(entry, arg) -} -pub fn gettid() -> isize { - sys_gettid() -} -pub fn waittid(tid: usize) -> isize { - loop { - match sys_waittid(tid) { - -2 => { - yield_(); - } - exit_code => return exit_code, - } - } -} - -pub fn mutex_create() -> isize { - sys_mutex_create(false) -} -pub fn mutex_blocking_create() -> isize { - sys_mutex_create(true) -} -pub fn mutex_lock(mutex_id: usize) { - sys_mutex_lock(mutex_id); -} -pub fn mutex_unlock(mutex_id: usize) { - sys_mutex_unlock(mutex_id); -} -pub fn semaphore_create(res_count: usize) -> isize { - sys_semaphore_create(res_count) -} -pub fn semaphore_up(sem_id: usize) { - sys_semaphore_up(sem_id); -} -pub fn semaphore_down(sem_id: usize) { - sys_semaphore_down(sem_id); -} -pub fn condvar_create() -> isize { - sys_condvar_create(0) -} -pub fn condvar_signal(condvar_id: usize) { - sys_condvar_signal(condvar_id); -} -pub fn condvar_wait(condvar_id: usize, mutex_id: usize) { - sys_condvar_wait(condvar_id, mutex_id); -} -pub fn framebuffer() -> isize { - sys_framebuffer() -} -pub fn framebuffer_flush() -> isize { - sys_framebuffer_flush() -} - -pub fn event_get() -> isize { - sys_event_get() -} - -pub fn key_pressed() -> bool { - if sys_key_pressed() == 1 { - true - } else { - false - } -} - #[macro_export] macro_rules! vstore { ($var_ref: expr, $value: expr) => { diff --git a/user/src/sync.rs b/user/src/sync.rs new file mode 100644 index 0000000..fbed4e3 --- /dev/null +++ b/user/src/sync.rs @@ -0,0 +1,32 @@ +use super::*; + +pub fn mutex_create() -> isize { + sys_mutex_create(false) +} +pub fn mutex_blocking_create() -> isize { + sys_mutex_create(true) +} +pub fn mutex_lock(mutex_id: usize) { + sys_mutex_lock(mutex_id); +} +pub fn mutex_unlock(mutex_id: usize) { + sys_mutex_unlock(mutex_id); +} +pub fn semaphore_create(res_count: usize) -> isize { + sys_semaphore_create(res_count) +} +pub fn semaphore_up(sem_id: usize) { + sys_semaphore_up(sem_id); +} +pub fn semaphore_down(sem_id: usize) { + sys_semaphore_down(sem_id); +} +pub fn condvar_create() -> isize { + sys_condvar_create(0) +} +pub fn condvar_signal(condvar_id: usize) { + sys_condvar_signal(condvar_id); +} +pub fn condvar_wait(condvar_id: usize, mutex_id: usize) { + sys_condvar_wait(condvar_id, mutex_id); +} \ No newline at end of file diff --git a/user/src/task.rs b/user/src/task.rs new file mode 100644 index 0000000..87d0dda --- /dev/null +++ b/user/src/task.rs @@ -0,0 +1,82 @@ +use super::*; + +pub fn exit(exit_code: i32) -> ! { + sys_exit(exit_code); +} +pub fn yield_() -> isize { + sys_yield() +} +pub fn get_time() -> isize { + sys_get_time() +} +pub fn getpid() -> isize { + sys_getpid() +} +pub fn fork() -> isize { + sys_fork() +} +pub fn exec(path: &str, args: &[*const u8]) -> isize { + sys_exec(path, args) +} +pub fn wait(exit_code: &mut i32) -> isize { + loop { + match sys_waitpid(-1, exit_code as *mut _) { + -2 => { + yield_(); + } + // -1 or a real pid + exit_pid => return exit_pid, + } + } +} + +pub fn waitpid(pid: usize, exit_code: &mut i32) -> isize { + loop { + match sys_waitpid(pid as isize, exit_code as *mut _) { + -2 => { + yield_(); + } + // -1 or a real pid + exit_pid => return exit_pid, + } + } +} + +pub fn waitpid_nb(pid: usize, exit_code: &mut i32) -> isize { + sys_waitpid(pid as isize, exit_code as *mut _) +} + +bitflags! { + pub struct SignalFlags: i32 { + const SIGINT = 1 << 2; + const SIGILL = 1 << 4; + const SIGABRT = 1 << 6; + const SIGFPE = 1 << 8; + const SIGSEGV = 1 << 11; + } +} + +pub fn kill(pid: usize, signal: i32) -> isize { + sys_kill(pid, signal) +} + +pub fn sleep(sleep_ms: usize) { + sys_sleep(sleep_ms); +} + +pub fn thread_create(entry: usize, arg: usize) -> isize { + sys_thread_create(entry, arg) +} +pub fn gettid() -> isize { + sys_gettid() +} +pub fn waittid(tid: usize) -> isize { + loop { + match sys_waittid(tid) { + -2 => { + yield_(); + } + exit_code => return exit_code, + } + } +} \ No newline at end of file From 4e84c5767e9d50c19a5d19ae18551aa31bb08fbc Mon Sep 17 00:00:00 2001 From: Yifan Wu Date: Fri, 13 Jan 2023 09:54:54 +0800 Subject: [PATCH 42/68] updates from ch8 --- user/src/bin/adder.rs | 55 ++++++++++++++ user/src/bin/adder_atomic.rs | 72 ++++++++++++++++++ user/src/bin/adder_mutex_blocking.rs | 59 +++++++++++++++ user/src/bin/adder_mutex_spin.rs | 60 +++++++++++++++ user/src/bin/adder_peterson_spin.rs | 90 +++++++++++++++++++++++ user/src/bin/adder_peterson_yield.rs | 89 ++++++++++++++++++++++ user/src/bin/adder_simple_spin.rs | 68 +++++++++++++++++ user/src/bin/adder_simple_yield.rs | 70 ++++++++++++++++++ user/src/bin/peterson.rs | 21 +++--- user/src/bin/race_adder.rs | 42 ----------- user/src/bin/race_adder_atomic.rs | 51 ------------- user/src/bin/race_adder_loop.rs | 51 ------------- user/src/bin/race_adder_mutex_blocking.rs | 46 ------------ user/src/bin/race_adder_mutex_spin.rs | 46 ------------ user/src/bin/usertests.rs | 13 ++-- 15 files changed, 582 insertions(+), 251 deletions(-) create mode 100644 user/src/bin/adder.rs create mode 100644 user/src/bin/adder_atomic.rs create mode 100644 user/src/bin/adder_mutex_blocking.rs create mode 100644 user/src/bin/adder_mutex_spin.rs create mode 100644 user/src/bin/adder_peterson_spin.rs create mode 100644 user/src/bin/adder_peterson_yield.rs create mode 100644 user/src/bin/adder_simple_spin.rs create mode 100644 user/src/bin/adder_simple_yield.rs delete mode 100644 user/src/bin/race_adder.rs delete mode 100644 user/src/bin/race_adder_atomic.rs delete mode 100644 user/src/bin/race_adder_loop.rs delete mode 100644 user/src/bin/race_adder_mutex_blocking.rs delete mode 100644 user/src/bin/race_adder_mutex_spin.rs diff --git a/user/src/bin/adder.rs b/user/src/bin/adder.rs new file mode 100644 index 0000000..e7b1611 --- /dev/null +++ b/user/src/bin/adder.rs @@ -0,0 +1,55 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; +extern crate alloc; + +use alloc::vec::Vec; +use user_lib::{exit, get_time, thread_create, waittid}; + +static mut A: usize = 0; +const PER_THREAD_DEFAULT: usize = 10000; +const THREAD_COUNT_DEFAULT: usize = 16; +static mut PER_THREAD: usize = 0; + +unsafe fn critical_section(t: &mut usize) { + let a = &mut A as *mut usize; + let cur = a.read_volatile(); + for _ in 0..500 { + *t = (*t) * (*t) % 10007; + } + a.write_volatile(cur + 1); +} + +unsafe fn f() -> ! { + let mut t = 2usize; + for _ in 0..PER_THREAD { + critical_section(&mut t); + } + exit(t as i32) +} + +#[no_mangle] +pub fn main(argc: usize, argv: &[&str]) -> i32 { + let mut thread_count = THREAD_COUNT_DEFAULT; + let mut per_thread = PER_THREAD_DEFAULT; + if argc >= 2 { + thread_count = argv[1].parse().unwrap(); + if argc >= 3 { + per_thread = argv[2].parse().unwrap(); + } + } + unsafe { PER_THREAD = per_thread; } + let start = get_time(); + let mut v = Vec::new(); + for _ in 0..thread_count { + v.push(thread_create(f as usize, 0) as usize); + } + for tid in v.into_iter() { + waittid(tid); + } + println!("time cost is {}ms", get_time() - start); + assert_eq!(unsafe { A }, unsafe { PER_THREAD } * thread_count); + 0 +} diff --git a/user/src/bin/adder_atomic.rs b/user/src/bin/adder_atomic.rs new file mode 100644 index 0000000..fe2cdb1 --- /dev/null +++ b/user/src/bin/adder_atomic.rs @@ -0,0 +1,72 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; +extern crate alloc; + +use alloc::vec::Vec; +use core::sync::atomic::{AtomicBool, Ordering}; +use user_lib::{exit, get_time, thread_create, waittid, yield_}; + +static mut A: usize = 0; +static OCCUPIED: AtomicBool = AtomicBool::new(false); +const PER_THREAD_DEFAULT: usize = 10000; +const THREAD_COUNT_DEFAULT: usize = 16; +static mut PER_THREAD: usize = 0; + +unsafe fn critical_section(t: &mut usize) { + let a = &mut A as *mut usize; + let cur = a.read_volatile(); + for _ in 0..500 { + *t = (*t) * (*t) % 10007; + } + a.write_volatile(cur + 1); +} + +fn lock() { + while OCCUPIED + .compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed) + .is_err() + { + yield_(); + } +} + +fn unlock() { + OCCUPIED.store(false, Ordering::Relaxed); +} + +unsafe fn f() -> ! { + let mut t = 2usize; + for _ in 0..PER_THREAD { + lock(); + critical_section(&mut t); + unlock(); + } + exit(t as i32) +} + +#[no_mangle] +pub fn main(argc: usize, argv: &[&str]) -> i32 { + let mut thread_count = THREAD_COUNT_DEFAULT; + let mut per_thread = PER_THREAD_DEFAULT; + if argc >= 2 { + thread_count = argv[1].parse().unwrap(); + if argc >= 3 { + per_thread = argv[2].parse().unwrap(); + } + } + unsafe { PER_THREAD = per_thread; } + let start = get_time(); + let mut v = Vec::new(); + for _ in 0..thread_count { + v.push(thread_create(f as usize, 0) as usize); + } + for tid in v.into_iter() { + waittid(tid); + } + println!("time cost is {}ms", get_time() - start); + assert_eq!(unsafe { A }, unsafe { PER_THREAD } * thread_count); + 0 +} diff --git a/user/src/bin/adder_mutex_blocking.rs b/user/src/bin/adder_mutex_blocking.rs new file mode 100644 index 0000000..963dd75 --- /dev/null +++ b/user/src/bin/adder_mutex_blocking.rs @@ -0,0 +1,59 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; +extern crate alloc; + +use alloc::vec::Vec; +use user_lib::{exit, get_time, thread_create, waittid}; +use user_lib::{mutex_blocking_create, mutex_lock, mutex_unlock}; + +static mut A: usize = 0; +const PER_THREAD_DEFAULT: usize = 10000; +const THREAD_COUNT_DEFAULT: usize = 16; +static mut PER_THREAD: usize = 0; + +unsafe fn critical_section(t: &mut usize) { + let a = &mut A as *mut usize; + let cur = a.read_volatile(); + for _ in 0..500 { + *t = (*t) * (*t) % 10007; + } + a.write_volatile(cur + 1); +} +unsafe fn f() -> ! { + let mut t = 2usize; + for _ in 0..PER_THREAD { + mutex_lock(0); + critical_section(&mut t); + mutex_unlock(0); + } + exit(t as i32) +} + +#[no_mangle] +pub fn main(argc: usize, argv: &[&str]) -> i32 { + let mut thread_count = THREAD_COUNT_DEFAULT; + let mut per_thread = PER_THREAD_DEFAULT; + if argc >= 2 { + thread_count = argv[1].parse().unwrap(); + if argc >= 3 { + per_thread = argv[2].parse().unwrap(); + } + } + unsafe { PER_THREAD = per_thread; } + + let start = get_time(); + assert_eq!(mutex_blocking_create(), 0); + let mut v = Vec::new(); + for _ in 0..thread_count { + v.push(thread_create(f as usize, 0) as usize); + } + for tid in v.into_iter() { + waittid(tid); + } + println!("time cost is {}ms", get_time() - start); + assert_eq!(unsafe { A }, unsafe { PER_THREAD } * thread_count); + 0 +} diff --git a/user/src/bin/adder_mutex_spin.rs b/user/src/bin/adder_mutex_spin.rs new file mode 100644 index 0000000..b96f933 --- /dev/null +++ b/user/src/bin/adder_mutex_spin.rs @@ -0,0 +1,60 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; +extern crate alloc; + +use alloc::vec::Vec; +use user_lib::{exit, get_time, thread_create, waittid}; +use user_lib::{mutex_create, mutex_lock, mutex_unlock}; + +static mut A: usize = 0; +const PER_THREAD_DEFAULT: usize = 10000; +const THREAD_COUNT_DEFAULT: usize = 16; +static mut PER_THREAD: usize = 0; + +unsafe fn critical_section(t: &mut usize) { + let a = &mut A as *mut usize; + let cur = a.read_volatile(); + for _ in 0..500 { + *t = (*t) * (*t) % 10007; + } + a.write_volatile(cur + 1); +} + +unsafe fn f() -> ! { + let mut t = 2usize; + for _ in 0..PER_THREAD { + mutex_lock(0); + critical_section(&mut t); + mutex_unlock(0); + } + exit(t as i32) +} + +#[no_mangle] +pub fn main(argc: usize, argv: &[&str]) -> i32 { + let mut thread_count = THREAD_COUNT_DEFAULT; + let mut per_thread = PER_THREAD_DEFAULT; + if argc >= 2 { + thread_count = argv[1].parse().unwrap(); + if argc >= 3 { + per_thread = argv[2].parse().unwrap(); + } + } + unsafe { PER_THREAD = per_thread; } + + let start = get_time(); + assert_eq!(mutex_create(), 0); + let mut v = Vec::new(); + for _ in 0..thread_count { + v.push(thread_create(f as usize, 0) as usize); + } + for tid in v.into_iter() { + waittid(tid); + } + println!("time cost is {}ms", get_time() - start); + assert_eq!(unsafe { A }, unsafe { PER_THREAD } * thread_count); + 0 +} diff --git a/user/src/bin/adder_peterson_spin.rs b/user/src/bin/adder_peterson_spin.rs new file mode 100644 index 0000000..bba1f23 --- /dev/null +++ b/user/src/bin/adder_peterson_spin.rs @@ -0,0 +1,90 @@ +//! It only works on a single CPU! + +#![no_std] +#![no_main] +#![feature(core_intrinsics)] + +#[macro_use] +extern crate user_lib; +extern crate alloc; + +use alloc::vec::Vec; +use user_lib::{exit, get_time, thread_create, waittid}; +use core::sync::atomic::{compiler_fence, Ordering}; + +static mut A: usize = 0; +static mut FLAG: [bool; 2] = [false; 2]; +static mut TURN: usize = 0; +const PER_THREAD_DEFAULT: usize = 2000; +const THREAD_COUNT_DEFAULT: usize = 2; +static mut PER_THREAD: usize = 0; + +unsafe fn critical_section(t: &mut usize) { + let a = &mut A as *mut usize; + let cur = a.read_volatile(); + for _ in 0..500 { + *t = (*t) * (*t) % 10007; + } + a.write_volatile(cur + 1); +} + +unsafe fn lock(id: usize) { + FLAG[id] = true; + let j = 1 - id; + TURN = j; + // Tell the compiler not to reorder memory operations + // across this fence. + compiler_fence(Ordering::SeqCst); + // Why do we need to use volatile_read here? + // Otherwise the compiler will assume that they will never + // be changed on this thread. Thus, they will be accessed + // only once! + while vload!(&FLAG[j]) && vload!(&TURN) == j {} +} + +unsafe fn unlock(id: usize) { + FLAG[id] = false; +} + +unsafe fn f(id: usize) -> ! { + let mut t = 2usize; + for _iter in 0..PER_THREAD { + lock(id); + critical_section(&mut t); + unlock(id); + } + exit(t as i32) +} + +#[no_mangle] +pub fn main(argc: usize, argv: &[&str]) -> i32 { + let mut thread_count = THREAD_COUNT_DEFAULT; + let mut per_thread = PER_THREAD_DEFAULT; + if argc >= 2 { + thread_count = argv[1].parse().unwrap(); + if argc >= 3 { + per_thread = argv[2].parse().unwrap(); + } + } + unsafe { PER_THREAD = per_thread; } + + // uncomment this if you want to check the assembly + // println!( + // "addr: lock={:#x}, unlock={:#x}", + // lock as usize, + // unlock as usize + // ); + let start = get_time(); + let mut v = Vec::new(); + assert_eq!(thread_count, 2, "Peterson works when there are only 2 threads."); + for id in 0..thread_count { + v.push(thread_create(f as usize, id) as usize); + } + let mut time_cost = Vec::new(); + for tid in v.iter() { + time_cost.push(waittid(*tid)); + } + println!("time cost is {}ms", get_time() - start); + assert_eq!(unsafe { A }, unsafe { PER_THREAD } * thread_count); + 0 +} diff --git a/user/src/bin/adder_peterson_yield.rs b/user/src/bin/adder_peterson_yield.rs new file mode 100644 index 0000000..fc5ff18 --- /dev/null +++ b/user/src/bin/adder_peterson_yield.rs @@ -0,0 +1,89 @@ +//! It only works on a single CPU! + +#![no_std] +#![no_main] +#![feature(core_intrinsics)] + +#[macro_use] +extern crate user_lib; +extern crate alloc; + +use alloc::vec::Vec; +use user_lib::{exit, get_time, thread_create, waittid, yield_}; +use core::sync::atomic::{compiler_fence, Ordering}; + +static mut A: usize = 0; +static mut FLAG: [bool; 2] = [false; 2]; +static mut TURN: usize = 0; +const PER_THREAD_DEFAULT: usize = 2000; +const THREAD_COUNT_DEFAULT: usize = 2; +static mut PER_THREAD: usize = 0; + +unsafe fn critical_section(t: &mut usize) { + let a = &mut A as *mut usize; + let cur = a.read_volatile(); + for _ in 0..500 { + *t = (*t) * (*t) % 10007; + } + a.write_volatile(cur + 1); +} + +unsafe fn lock(id: usize) { + FLAG[id] = true; + let j = 1 - id; + TURN = j; + // Tell the compiler not to reorder memory operations + // across this fence. + compiler_fence(Ordering::SeqCst); + while FLAG[j] && TURN == j { + yield_(); + } +} + +unsafe fn unlock(id: usize) { + FLAG[id] = false; +} + +unsafe fn f(id: usize) -> ! { + let mut t = 2usize; + for _iter in 0..PER_THREAD { + lock(id); + critical_section(&mut t); + unlock(id); + } + exit(t as i32) +} + +#[no_mangle] +pub fn main(argc: usize, argv: &[&str]) -> i32 { + let mut thread_count = THREAD_COUNT_DEFAULT; + let mut per_thread = PER_THREAD_DEFAULT; + if argc >= 2 { + thread_count = argv[1].parse().unwrap(); + if argc >= 3 { + per_thread = argv[2].parse().unwrap(); + } + } + unsafe { PER_THREAD = per_thread; } + + // uncomment this if you want to check the assembly + // println!( + // "addr: lock={:#x}, unlock={:#x}", + // lock as usize, + // unlock as usize + // ); + + let start = get_time(); + let mut v = Vec::new(); + assert_eq!(thread_count, 2, "Peterson works when there are only 2 threads."); + for id in 0..thread_count { + v.push(thread_create(f as usize, id) as usize); + } + let mut time_cost = Vec::new(); + for tid in v.iter() { + time_cost.push(waittid(*tid)); + } + println!("time cost is {}ms", get_time() - start); + assert_eq!(unsafe { A }, unsafe { PER_THREAD } * thread_count); + 0 +} diff --git a/user/src/bin/adder_simple_spin.rs b/user/src/bin/adder_simple_spin.rs new file mode 100644 index 0000000..d950eca --- /dev/null +++ b/user/src/bin/adder_simple_spin.rs @@ -0,0 +1,68 @@ +#![no_std] +#![no_main] +#![feature(core_intrinsics)] + +#[macro_use] +extern crate user_lib; +extern crate alloc; + +use alloc::vec::Vec; +use user_lib::{exit, get_time, thread_create, waittid}; + +static mut A: usize = 0; +static mut OCCUPIED: bool = false; +const PER_THREAD_DEFAULT: usize = 10000; +const THREAD_COUNT_DEFAULT: usize = 16; +static mut PER_THREAD: usize = 0; + +unsafe fn critical_section(t: &mut usize) { + let a = &mut A as *mut usize; + let cur = a.read_volatile(); + for _ in 0..500 { + *t = (*t) * (*t) % 10007; + } + a.write_volatile(cur + 1); +} + +unsafe fn lock() { + while vload!(&OCCUPIED) {} + OCCUPIED = true; +} + +unsafe fn unlock() { + OCCUPIED = false; +} + +unsafe fn f() -> ! { + let mut t = 2usize; + for _ in 0..PER_THREAD { + lock(); + critical_section(&mut t); + unlock(); + } + exit(t as i32) +} + +#[no_mangle] +pub fn main(argc: usize, argv: &[&str]) -> i32 { + let mut thread_count = THREAD_COUNT_DEFAULT; + let mut per_thread = PER_THREAD_DEFAULT; + if argc >= 2 { + thread_count = argv[1].parse().unwrap(); + if argc >= 3 { + per_thread = argv[2].parse().unwrap(); + } + } + unsafe { PER_THREAD = per_thread; } + let start = get_time(); + let mut v = Vec::new(); + for _ in 0..thread_count { + v.push(thread_create(f as usize, 0) as usize); + } + for tid in v.into_iter() { + waittid(tid); + } + println!("time cost is {}ms", get_time() - start); + assert_eq!(unsafe { A }, unsafe { PER_THREAD } * thread_count); + 0 +} diff --git a/user/src/bin/adder_simple_yield.rs b/user/src/bin/adder_simple_yield.rs new file mode 100644 index 0000000..1c77777 --- /dev/null +++ b/user/src/bin/adder_simple_yield.rs @@ -0,0 +1,70 @@ +#![no_std] +#![no_main] +#![feature(core_intrinsics)] + +#[macro_use] +extern crate user_lib; +extern crate alloc; + +use alloc::vec::Vec; +use user_lib::{exit, get_time, thread_create, waittid, yield_}; + +static mut A: usize = 0; +static mut OCCUPIED: bool = false; +const PER_THREAD_DEFAULT: usize = 10000; +const THREAD_COUNT_DEFAULT: usize = 16; +static mut PER_THREAD: usize = 0; + +unsafe fn critical_section(t: &mut usize) { + let a = &mut A as *mut usize; + let cur = a.read_volatile(); + for _ in 0..500 { + *t = (*t) * (*t) % 10007; + } + a.write_volatile(cur + 1); +} + +unsafe fn lock() { + while OCCUPIED { + yield_(); + } + OCCUPIED = true; +} + +unsafe fn unlock() { + OCCUPIED = false; +} + +unsafe fn f() -> ! { + let mut t = 2usize; + for _ in 0..PER_THREAD { + lock(); + critical_section(&mut t); + unlock(); + } + exit(t as i32) +} + +#[no_mangle] +pub fn main(argc: usize, argv: &[&str]) -> i32 { + let mut thread_count = THREAD_COUNT_DEFAULT; + let mut per_thread = PER_THREAD_DEFAULT; + if argc >= 2 { + thread_count = argv[1].parse().unwrap(); + if argc >= 3 { + per_thread = argv[2].parse().unwrap(); + } + } + unsafe { PER_THREAD = per_thread; } + let start = get_time(); + let mut v = Vec::new(); + for _ in 0..thread_count { + v.push(thread_create(f as usize, 0) as usize); + } + for tid in v.into_iter() { + waittid(tid); + } + println!("time cost is {}ms", get_time() - start); + assert_eq!(unsafe { A }, unsafe { PER_THREAD } * thread_count); + 0 +} diff --git a/user/src/bin/peterson.rs b/user/src/bin/peterson.rs index 089841d..1fa2c41 100644 --- a/user/src/bin/peterson.rs +++ b/user/src/bin/peterson.rs @@ -10,7 +10,7 @@ extern crate core; use alloc::vec::Vec; use core::sync::atomic::{AtomicUsize, Ordering}; use user_lib::{exit, sleep, thread_create, waittid}; -const N: usize = 3; +const N: usize = 1000; static mut TURN: usize = 0; static mut FLAG: [bool; 2] = [false; 2]; @@ -29,27 +29,30 @@ fn critical_test_exit() { } fn peterson_enter_critical(id: usize, peer_id: usize) { - println!("Thread[{}] try enter", id); + // println!("Thread[{}] try enter", id); vstore!(&FLAG[id], true); vstore!(&TURN, peer_id); memory_fence!(); while vload!(&FLAG[peer_id]) && vload!(&TURN) == peer_id { - println!("Thread[{}] enter fail", id); + // println!("Thread[{}] enter fail", id); sleep(1); - println!("Thread[{}] retry enter", id); + // println!("Thread[{}] retry enter", id); } - println!("Thread[{}] enter", id); + // println!("Thread[{}] enter", id); } fn peterson_exit_critical(id: usize) { vstore!(&FLAG[id], false); - println!("Thread[{}] exit", id); + // println!("Thread[{}] exit", id); } pub fn thread_fn(id: usize) -> ! { - println!("Thread[{}] init.", id); + // println!("Thread[{}] init.", id); let peer_id: usize = id ^ 1; - for _ in 0..N { + for iter in 0..N { + if iter % 10 == 0 { + println!("[{}] it={}", id, iter); + } peterson_enter_critical(id, peer_id); critical_test_enter(); for _ in 0..3 { @@ -74,4 +77,4 @@ pub fn main() -> i32 { } println!("main thread exited."); 0 -} +} \ No newline at end of file diff --git a/user/src/bin/race_adder.rs b/user/src/bin/race_adder.rs deleted file mode 100644 index c7b6747..0000000 --- a/user/src/bin/race_adder.rs +++ /dev/null @@ -1,42 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; -extern crate alloc; - -use alloc::vec::Vec; -use user_lib::{exit, get_time, thread_create, waittid}; - -static mut A: usize = 0; -const PER_THREAD: usize = 1000; -const THREAD_COUNT: usize = 16; - -unsafe fn f() -> ! { - let mut t = 2usize; - for _ in 0..PER_THREAD { - let a = &mut A as *mut usize; - let cur = a.read_volatile(); - for _ in 0..500 { - t = t * t % 10007; - } - a.write_volatile(cur + 1); - } - exit(t as i32) -} - -#[no_mangle] -pub fn main() -> i32 { - let start = get_time(); - let mut v = Vec::new(); - for _ in 0..THREAD_COUNT { - v.push(thread_create(f as usize, 0) as usize); - } - let mut time_cost = Vec::new(); - for tid in v.iter() { - time_cost.push(waittid(*tid)); - } - println!("time cost is {}ms", get_time() - start); - assert_eq!(unsafe { A }, PER_THREAD * THREAD_COUNT); - 0 -} diff --git a/user/src/bin/race_adder_atomic.rs b/user/src/bin/race_adder_atomic.rs deleted file mode 100644 index 2feaed0..0000000 --- a/user/src/bin/race_adder_atomic.rs +++ /dev/null @@ -1,51 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; -extern crate alloc; - -use alloc::vec::Vec; -use core::sync::atomic::{AtomicBool, Ordering}; -use user_lib::{exit, get_time, thread_create, waittid, yield_}; - -static mut A: usize = 0; -static OCCUPIED: AtomicBool = AtomicBool::new(false); -const PER_THREAD: usize = 1000; -const THREAD_COUNT: usize = 16; - -unsafe fn f() -> ! { - let mut t = 2usize; - for _ in 0..PER_THREAD { - while OCCUPIED - .compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed) - .is_err() - { - yield_(); - } - let a = &mut A as *mut usize; - let cur = a.read_volatile(); - for _ in 0..500 { - t = t * t % 10007; - } - a.write_volatile(cur + 1); - OCCUPIED.store(false, Ordering::Relaxed); - } - exit(t as i32) -} - -#[no_mangle] -pub fn main() -> i32 { - let start = get_time(); - let mut v = Vec::new(); - for _ in 0..THREAD_COUNT { - v.push(thread_create(f as usize, 0) as usize); - } - let mut time_cost = Vec::new(); - for tid in v.iter() { - time_cost.push(waittid(*tid)); - } - println!("time cost is {}ms", get_time() - start); - assert_eq!(unsafe { A }, PER_THREAD * THREAD_COUNT); - 0 -} diff --git a/user/src/bin/race_adder_loop.rs b/user/src/bin/race_adder_loop.rs deleted file mode 100644 index 0e4fe83..0000000 --- a/user/src/bin/race_adder_loop.rs +++ /dev/null @@ -1,51 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; -extern crate alloc; - -use alloc::vec::Vec; -use user_lib::{exit, get_time, thread_create, waittid, yield_}; - -static mut A: usize = 0; -static mut OCCUPIED: bool = false; -const PER_THREAD: usize = 1000; -const THREAD_COUNT: usize = 16; - -unsafe fn f() -> ! { - let mut t = 2usize; - for _ in 0..PER_THREAD { - while OCCUPIED { - yield_(); - } - OCCUPIED = true; - // enter critical section - let a = &mut A as *mut usize; - let cur = a.read_volatile(); - for _ in 0..500 { - t = t * t % 10007; - } - a.write_volatile(cur + 1); - // exit critical section - OCCUPIED = false; - } - - exit(t as i32) -} - -#[no_mangle] -pub fn main() -> i32 { - let start = get_time(); - let mut v = Vec::new(); - for _ in 0..THREAD_COUNT { - v.push(thread_create(f as usize, 0) as usize); - } - let mut time_cost = Vec::new(); - for tid in v.iter() { - time_cost.push(waittid(*tid)); - } - println!("time cost is {}ms", get_time() - start); - assert_eq!(unsafe { A }, PER_THREAD * THREAD_COUNT); - 0 -} diff --git a/user/src/bin/race_adder_mutex_blocking.rs b/user/src/bin/race_adder_mutex_blocking.rs deleted file mode 100644 index e5affc4..0000000 --- a/user/src/bin/race_adder_mutex_blocking.rs +++ /dev/null @@ -1,46 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; -extern crate alloc; - -use alloc::vec::Vec; -use user_lib::{exit, get_time, thread_create, waittid}; -use user_lib::{mutex_blocking_create, mutex_lock, mutex_unlock}; - -static mut A: usize = 0; -const PER_THREAD: usize = 1000; -const THREAD_COUNT: usize = 16; - -unsafe fn f() -> ! { - let mut t = 2usize; - for _ in 0..PER_THREAD { - mutex_lock(0); - let a = &mut A as *mut usize; - let cur = a.read_volatile(); - for _ in 0..500 { - t = t * t % 10007; - } - a.write_volatile(cur + 1); - mutex_unlock(0); - } - exit(t as i32) -} - -#[no_mangle] -pub fn main() -> i32 { - let start = get_time(); - assert_eq!(mutex_blocking_create(), 0); - let mut v = Vec::new(); - for _ in 0..THREAD_COUNT { - v.push(thread_create(f as usize, 0) as usize); - } - let mut time_cost = Vec::new(); - for tid in v.iter() { - time_cost.push(waittid(*tid)); - } - println!("time cost is {}ms", get_time() - start); - assert_eq!(unsafe { A }, PER_THREAD * THREAD_COUNT); - 0 -} diff --git a/user/src/bin/race_adder_mutex_spin.rs b/user/src/bin/race_adder_mutex_spin.rs deleted file mode 100644 index ed3bcec..0000000 --- a/user/src/bin/race_adder_mutex_spin.rs +++ /dev/null @@ -1,46 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; -extern crate alloc; - -use alloc::vec::Vec; -use user_lib::{exit, get_time, thread_create, waittid}; -use user_lib::{mutex_create, mutex_lock, mutex_unlock}; - -static mut A: usize = 0; -const PER_THREAD: usize = 1000; -const THREAD_COUNT: usize = 16; - -unsafe fn f() -> ! { - let mut t = 2usize; - for _ in 0..PER_THREAD { - mutex_lock(0); - let a = &mut A as *mut usize; - let cur = a.read_volatile(); - for _ in 0..500 { - t = t * t % 10007; - } - a.write_volatile(cur + 1); - mutex_unlock(0); - } - exit(t as i32) -} - -#[no_mangle] -pub fn main() -> i32 { - let start = get_time(); - assert_eq!(mutex_create(), 0); - let mut v = Vec::new(); - for _ in 0..THREAD_COUNT { - v.push(thread_create(f as usize, 0) as usize); - } - let mut time_cost = Vec::new(); - for tid in v.iter() { - time_cost.push(waittid(*tid)); - } - println!("time cost is {}ms", get_time() - start); - assert_eq!(unsafe { A }, PER_THREAD * THREAD_COUNT); - 0 -} diff --git a/user/src/bin/usertests.rs b/user/src/bin/usertests.rs index eb706fd..a631314 100644 --- a/user/src/bin/usertests.rs +++ b/user/src/bin/usertests.rs @@ -27,10 +27,10 @@ static SUCC_TESTS: &[(&str, &str, &str, &str, i32)] = &[ ("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), + ("adder_peterson_spin\0", "\0", "\0", "\0", 0), + ("adder_peterson_yield\0", "\0", "\0", "\0", 0), + ("adder_mutex_blocking\0", "\0", "\0", "\0", 0), + ("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), @@ -49,8 +49,9 @@ static FAIL_TESTS: &[(&str, &str, &str, &str, i32)] = &[ ("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), + ("adder\0", "\0", "\0", "\0", -6), + ("adder_simple_spin\0", "\0", "\0", "\0", -6), + ("adder_simple_yield\0", "\0", "\0", "\0", -6), ]; use user_lib::{exec, fork, waitpid}; From fe2f776fe8b9f5dc549daefa5115d67c80bc375b Mon Sep 17 00:00:00 2001 From: Yifan Wu Date: Fri, 13 Jan 2023 09:59:46 +0800 Subject: [PATCH 43/68] updates from ch8 --- user/src/bin/adder.rs | 55 ++++++++++++++ user/src/bin/adder_atomic.rs | 72 ++++++++++++++++++ user/src/bin/adder_mutex_blocking.rs | 59 +++++++++++++++ user/src/bin/adder_mutex_spin.rs | 60 +++++++++++++++ user/src/bin/adder_peterson_spin.rs | 90 +++++++++++++++++++++++ user/src/bin/adder_peterson_yield.rs | 89 ++++++++++++++++++++++ user/src/bin/adder_simple_spin.rs | 68 +++++++++++++++++ user/src/bin/adder_simple_yield.rs | 70 ++++++++++++++++++ user/src/bin/peterson.rs | 21 +++--- user/src/bin/race_adder.rs | 42 ----------- user/src/bin/race_adder_atomic.rs | 51 ------------- user/src/bin/race_adder_loop.rs | 51 ------------- user/src/bin/race_adder_mutex_blocking.rs | 46 ------------ user/src/bin/race_adder_mutex_spin.rs | 46 ------------ user/src/bin/usertests.rs | 13 ++-- 15 files changed, 582 insertions(+), 251 deletions(-) create mode 100644 user/src/bin/adder.rs create mode 100644 user/src/bin/adder_atomic.rs create mode 100644 user/src/bin/adder_mutex_blocking.rs create mode 100644 user/src/bin/adder_mutex_spin.rs create mode 100644 user/src/bin/adder_peterson_spin.rs create mode 100644 user/src/bin/adder_peterson_yield.rs create mode 100644 user/src/bin/adder_simple_spin.rs create mode 100644 user/src/bin/adder_simple_yield.rs delete mode 100644 user/src/bin/race_adder.rs delete mode 100644 user/src/bin/race_adder_atomic.rs delete mode 100644 user/src/bin/race_adder_loop.rs delete mode 100644 user/src/bin/race_adder_mutex_blocking.rs delete mode 100644 user/src/bin/race_adder_mutex_spin.rs diff --git a/user/src/bin/adder.rs b/user/src/bin/adder.rs new file mode 100644 index 0000000..e7b1611 --- /dev/null +++ b/user/src/bin/adder.rs @@ -0,0 +1,55 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; +extern crate alloc; + +use alloc::vec::Vec; +use user_lib::{exit, get_time, thread_create, waittid}; + +static mut A: usize = 0; +const PER_THREAD_DEFAULT: usize = 10000; +const THREAD_COUNT_DEFAULT: usize = 16; +static mut PER_THREAD: usize = 0; + +unsafe fn critical_section(t: &mut usize) { + let a = &mut A as *mut usize; + let cur = a.read_volatile(); + for _ in 0..500 { + *t = (*t) * (*t) % 10007; + } + a.write_volatile(cur + 1); +} + +unsafe fn f() -> ! { + let mut t = 2usize; + for _ in 0..PER_THREAD { + critical_section(&mut t); + } + exit(t as i32) +} + +#[no_mangle] +pub fn main(argc: usize, argv: &[&str]) -> i32 { + let mut thread_count = THREAD_COUNT_DEFAULT; + let mut per_thread = PER_THREAD_DEFAULT; + if argc >= 2 { + thread_count = argv[1].parse().unwrap(); + if argc >= 3 { + per_thread = argv[2].parse().unwrap(); + } + } + unsafe { PER_THREAD = per_thread; } + let start = get_time(); + let mut v = Vec::new(); + for _ in 0..thread_count { + v.push(thread_create(f as usize, 0) as usize); + } + for tid in v.into_iter() { + waittid(tid); + } + println!("time cost is {}ms", get_time() - start); + assert_eq!(unsafe { A }, unsafe { PER_THREAD } * thread_count); + 0 +} diff --git a/user/src/bin/adder_atomic.rs b/user/src/bin/adder_atomic.rs new file mode 100644 index 0000000..fe2cdb1 --- /dev/null +++ b/user/src/bin/adder_atomic.rs @@ -0,0 +1,72 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; +extern crate alloc; + +use alloc::vec::Vec; +use core::sync::atomic::{AtomicBool, Ordering}; +use user_lib::{exit, get_time, thread_create, waittid, yield_}; + +static mut A: usize = 0; +static OCCUPIED: AtomicBool = AtomicBool::new(false); +const PER_THREAD_DEFAULT: usize = 10000; +const THREAD_COUNT_DEFAULT: usize = 16; +static mut PER_THREAD: usize = 0; + +unsafe fn critical_section(t: &mut usize) { + let a = &mut A as *mut usize; + let cur = a.read_volatile(); + for _ in 0..500 { + *t = (*t) * (*t) % 10007; + } + a.write_volatile(cur + 1); +} + +fn lock() { + while OCCUPIED + .compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed) + .is_err() + { + yield_(); + } +} + +fn unlock() { + OCCUPIED.store(false, Ordering::Relaxed); +} + +unsafe fn f() -> ! { + let mut t = 2usize; + for _ in 0..PER_THREAD { + lock(); + critical_section(&mut t); + unlock(); + } + exit(t as i32) +} + +#[no_mangle] +pub fn main(argc: usize, argv: &[&str]) -> i32 { + let mut thread_count = THREAD_COUNT_DEFAULT; + let mut per_thread = PER_THREAD_DEFAULT; + if argc >= 2 { + thread_count = argv[1].parse().unwrap(); + if argc >= 3 { + per_thread = argv[2].parse().unwrap(); + } + } + unsafe { PER_THREAD = per_thread; } + let start = get_time(); + let mut v = Vec::new(); + for _ in 0..thread_count { + v.push(thread_create(f as usize, 0) as usize); + } + for tid in v.into_iter() { + waittid(tid); + } + println!("time cost is {}ms", get_time() - start); + assert_eq!(unsafe { A }, unsafe { PER_THREAD } * thread_count); + 0 +} diff --git a/user/src/bin/adder_mutex_blocking.rs b/user/src/bin/adder_mutex_blocking.rs new file mode 100644 index 0000000..963dd75 --- /dev/null +++ b/user/src/bin/adder_mutex_blocking.rs @@ -0,0 +1,59 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; +extern crate alloc; + +use alloc::vec::Vec; +use user_lib::{exit, get_time, thread_create, waittid}; +use user_lib::{mutex_blocking_create, mutex_lock, mutex_unlock}; + +static mut A: usize = 0; +const PER_THREAD_DEFAULT: usize = 10000; +const THREAD_COUNT_DEFAULT: usize = 16; +static mut PER_THREAD: usize = 0; + +unsafe fn critical_section(t: &mut usize) { + let a = &mut A as *mut usize; + let cur = a.read_volatile(); + for _ in 0..500 { + *t = (*t) * (*t) % 10007; + } + a.write_volatile(cur + 1); +} +unsafe fn f() -> ! { + let mut t = 2usize; + for _ in 0..PER_THREAD { + mutex_lock(0); + critical_section(&mut t); + mutex_unlock(0); + } + exit(t as i32) +} + +#[no_mangle] +pub fn main(argc: usize, argv: &[&str]) -> i32 { + let mut thread_count = THREAD_COUNT_DEFAULT; + let mut per_thread = PER_THREAD_DEFAULT; + if argc >= 2 { + thread_count = argv[1].parse().unwrap(); + if argc >= 3 { + per_thread = argv[2].parse().unwrap(); + } + } + unsafe { PER_THREAD = per_thread; } + + let start = get_time(); + assert_eq!(mutex_blocking_create(), 0); + let mut v = Vec::new(); + for _ in 0..thread_count { + v.push(thread_create(f as usize, 0) as usize); + } + for tid in v.into_iter() { + waittid(tid); + } + println!("time cost is {}ms", get_time() - start); + assert_eq!(unsafe { A }, unsafe { PER_THREAD } * thread_count); + 0 +} diff --git a/user/src/bin/adder_mutex_spin.rs b/user/src/bin/adder_mutex_spin.rs new file mode 100644 index 0000000..b96f933 --- /dev/null +++ b/user/src/bin/adder_mutex_spin.rs @@ -0,0 +1,60 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; +extern crate alloc; + +use alloc::vec::Vec; +use user_lib::{exit, get_time, thread_create, waittid}; +use user_lib::{mutex_create, mutex_lock, mutex_unlock}; + +static mut A: usize = 0; +const PER_THREAD_DEFAULT: usize = 10000; +const THREAD_COUNT_DEFAULT: usize = 16; +static mut PER_THREAD: usize = 0; + +unsafe fn critical_section(t: &mut usize) { + let a = &mut A as *mut usize; + let cur = a.read_volatile(); + for _ in 0..500 { + *t = (*t) * (*t) % 10007; + } + a.write_volatile(cur + 1); +} + +unsafe fn f() -> ! { + let mut t = 2usize; + for _ in 0..PER_THREAD { + mutex_lock(0); + critical_section(&mut t); + mutex_unlock(0); + } + exit(t as i32) +} + +#[no_mangle] +pub fn main(argc: usize, argv: &[&str]) -> i32 { + let mut thread_count = THREAD_COUNT_DEFAULT; + let mut per_thread = PER_THREAD_DEFAULT; + if argc >= 2 { + thread_count = argv[1].parse().unwrap(); + if argc >= 3 { + per_thread = argv[2].parse().unwrap(); + } + } + unsafe { PER_THREAD = per_thread; } + + let start = get_time(); + assert_eq!(mutex_create(), 0); + let mut v = Vec::new(); + for _ in 0..thread_count { + v.push(thread_create(f as usize, 0) as usize); + } + for tid in v.into_iter() { + waittid(tid); + } + println!("time cost is {}ms", get_time() - start); + assert_eq!(unsafe { A }, unsafe { PER_THREAD } * thread_count); + 0 +} diff --git a/user/src/bin/adder_peterson_spin.rs b/user/src/bin/adder_peterson_spin.rs new file mode 100644 index 0000000..bba1f23 --- /dev/null +++ b/user/src/bin/adder_peterson_spin.rs @@ -0,0 +1,90 @@ +//! It only works on a single CPU! + +#![no_std] +#![no_main] +#![feature(core_intrinsics)] + +#[macro_use] +extern crate user_lib; +extern crate alloc; + +use alloc::vec::Vec; +use user_lib::{exit, get_time, thread_create, waittid}; +use core::sync::atomic::{compiler_fence, Ordering}; + +static mut A: usize = 0; +static mut FLAG: [bool; 2] = [false; 2]; +static mut TURN: usize = 0; +const PER_THREAD_DEFAULT: usize = 2000; +const THREAD_COUNT_DEFAULT: usize = 2; +static mut PER_THREAD: usize = 0; + +unsafe fn critical_section(t: &mut usize) { + let a = &mut A as *mut usize; + let cur = a.read_volatile(); + for _ in 0..500 { + *t = (*t) * (*t) % 10007; + } + a.write_volatile(cur + 1); +} + +unsafe fn lock(id: usize) { + FLAG[id] = true; + let j = 1 - id; + TURN = j; + // Tell the compiler not to reorder memory operations + // across this fence. + compiler_fence(Ordering::SeqCst); + // Why do we need to use volatile_read here? + // Otherwise the compiler will assume that they will never + // be changed on this thread. Thus, they will be accessed + // only once! + while vload!(&FLAG[j]) && vload!(&TURN) == j {} +} + +unsafe fn unlock(id: usize) { + FLAG[id] = false; +} + +unsafe fn f(id: usize) -> ! { + let mut t = 2usize; + for _iter in 0..PER_THREAD { + lock(id); + critical_section(&mut t); + unlock(id); + } + exit(t as i32) +} + +#[no_mangle] +pub fn main(argc: usize, argv: &[&str]) -> i32 { + let mut thread_count = THREAD_COUNT_DEFAULT; + let mut per_thread = PER_THREAD_DEFAULT; + if argc >= 2 { + thread_count = argv[1].parse().unwrap(); + if argc >= 3 { + per_thread = argv[2].parse().unwrap(); + } + } + unsafe { PER_THREAD = per_thread; } + + // uncomment this if you want to check the assembly + // println!( + // "addr: lock={:#x}, unlock={:#x}", + // lock as usize, + // unlock as usize + // ); + let start = get_time(); + let mut v = Vec::new(); + assert_eq!(thread_count, 2, "Peterson works when there are only 2 threads."); + for id in 0..thread_count { + v.push(thread_create(f as usize, id) as usize); + } + let mut time_cost = Vec::new(); + for tid in v.iter() { + time_cost.push(waittid(*tid)); + } + println!("time cost is {}ms", get_time() - start); + assert_eq!(unsafe { A }, unsafe { PER_THREAD } * thread_count); + 0 +} diff --git a/user/src/bin/adder_peterson_yield.rs b/user/src/bin/adder_peterson_yield.rs new file mode 100644 index 0000000..fc5ff18 --- /dev/null +++ b/user/src/bin/adder_peterson_yield.rs @@ -0,0 +1,89 @@ +//! It only works on a single CPU! + +#![no_std] +#![no_main] +#![feature(core_intrinsics)] + +#[macro_use] +extern crate user_lib; +extern crate alloc; + +use alloc::vec::Vec; +use user_lib::{exit, get_time, thread_create, waittid, yield_}; +use core::sync::atomic::{compiler_fence, Ordering}; + +static mut A: usize = 0; +static mut FLAG: [bool; 2] = [false; 2]; +static mut TURN: usize = 0; +const PER_THREAD_DEFAULT: usize = 2000; +const THREAD_COUNT_DEFAULT: usize = 2; +static mut PER_THREAD: usize = 0; + +unsafe fn critical_section(t: &mut usize) { + let a = &mut A as *mut usize; + let cur = a.read_volatile(); + for _ in 0..500 { + *t = (*t) * (*t) % 10007; + } + a.write_volatile(cur + 1); +} + +unsafe fn lock(id: usize) { + FLAG[id] = true; + let j = 1 - id; + TURN = j; + // Tell the compiler not to reorder memory operations + // across this fence. + compiler_fence(Ordering::SeqCst); + while FLAG[j] && TURN == j { + yield_(); + } +} + +unsafe fn unlock(id: usize) { + FLAG[id] = false; +} + +unsafe fn f(id: usize) -> ! { + let mut t = 2usize; + for _iter in 0..PER_THREAD { + lock(id); + critical_section(&mut t); + unlock(id); + } + exit(t as i32) +} + +#[no_mangle] +pub fn main(argc: usize, argv: &[&str]) -> i32 { + let mut thread_count = THREAD_COUNT_DEFAULT; + let mut per_thread = PER_THREAD_DEFAULT; + if argc >= 2 { + thread_count = argv[1].parse().unwrap(); + if argc >= 3 { + per_thread = argv[2].parse().unwrap(); + } + } + unsafe { PER_THREAD = per_thread; } + + // uncomment this if you want to check the assembly + // println!( + // "addr: lock={:#x}, unlock={:#x}", + // lock as usize, + // unlock as usize + // ); + + let start = get_time(); + let mut v = Vec::new(); + assert_eq!(thread_count, 2, "Peterson works when there are only 2 threads."); + for id in 0..thread_count { + v.push(thread_create(f as usize, id) as usize); + } + let mut time_cost = Vec::new(); + for tid in v.iter() { + time_cost.push(waittid(*tid)); + } + println!("time cost is {}ms", get_time() - start); + assert_eq!(unsafe { A }, unsafe { PER_THREAD } * thread_count); + 0 +} diff --git a/user/src/bin/adder_simple_spin.rs b/user/src/bin/adder_simple_spin.rs new file mode 100644 index 0000000..d950eca --- /dev/null +++ b/user/src/bin/adder_simple_spin.rs @@ -0,0 +1,68 @@ +#![no_std] +#![no_main] +#![feature(core_intrinsics)] + +#[macro_use] +extern crate user_lib; +extern crate alloc; + +use alloc::vec::Vec; +use user_lib::{exit, get_time, thread_create, waittid}; + +static mut A: usize = 0; +static mut OCCUPIED: bool = false; +const PER_THREAD_DEFAULT: usize = 10000; +const THREAD_COUNT_DEFAULT: usize = 16; +static mut PER_THREAD: usize = 0; + +unsafe fn critical_section(t: &mut usize) { + let a = &mut A as *mut usize; + let cur = a.read_volatile(); + for _ in 0..500 { + *t = (*t) * (*t) % 10007; + } + a.write_volatile(cur + 1); +} + +unsafe fn lock() { + while vload!(&OCCUPIED) {} + OCCUPIED = true; +} + +unsafe fn unlock() { + OCCUPIED = false; +} + +unsafe fn f() -> ! { + let mut t = 2usize; + for _ in 0..PER_THREAD { + lock(); + critical_section(&mut t); + unlock(); + } + exit(t as i32) +} + +#[no_mangle] +pub fn main(argc: usize, argv: &[&str]) -> i32 { + let mut thread_count = THREAD_COUNT_DEFAULT; + let mut per_thread = PER_THREAD_DEFAULT; + if argc >= 2 { + thread_count = argv[1].parse().unwrap(); + if argc >= 3 { + per_thread = argv[2].parse().unwrap(); + } + } + unsafe { PER_THREAD = per_thread; } + let start = get_time(); + let mut v = Vec::new(); + for _ in 0..thread_count { + v.push(thread_create(f as usize, 0) as usize); + } + for tid in v.into_iter() { + waittid(tid); + } + println!("time cost is {}ms", get_time() - start); + assert_eq!(unsafe { A }, unsafe { PER_THREAD } * thread_count); + 0 +} diff --git a/user/src/bin/adder_simple_yield.rs b/user/src/bin/adder_simple_yield.rs new file mode 100644 index 0000000..1c77777 --- /dev/null +++ b/user/src/bin/adder_simple_yield.rs @@ -0,0 +1,70 @@ +#![no_std] +#![no_main] +#![feature(core_intrinsics)] + +#[macro_use] +extern crate user_lib; +extern crate alloc; + +use alloc::vec::Vec; +use user_lib::{exit, get_time, thread_create, waittid, yield_}; + +static mut A: usize = 0; +static mut OCCUPIED: bool = false; +const PER_THREAD_DEFAULT: usize = 10000; +const THREAD_COUNT_DEFAULT: usize = 16; +static mut PER_THREAD: usize = 0; + +unsafe fn critical_section(t: &mut usize) { + let a = &mut A as *mut usize; + let cur = a.read_volatile(); + for _ in 0..500 { + *t = (*t) * (*t) % 10007; + } + a.write_volatile(cur + 1); +} + +unsafe fn lock() { + while OCCUPIED { + yield_(); + } + OCCUPIED = true; +} + +unsafe fn unlock() { + OCCUPIED = false; +} + +unsafe fn f() -> ! { + let mut t = 2usize; + for _ in 0..PER_THREAD { + lock(); + critical_section(&mut t); + unlock(); + } + exit(t as i32) +} + +#[no_mangle] +pub fn main(argc: usize, argv: &[&str]) -> i32 { + let mut thread_count = THREAD_COUNT_DEFAULT; + let mut per_thread = PER_THREAD_DEFAULT; + if argc >= 2 { + thread_count = argv[1].parse().unwrap(); + if argc >= 3 { + per_thread = argv[2].parse().unwrap(); + } + } + unsafe { PER_THREAD = per_thread; } + let start = get_time(); + let mut v = Vec::new(); + for _ in 0..thread_count { + v.push(thread_create(f as usize, 0) as usize); + } + for tid in v.into_iter() { + waittid(tid); + } + println!("time cost is {}ms", get_time() - start); + assert_eq!(unsafe { A }, unsafe { PER_THREAD } * thread_count); + 0 +} diff --git a/user/src/bin/peterson.rs b/user/src/bin/peterson.rs index 089841d..1fa2c41 100644 --- a/user/src/bin/peterson.rs +++ b/user/src/bin/peterson.rs @@ -10,7 +10,7 @@ extern crate core; use alloc::vec::Vec; use core::sync::atomic::{AtomicUsize, Ordering}; use user_lib::{exit, sleep, thread_create, waittid}; -const N: usize = 3; +const N: usize = 1000; static mut TURN: usize = 0; static mut FLAG: [bool; 2] = [false; 2]; @@ -29,27 +29,30 @@ fn critical_test_exit() { } fn peterson_enter_critical(id: usize, peer_id: usize) { - println!("Thread[{}] try enter", id); + // println!("Thread[{}] try enter", id); vstore!(&FLAG[id], true); vstore!(&TURN, peer_id); memory_fence!(); while vload!(&FLAG[peer_id]) && vload!(&TURN) == peer_id { - println!("Thread[{}] enter fail", id); + // println!("Thread[{}] enter fail", id); sleep(1); - println!("Thread[{}] retry enter", id); + // println!("Thread[{}] retry enter", id); } - println!("Thread[{}] enter", id); + // println!("Thread[{}] enter", id); } fn peterson_exit_critical(id: usize) { vstore!(&FLAG[id], false); - println!("Thread[{}] exit", id); + // println!("Thread[{}] exit", id); } pub fn thread_fn(id: usize) -> ! { - println!("Thread[{}] init.", id); + // println!("Thread[{}] init.", id); let peer_id: usize = id ^ 1; - for _ in 0..N { + for iter in 0..N { + if iter % 10 == 0 { + println!("[{}] it={}", id, iter); + } peterson_enter_critical(id, peer_id); critical_test_enter(); for _ in 0..3 { @@ -74,4 +77,4 @@ pub fn main() -> i32 { } println!("main thread exited."); 0 -} +} \ No newline at end of file diff --git a/user/src/bin/race_adder.rs b/user/src/bin/race_adder.rs deleted file mode 100644 index c7b6747..0000000 --- a/user/src/bin/race_adder.rs +++ /dev/null @@ -1,42 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; -extern crate alloc; - -use alloc::vec::Vec; -use user_lib::{exit, get_time, thread_create, waittid}; - -static mut A: usize = 0; -const PER_THREAD: usize = 1000; -const THREAD_COUNT: usize = 16; - -unsafe fn f() -> ! { - let mut t = 2usize; - for _ in 0..PER_THREAD { - let a = &mut A as *mut usize; - let cur = a.read_volatile(); - for _ in 0..500 { - t = t * t % 10007; - } - a.write_volatile(cur + 1); - } - exit(t as i32) -} - -#[no_mangle] -pub fn main() -> i32 { - let start = get_time(); - let mut v = Vec::new(); - for _ in 0..THREAD_COUNT { - v.push(thread_create(f as usize, 0) as usize); - } - let mut time_cost = Vec::new(); - for tid in v.iter() { - time_cost.push(waittid(*tid)); - } - println!("time cost is {}ms", get_time() - start); - assert_eq!(unsafe { A }, PER_THREAD * THREAD_COUNT); - 0 -} diff --git a/user/src/bin/race_adder_atomic.rs b/user/src/bin/race_adder_atomic.rs deleted file mode 100644 index 2feaed0..0000000 --- a/user/src/bin/race_adder_atomic.rs +++ /dev/null @@ -1,51 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; -extern crate alloc; - -use alloc::vec::Vec; -use core::sync::atomic::{AtomicBool, Ordering}; -use user_lib::{exit, get_time, thread_create, waittid, yield_}; - -static mut A: usize = 0; -static OCCUPIED: AtomicBool = AtomicBool::new(false); -const PER_THREAD: usize = 1000; -const THREAD_COUNT: usize = 16; - -unsafe fn f() -> ! { - let mut t = 2usize; - for _ in 0..PER_THREAD { - while OCCUPIED - .compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed) - .is_err() - { - yield_(); - } - let a = &mut A as *mut usize; - let cur = a.read_volatile(); - for _ in 0..500 { - t = t * t % 10007; - } - a.write_volatile(cur + 1); - OCCUPIED.store(false, Ordering::Relaxed); - } - exit(t as i32) -} - -#[no_mangle] -pub fn main() -> i32 { - let start = get_time(); - let mut v = Vec::new(); - for _ in 0..THREAD_COUNT { - v.push(thread_create(f as usize, 0) as usize); - } - let mut time_cost = Vec::new(); - for tid in v.iter() { - time_cost.push(waittid(*tid)); - } - println!("time cost is {}ms", get_time() - start); - assert_eq!(unsafe { A }, PER_THREAD * THREAD_COUNT); - 0 -} diff --git a/user/src/bin/race_adder_loop.rs b/user/src/bin/race_adder_loop.rs deleted file mode 100644 index 0e4fe83..0000000 --- a/user/src/bin/race_adder_loop.rs +++ /dev/null @@ -1,51 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; -extern crate alloc; - -use alloc::vec::Vec; -use user_lib::{exit, get_time, thread_create, waittid, yield_}; - -static mut A: usize = 0; -static mut OCCUPIED: bool = false; -const PER_THREAD: usize = 1000; -const THREAD_COUNT: usize = 16; - -unsafe fn f() -> ! { - let mut t = 2usize; - for _ in 0..PER_THREAD { - while OCCUPIED { - yield_(); - } - OCCUPIED = true; - // enter critical section - let a = &mut A as *mut usize; - let cur = a.read_volatile(); - for _ in 0..500 { - t = t * t % 10007; - } - a.write_volatile(cur + 1); - // exit critical section - OCCUPIED = false; - } - - exit(t as i32) -} - -#[no_mangle] -pub fn main() -> i32 { - let start = get_time(); - let mut v = Vec::new(); - for _ in 0..THREAD_COUNT { - v.push(thread_create(f as usize, 0) as usize); - } - let mut time_cost = Vec::new(); - for tid in v.iter() { - time_cost.push(waittid(*tid)); - } - println!("time cost is {}ms", get_time() - start); - assert_eq!(unsafe { A }, PER_THREAD * THREAD_COUNT); - 0 -} diff --git a/user/src/bin/race_adder_mutex_blocking.rs b/user/src/bin/race_adder_mutex_blocking.rs deleted file mode 100644 index e5affc4..0000000 --- a/user/src/bin/race_adder_mutex_blocking.rs +++ /dev/null @@ -1,46 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; -extern crate alloc; - -use alloc::vec::Vec; -use user_lib::{exit, get_time, thread_create, waittid}; -use user_lib::{mutex_blocking_create, mutex_lock, mutex_unlock}; - -static mut A: usize = 0; -const PER_THREAD: usize = 1000; -const THREAD_COUNT: usize = 16; - -unsafe fn f() -> ! { - let mut t = 2usize; - for _ in 0..PER_THREAD { - mutex_lock(0); - let a = &mut A as *mut usize; - let cur = a.read_volatile(); - for _ in 0..500 { - t = t * t % 10007; - } - a.write_volatile(cur + 1); - mutex_unlock(0); - } - exit(t as i32) -} - -#[no_mangle] -pub fn main() -> i32 { - let start = get_time(); - assert_eq!(mutex_blocking_create(), 0); - let mut v = Vec::new(); - for _ in 0..THREAD_COUNT { - v.push(thread_create(f as usize, 0) as usize); - } - let mut time_cost = Vec::new(); - for tid in v.iter() { - time_cost.push(waittid(*tid)); - } - println!("time cost is {}ms", get_time() - start); - assert_eq!(unsafe { A }, PER_THREAD * THREAD_COUNT); - 0 -} diff --git a/user/src/bin/race_adder_mutex_spin.rs b/user/src/bin/race_adder_mutex_spin.rs deleted file mode 100644 index ed3bcec..0000000 --- a/user/src/bin/race_adder_mutex_spin.rs +++ /dev/null @@ -1,46 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; -extern crate alloc; - -use alloc::vec::Vec; -use user_lib::{exit, get_time, thread_create, waittid}; -use user_lib::{mutex_create, mutex_lock, mutex_unlock}; - -static mut A: usize = 0; -const PER_THREAD: usize = 1000; -const THREAD_COUNT: usize = 16; - -unsafe fn f() -> ! { - let mut t = 2usize; - for _ in 0..PER_THREAD { - mutex_lock(0); - let a = &mut A as *mut usize; - let cur = a.read_volatile(); - for _ in 0..500 { - t = t * t % 10007; - } - a.write_volatile(cur + 1); - mutex_unlock(0); - } - exit(t as i32) -} - -#[no_mangle] -pub fn main() -> i32 { - let start = get_time(); - assert_eq!(mutex_create(), 0); - let mut v = Vec::new(); - for _ in 0..THREAD_COUNT { - v.push(thread_create(f as usize, 0) as usize); - } - let mut time_cost = Vec::new(); - for tid in v.iter() { - time_cost.push(waittid(*tid)); - } - println!("time cost is {}ms", get_time() - start); - assert_eq!(unsafe { A }, PER_THREAD * THREAD_COUNT); - 0 -} diff --git a/user/src/bin/usertests.rs b/user/src/bin/usertests.rs index eb706fd..a631314 100644 --- a/user/src/bin/usertests.rs +++ b/user/src/bin/usertests.rs @@ -27,10 +27,10 @@ static SUCC_TESTS: &[(&str, &str, &str, &str, i32)] = &[ ("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), + ("adder_peterson_spin\0", "\0", "\0", "\0", 0), + ("adder_peterson_yield\0", "\0", "\0", "\0", 0), + ("adder_mutex_blocking\0", "\0", "\0", "\0", 0), + ("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), @@ -49,8 +49,9 @@ static FAIL_TESTS: &[(&str, &str, &str, &str, i32)] = &[ ("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), + ("adder\0", "\0", "\0", "\0", -6), + ("adder_simple_spin\0", "\0", "\0", "\0", -6), + ("adder_simple_yield\0", "\0", "\0", "\0", -6), ]; use user_lib::{exec, fork, waitpid}; From 8326bf15165f7d612e2e38488ae3c338e36f8286 Mon Sep 17 00:00:00 2001 From: Yu Chen Date: Tue, 17 Jan 2023 13:28:31 +0800 Subject: [PATCH 44/68] update usr app gui_ret for more graph outputs --- user/src/bin/gui_rect.rs | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/user/src/bin/gui_rect.rs b/user/src/bin/gui_rect.rs index c8696be..a459dbc 100644 --- a/user/src/bin/gui_rect.rs +++ b/user/src/bin/gui_rect.rs @@ -1,18 +1,18 @@ #![no_std] #![no_main] -extern crate user_lib; extern crate alloc; +extern crate user_lib; -use user_lib::{VIRTGPU_XRES, VIRTGPU_YRES, Display}; +use user_lib::{Display, VIRTGPU_XRES, VIRTGPU_YRES}; use embedded_graphics::pixelcolor::Rgb888; use embedded_graphics::prelude::{DrawTarget, Drawable, Point, RgbColor, Size}; -use embedded_graphics::primitives::{Primitive, PrimitiveStyle, Rectangle}; +use embedded_graphics::primitives::{Circle, Primitive, PrimitiveStyle, Rectangle,Triangle}; -const INIT_X: i32 = 640; +const INIT_X: i32 = 80; const INIT_Y: i32 = 400; -const RECT_SIZE: u32 = 40; +const RECT_SIZE: u32 = 150; pub struct DrawingBoard { disp: Display, @@ -28,13 +28,21 @@ impl DrawingBoard { } fn paint(&mut self) { Rectangle::with_center(self.latest_pos, Size::new(RECT_SIZE, RECT_SIZE)) - .into_styled(PrimitiveStyle::with_stroke(Rgb888::WHITE, 1)) + .into_styled(PrimitiveStyle::with_stroke(Rgb888::RED, 10)) + .draw(&mut self.disp) + .ok(); + Circle::new(self.latest_pos + Point::new(-70, -300), 150) + .into_styled(PrimitiveStyle::with_fill(Rgb888::BLUE)) + .draw(&mut self.disp) + .ok(); + Triangle::new(self.latest_pos + Point::new(0, 150), self.latest_pos + Point::new(80, 200), self.latest_pos + Point::new(-120, 300)) + .into_styled(PrimitiveStyle::with_stroke(Rgb888::GREEN, 10)) .draw(&mut self.disp) .ok(); } fn unpaint(&mut self) { Rectangle::with_center(self.latest_pos, Size::new(RECT_SIZE, RECT_SIZE)) - .into_styled(PrimitiveStyle::with_stroke(Rgb888::BLACK, 1)) + .into_styled(PrimitiveStyle::with_stroke(Rgb888::BLACK, 10)) .draw(&mut self.disp) .ok(); } @@ -50,9 +58,9 @@ impl DrawingBoard { pub fn main() -> i32 { let mut board = DrawingBoard::new(); let _ = board.disp.clear(Rgb888::BLACK).unwrap(); - for i in 0..20 { - board.latest_pos.x += i; - board.latest_pos.y += i; + for i in 0..5 { + board.latest_pos.x += (RECT_SIZE as i32 + 20); + //board.latest_pos.y += i; board.paint(); } 0 From 274a7c0eb27a315e93bec77854f3ea176c097cb6 Mon Sep 17 00:00:00 2001 From: Yifan Wu Date: Thu, 19 Jan 2023 13:55:17 +0800 Subject: [PATCH 45/68] TaskStatus::Blocking->Blocked --- os/src/task/mod.rs | 2 +- os/src/task/task.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/os/src/task/mod.rs b/os/src/task/mod.rs index 97e76bd..9ed25ae 100644 --- a/os/src/task/mod.rs +++ b/os/src/task/mod.rs @@ -48,7 +48,7 @@ pub fn suspend_current_and_run_next() { pub fn block_current_task() -> *mut TaskContext { let task = take_current_task().unwrap(); let mut task_inner = task.inner_exclusive_access(); - task_inner.task_status = TaskStatus::Blocking; + task_inner.task_status = TaskStatus::Blocked; &mut task_inner.task_cx as *mut TaskContext } diff --git a/os/src/task/task.rs b/os/src/task/task.rs index c620890..ffc5c0e 100644 --- a/os/src/task/task.rs +++ b/os/src/task/task.rs @@ -76,5 +76,5 @@ impl TaskControlBlock { pub enum TaskStatus { Ready, Running, - Blocking, + Blocked, } From 4ccf22f581d3f10ba77384bdf78a42858f1df609 Mon Sep 17 00:00:00 2001 From: Yifan Wu Date: Thu, 19 Jan 2023 13:59:06 +0800 Subject: [PATCH 46/68] TaskStatus::Blocking->Blocked --- os/src/task/mod.rs | 2 +- os/src/task/task.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/os/src/task/mod.rs b/os/src/task/mod.rs index 97e76bd..9ed25ae 100644 --- a/os/src/task/mod.rs +++ b/os/src/task/mod.rs @@ -48,7 +48,7 @@ pub fn suspend_current_and_run_next() { pub fn block_current_task() -> *mut TaskContext { let task = take_current_task().unwrap(); let mut task_inner = task.inner_exclusive_access(); - task_inner.task_status = TaskStatus::Blocking; + task_inner.task_status = TaskStatus::Blocked; &mut task_inner.task_cx as *mut TaskContext } diff --git a/os/src/task/task.rs b/os/src/task/task.rs index c620890..ffc5c0e 100644 --- a/os/src/task/task.rs +++ b/os/src/task/task.rs @@ -76,5 +76,5 @@ impl TaskControlBlock { pub enum TaskStatus { Ready, Running, - Blocking, + Blocked, } From 24e40f3722b410a1f4e8f23daf8307d16c41bb98 Mon Sep 17 00:00:00 2001 From: Yifan Wu Date: Fri, 20 Jan 2023 01:54:13 +0800 Subject: [PATCH 47/68] add_task->wakeup_task --- os/src/sync/condvar.rs | 4 ++-- os/src/sync/mutex.rs | 4 ++-- os/src/sync/semaphore.rs | 4 ++-- os/src/task/manager.rs | 9 ++++++++- os/src/task/mod.rs | 2 +- os/src/timer.rs | 4 ++-- 6 files changed, 17 insertions(+), 10 deletions(-) diff --git a/os/src/sync/condvar.rs b/os/src/sync/condvar.rs index 714782c..b8ad07b 100644 --- a/os/src/sync/condvar.rs +++ b/os/src/sync/condvar.rs @@ -1,6 +1,6 @@ use crate::sync::{Mutex, UPIntrFreeCell}; use crate::task::{ - add_task, block_current_and_run_next, block_current_task, current_task, TaskContext, + wakeup_task, block_current_and_run_next, block_current_task, current_task, TaskContext, TaskControlBlock, }; use alloc::{collections::VecDeque, sync::Arc}; @@ -27,7 +27,7 @@ impl Condvar { pub fn signal(&self) { let mut inner = self.inner.exclusive_access(); if let Some(task) = inner.wait_queue.pop_front() { - add_task(task); + wakeup_task(task); } } diff --git a/os/src/sync/mutex.rs b/os/src/sync/mutex.rs index 463638b..2b2db10 100644 --- a/os/src/sync/mutex.rs +++ b/os/src/sync/mutex.rs @@ -1,6 +1,6 @@ use super::UPIntrFreeCell; use crate::task::TaskControlBlock; -use crate::task::{add_task, current_task}; +use crate::task::{wakeup_task, current_task}; use crate::task::{block_current_and_run_next, suspend_current_and_run_next}; use alloc::{collections::VecDeque, sync::Arc}; @@ -80,7 +80,7 @@ impl Mutex for MutexBlocking { let mut mutex_inner = self.inner.exclusive_access(); assert!(mutex_inner.locked); if let Some(waking_task) = mutex_inner.wait_queue.pop_front() { - add_task(waking_task); + wakeup_task(waking_task); } else { mutex_inner.locked = false; } diff --git a/os/src/sync/semaphore.rs b/os/src/sync/semaphore.rs index 354db29..cb62c20 100644 --- a/os/src/sync/semaphore.rs +++ b/os/src/sync/semaphore.rs @@ -1,5 +1,5 @@ use crate::sync::UPIntrFreeCell; -use crate::task::{add_task, block_current_and_run_next, current_task, TaskControlBlock}; +use crate::task::{wakeup_task, block_current_and_run_next, current_task, TaskControlBlock}; use alloc::{collections::VecDeque, sync::Arc}; pub struct Semaphore { @@ -28,7 +28,7 @@ impl Semaphore { inner.count += 1; if inner.count <= 0 { if let Some(task) = inner.wait_queue.pop_front() { - add_task(task); + wakeup_task(task); } } } diff --git a/os/src/task/manager.rs b/os/src/task/manager.rs index 168ba32..7672cf5 100644 --- a/os/src/task/manager.rs +++ b/os/src/task/manager.rs @@ -1,4 +1,4 @@ -use super::{ProcessControlBlock, TaskControlBlock}; +use super::{ProcessControlBlock, TaskControlBlock, TaskStatus}; use crate::sync::UPIntrFreeCell; use alloc::collections::{BTreeMap, VecDeque}; use alloc::sync::Arc; @@ -34,6 +34,13 @@ pub fn add_task(task: Arc) { TASK_MANAGER.exclusive_access().add(task); } +pub fn wakeup_task(task: Arc) { + let mut task_inner = task.inner_exclusive_access(); + task_inner.task_status = TaskStatus::Ready; + drop(task_inner); + add_task(task); +} + pub fn fetch_task() -> Option> { TASK_MANAGER.exclusive_access().fetch() } diff --git a/os/src/task/mod.rs b/os/src/task/mod.rs index 9ed25ae..c835480 100644 --- a/os/src/task/mod.rs +++ b/os/src/task/mod.rs @@ -18,7 +18,7 @@ use switch::__switch; pub use context::TaskContext; pub use id::{kstack_alloc, pid_alloc, KernelStack, PidHandle, IDLE_PID}; -pub use manager::{add_task, pid2process, remove_from_pid2process}; +pub use manager::{add_task, wakeup_task, pid2process, remove_from_pid2process}; pub use processor::{ current_kstack_top, current_process, current_task, current_trap_cx, current_trap_cx_user_va, current_user_token, run_tasks, schedule, take_current_task, diff --git a/os/src/timer.rs b/os/src/timer.rs index 7be2d01..83c969d 100644 --- a/os/src/timer.rs +++ b/os/src/timer.rs @@ -3,7 +3,7 @@ use core::cmp::Ordering; use crate::config::CLOCK_FREQ; use crate::sbi::set_timer; use crate::sync::UPIntrFreeCell; -use crate::task::{add_task, TaskControlBlock}; +use crate::task::{wakeup_task, TaskControlBlock}; use alloc::collections::BinaryHeap; use alloc::sync::Arc; use lazy_static::*; @@ -64,7 +64,7 @@ pub fn check_timer() { TIMERS.exclusive_session(|timers| { while let Some(timer) = timers.peek() { if timer.expire_ms <= current_ms { - add_task(Arc::clone(&timer.task)); + wakeup_task(Arc::clone(&timer.task)); timers.pop(); } else { break; From c12e3b733dde789a14eae9f7873281f8a2f2791f Mon Sep 17 00:00:00 2001 From: Yifan Wu Date: Fri, 20 Jan 2023 01:59:37 +0800 Subject: [PATCH 48/68] add_task->wakeup_task --- os/src/sync/condvar.rs | 4 ++-- os/src/sync/mutex.rs | 4 ++-- os/src/sync/semaphore.rs | 4 ++-- os/src/task/manager.rs | 9 ++++++++- os/src/task/mod.rs | 2 +- os/src/timer.rs | 4 ++-- 6 files changed, 17 insertions(+), 10 deletions(-) diff --git a/os/src/sync/condvar.rs b/os/src/sync/condvar.rs index 714782c..b8ad07b 100644 --- a/os/src/sync/condvar.rs +++ b/os/src/sync/condvar.rs @@ -1,6 +1,6 @@ use crate::sync::{Mutex, UPIntrFreeCell}; use crate::task::{ - add_task, block_current_and_run_next, block_current_task, current_task, TaskContext, + wakeup_task, block_current_and_run_next, block_current_task, current_task, TaskContext, TaskControlBlock, }; use alloc::{collections::VecDeque, sync::Arc}; @@ -27,7 +27,7 @@ impl Condvar { pub fn signal(&self) { let mut inner = self.inner.exclusive_access(); if let Some(task) = inner.wait_queue.pop_front() { - add_task(task); + wakeup_task(task); } } diff --git a/os/src/sync/mutex.rs b/os/src/sync/mutex.rs index 463638b..2b2db10 100644 --- a/os/src/sync/mutex.rs +++ b/os/src/sync/mutex.rs @@ -1,6 +1,6 @@ use super::UPIntrFreeCell; use crate::task::TaskControlBlock; -use crate::task::{add_task, current_task}; +use crate::task::{wakeup_task, current_task}; use crate::task::{block_current_and_run_next, suspend_current_and_run_next}; use alloc::{collections::VecDeque, sync::Arc}; @@ -80,7 +80,7 @@ impl Mutex for MutexBlocking { let mut mutex_inner = self.inner.exclusive_access(); assert!(mutex_inner.locked); if let Some(waking_task) = mutex_inner.wait_queue.pop_front() { - add_task(waking_task); + wakeup_task(waking_task); } else { mutex_inner.locked = false; } diff --git a/os/src/sync/semaphore.rs b/os/src/sync/semaphore.rs index 354db29..cb62c20 100644 --- a/os/src/sync/semaphore.rs +++ b/os/src/sync/semaphore.rs @@ -1,5 +1,5 @@ use crate::sync::UPIntrFreeCell; -use crate::task::{add_task, block_current_and_run_next, current_task, TaskControlBlock}; +use crate::task::{wakeup_task, block_current_and_run_next, current_task, TaskControlBlock}; use alloc::{collections::VecDeque, sync::Arc}; pub struct Semaphore { @@ -28,7 +28,7 @@ impl Semaphore { inner.count += 1; if inner.count <= 0 { if let Some(task) = inner.wait_queue.pop_front() { - add_task(task); + wakeup_task(task); } } } diff --git a/os/src/task/manager.rs b/os/src/task/manager.rs index 168ba32..7672cf5 100644 --- a/os/src/task/manager.rs +++ b/os/src/task/manager.rs @@ -1,4 +1,4 @@ -use super::{ProcessControlBlock, TaskControlBlock}; +use super::{ProcessControlBlock, TaskControlBlock, TaskStatus}; use crate::sync::UPIntrFreeCell; use alloc::collections::{BTreeMap, VecDeque}; use alloc::sync::Arc; @@ -34,6 +34,13 @@ pub fn add_task(task: Arc) { TASK_MANAGER.exclusive_access().add(task); } +pub fn wakeup_task(task: Arc) { + let mut task_inner = task.inner_exclusive_access(); + task_inner.task_status = TaskStatus::Ready; + drop(task_inner); + add_task(task); +} + pub fn fetch_task() -> Option> { TASK_MANAGER.exclusive_access().fetch() } diff --git a/os/src/task/mod.rs b/os/src/task/mod.rs index 9ed25ae..c835480 100644 --- a/os/src/task/mod.rs +++ b/os/src/task/mod.rs @@ -18,7 +18,7 @@ use switch::__switch; pub use context::TaskContext; pub use id::{kstack_alloc, pid_alloc, KernelStack, PidHandle, IDLE_PID}; -pub use manager::{add_task, pid2process, remove_from_pid2process}; +pub use manager::{add_task, wakeup_task, pid2process, remove_from_pid2process}; pub use processor::{ current_kstack_top, current_process, current_task, current_trap_cx, current_trap_cx_user_va, current_user_token, run_tasks, schedule, take_current_task, diff --git a/os/src/timer.rs b/os/src/timer.rs index 7be2d01..83c969d 100644 --- a/os/src/timer.rs +++ b/os/src/timer.rs @@ -3,7 +3,7 @@ use core::cmp::Ordering; use crate::config::CLOCK_FREQ; use crate::sbi::set_timer; use crate::sync::UPIntrFreeCell; -use crate::task::{add_task, TaskControlBlock}; +use crate::task::{wakeup_task, TaskControlBlock}; use alloc::collections::BinaryHeap; use alloc::sync::Arc; use lazy_static::*; @@ -64,7 +64,7 @@ pub fn check_timer() { TIMERS.exclusive_session(|timers| { while let Some(timer) = timers.peek() { if timer.expire_ms <= current_ms { - add_task(Arc::clone(&timer.task)); + wakeup_task(Arc::clone(&timer.task)); timers.pop(); } else { break; From 29ef0a52d539f72f1d76e46f2c7a5b442e1c2896 Mon Sep 17 00:00:00 2001 From: Yifan Wu Date: Wed, 25 Jan 2023 10:32:03 +0800 Subject: [PATCH 49/68] Added condvar examples. --- user/Cargo.toml | 1 + user/src/bin/barrier_condvar.rs | 72 +++++++++++++++++++++++++++++++++ user/src/bin/barrier_fail.rs | 33 +++++++++++++++ user/src/bin/usertests.rs | 2 + 4 files changed, 108 insertions(+) create mode 100644 user/src/bin/barrier_condvar.rs create mode 100644 user/src/bin/barrier_fail.rs diff --git a/user/Cargo.toml b/user/Cargo.toml index 7b1233e..d1816c6 100644 --- a/user/Cargo.toml +++ b/user/Cargo.toml @@ -10,6 +10,7 @@ edition = "2018" buddy_system_allocator = "0.6" bitflags = "1.2.1" riscv = { git = "https://github.com/rcore-os/riscv", features = ["inline-asm"] } +lazy_static = { version = "1.4.0", features = ["spin_no_std"] } embedded-graphics = "0.7.1" oorandom ="11" virtio-input-decoder = "0.1.4" diff --git a/user/src/bin/barrier_condvar.rs b/user/src/bin/barrier_condvar.rs new file mode 100644 index 0000000..db0a80b --- /dev/null +++ b/user/src/bin/barrier_condvar.rs @@ -0,0 +1,72 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; +extern crate alloc; + +use user_lib::{thread_create, exit, waittid, mutex_create, mutex_lock, mutex_unlock, condvar_create, condvar_signal, condvar_wait}; +use alloc::vec::Vec; +use core::cell::UnsafeCell; +use lazy_static::*; + +const THREAD_NUM: usize = 3; + +struct Barrier { + mutex_id: usize, + condvar_id: usize, + count: UnsafeCell, +} + +impl Barrier { + pub fn new() -> Self { + Self { + mutex_id: mutex_create() as usize, + condvar_id: condvar_create() as usize, + count: UnsafeCell::new(0), + } + } + pub fn block(&self) { + mutex_lock(self.mutex_id); + let mut count = self.count.get(); + // SAFETY: Here, the accesses of the count is in the + // critical section protected by the mutex. + unsafe { *count = *count + 1; } + if unsafe { *count } == THREAD_NUM { + condvar_signal(self.condvar_id); + } else { + condvar_wait(self.condvar_id, self.mutex_id); + condvar_signal(self.condvar_id); + } + mutex_unlock(self.mutex_id); + } +} + +unsafe impl Sync for Barrier {} + +lazy_static! { + static ref BARRIER_AB: Barrier = Barrier::new(); + static ref BARRIER_BC: Barrier = Barrier::new(); +} + +fn thread_fn() { + for _ in 0..300 { print!("a"); } + BARRIER_AB.block(); + for _ in 0..300 { print!("b"); } + BARRIER_BC.block(); + for _ in 0..300 { print!("c"); } + exit(0) +} + +#[no_mangle] +pub fn main() -> i32 { + let mut v: Vec = Vec::new(); + for _ in 0..THREAD_NUM { + v.push(thread_create(thread_fn as usize, 0)); + } + for tid in v.into_iter() { + waittid(tid as usize); + } + println!("\nOK!"); + 0 +} diff --git a/user/src/bin/barrier_fail.rs b/user/src/bin/barrier_fail.rs new file mode 100644 index 0000000..0eb4b17 --- /dev/null +++ b/user/src/bin/barrier_fail.rs @@ -0,0 +1,33 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; +extern crate alloc; + +use user_lib::{thread_create, exit, waittid}; +use alloc::vec::Vec; + +const THREAD_NUM: usize = 3; + +fn thread_fn() { + for ch in 'a'..='c' { + for _ in 0..300 { + print!("{}", ch); + } + } + exit(0) +} + +#[no_mangle] +pub fn main() -> i32 { + let mut v: Vec = Vec::new(); + for _ in 0..THREAD_NUM { + v.push(thread_create(thread_fn as usize, 0)); + } + for tid in v.into_iter() { + waittid(tid as usize); + } + println!("\nOK!"); + 0 +} diff --git a/user/src/bin/usertests.rs b/user/src/bin/usertests.rs index a631314..9ee0340 100644 --- a/user/src/bin/usertests.rs +++ b/user/src/bin/usertests.rs @@ -40,6 +40,8 @@ static SUCC_TESTS: &[(&str, &str, &str, &str, i32)] = &[ ("threads_arg\0", "\0", "\0", "\0", 0), ("threads\0", "\0", "\0", "\0", 0), ("yield\0", "\0", "\0", "\0", 0), + ("barrier_fail\0", "\0", "\0", "\0", 0), + ("barrier_condvar\0", "\0", "\0", "\0", 0), ]; static FAIL_TESTS: &[(&str, &str, &str, &str, i32)] = &[ From c0141d34d9b45429263cb4f8a8db0246cdd50b1a Mon Sep 17 00:00:00 2001 From: Yifan Wu Date: Wed, 25 Jan 2023 10:38:05 +0800 Subject: [PATCH 50/68] Added condvar examples. --- user/Cargo.toml | 1 + user/src/bin/barrier_condvar.rs | 72 +++++++++++++++++++++++++++++++++ user/src/bin/barrier_fail.rs | 33 +++++++++++++++ user/src/bin/usertests.rs | 2 + 4 files changed, 108 insertions(+) create mode 100644 user/src/bin/barrier_condvar.rs create mode 100644 user/src/bin/barrier_fail.rs diff --git a/user/Cargo.toml b/user/Cargo.toml index 7b1233e..d1816c6 100644 --- a/user/Cargo.toml +++ b/user/Cargo.toml @@ -10,6 +10,7 @@ edition = "2018" buddy_system_allocator = "0.6" bitflags = "1.2.1" riscv = { git = "https://github.com/rcore-os/riscv", features = ["inline-asm"] } +lazy_static = { version = "1.4.0", features = ["spin_no_std"] } embedded-graphics = "0.7.1" oorandom ="11" virtio-input-decoder = "0.1.4" diff --git a/user/src/bin/barrier_condvar.rs b/user/src/bin/barrier_condvar.rs new file mode 100644 index 0000000..db0a80b --- /dev/null +++ b/user/src/bin/barrier_condvar.rs @@ -0,0 +1,72 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; +extern crate alloc; + +use user_lib::{thread_create, exit, waittid, mutex_create, mutex_lock, mutex_unlock, condvar_create, condvar_signal, condvar_wait}; +use alloc::vec::Vec; +use core::cell::UnsafeCell; +use lazy_static::*; + +const THREAD_NUM: usize = 3; + +struct Barrier { + mutex_id: usize, + condvar_id: usize, + count: UnsafeCell, +} + +impl Barrier { + pub fn new() -> Self { + Self { + mutex_id: mutex_create() as usize, + condvar_id: condvar_create() as usize, + count: UnsafeCell::new(0), + } + } + pub fn block(&self) { + mutex_lock(self.mutex_id); + let mut count = self.count.get(); + // SAFETY: Here, the accesses of the count is in the + // critical section protected by the mutex. + unsafe { *count = *count + 1; } + if unsafe { *count } == THREAD_NUM { + condvar_signal(self.condvar_id); + } else { + condvar_wait(self.condvar_id, self.mutex_id); + condvar_signal(self.condvar_id); + } + mutex_unlock(self.mutex_id); + } +} + +unsafe impl Sync for Barrier {} + +lazy_static! { + static ref BARRIER_AB: Barrier = Barrier::new(); + static ref BARRIER_BC: Barrier = Barrier::new(); +} + +fn thread_fn() { + for _ in 0..300 { print!("a"); } + BARRIER_AB.block(); + for _ in 0..300 { print!("b"); } + BARRIER_BC.block(); + for _ in 0..300 { print!("c"); } + exit(0) +} + +#[no_mangle] +pub fn main() -> i32 { + let mut v: Vec = Vec::new(); + for _ in 0..THREAD_NUM { + v.push(thread_create(thread_fn as usize, 0)); + } + for tid in v.into_iter() { + waittid(tid as usize); + } + println!("\nOK!"); + 0 +} diff --git a/user/src/bin/barrier_fail.rs b/user/src/bin/barrier_fail.rs new file mode 100644 index 0000000..0eb4b17 --- /dev/null +++ b/user/src/bin/barrier_fail.rs @@ -0,0 +1,33 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; +extern crate alloc; + +use user_lib::{thread_create, exit, waittid}; +use alloc::vec::Vec; + +const THREAD_NUM: usize = 3; + +fn thread_fn() { + for ch in 'a'..='c' { + for _ in 0..300 { + print!("{}", ch); + } + } + exit(0) +} + +#[no_mangle] +pub fn main() -> i32 { + let mut v: Vec = Vec::new(); + for _ in 0..THREAD_NUM { + v.push(thread_create(thread_fn as usize, 0)); + } + for tid in v.into_iter() { + waittid(tid as usize); + } + println!("\nOK!"); + 0 +} diff --git a/user/src/bin/usertests.rs b/user/src/bin/usertests.rs index a631314..9ee0340 100644 --- a/user/src/bin/usertests.rs +++ b/user/src/bin/usertests.rs @@ -40,6 +40,8 @@ static SUCC_TESTS: &[(&str, &str, &str, &str, i32)] = &[ ("threads_arg\0", "\0", "\0", "\0", 0), ("threads\0", "\0", "\0", "\0", 0), ("yield\0", "\0", "\0", "\0", 0), + ("barrier_fail\0", "\0", "\0", "\0", 0), + ("barrier_condvar\0", "\0", "\0", "\0", 0), ]; static FAIL_TESTS: &[(&str, &str, &str, &str, i32)] = &[ From ffe22a57fb6ea701d8106a32a72ed498ec35b534 Mon Sep 17 00:00:00 2001 From: Yifan Wu Date: Fri, 27 Jan 2023 16:57:40 +0800 Subject: [PATCH 51/68] update mpsc_sem --- user/src/bin/mpsc_sem.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/user/src/bin/mpsc_sem.rs b/user/src/bin/mpsc_sem.rs index 7b92b9b..7b72bbb 100644 --- a/user/src/bin/mpsc_sem.rs +++ b/user/src/bin/mpsc_sem.rs @@ -14,7 +14,7 @@ use user_lib::{thread_create, waittid}; const SEM_MUTEX: usize = 0; const SEM_EMPTY: usize = 1; -const SEM_EXISTED: usize = 2; +const SEM_AVAIL: usize = 2; const BUFFER_SIZE: usize = 8; static mut BUFFER: [usize; BUFFER_SIZE] = [0; BUFFER_SIZE]; static mut FRONT: usize = 0; @@ -27,20 +27,20 @@ unsafe fn producer(id: *const usize) -> ! { for _ in 0..NUMBER_PER_PRODUCER { semaphore_down(SEM_EMPTY); semaphore_down(SEM_MUTEX); - BUFFER[FRONT] = id; - FRONT = (FRONT + 1) % BUFFER_SIZE; + BUFFER[TAIL] = id; + TAIL = (TAIL + 1) % BUFFER_SIZE; semaphore_up(SEM_MUTEX); - semaphore_up(SEM_EXISTED); + semaphore_up(SEM_AVAIL); } exit(0) } unsafe fn consumer() -> ! { for _ in 0..PRODUCER_COUNT * NUMBER_PER_PRODUCER { - semaphore_down(SEM_EXISTED); + semaphore_down(SEM_AVAIL); semaphore_down(SEM_MUTEX); - print!("{} ", BUFFER[TAIL]); - TAIL = (TAIL + 1) % BUFFER_SIZE; + print!("{} ", BUFFER[FRONT]); + FRONT = (FRONT + 1) % BUFFER_SIZE; semaphore_up(SEM_MUTEX); semaphore_up(SEM_EMPTY); } @@ -53,7 +53,7 @@ pub fn main() -> i32 { // create semaphores assert_eq!(semaphore_create(1) as usize, SEM_MUTEX); assert_eq!(semaphore_create(BUFFER_SIZE) as usize, SEM_EMPTY); - assert_eq!(semaphore_create(0) as usize, SEM_EXISTED); + assert_eq!(semaphore_create(0) as usize, SEM_AVAIL); // create threads let ids: Vec<_> = (0..PRODUCER_COUNT).collect(); let mut threads = Vec::new(); From b3d434d539289fe21de9139bef785e95e6660713 Mon Sep 17 00:00:00 2001 From: Yifan Wu Date: Fri, 27 Jan 2023 16:58:18 +0800 Subject: [PATCH 52/68] update mpsc_sem --- user/src/bin/mpsc_sem.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/user/src/bin/mpsc_sem.rs b/user/src/bin/mpsc_sem.rs index 7b92b9b..7b72bbb 100644 --- a/user/src/bin/mpsc_sem.rs +++ b/user/src/bin/mpsc_sem.rs @@ -14,7 +14,7 @@ use user_lib::{thread_create, waittid}; const SEM_MUTEX: usize = 0; const SEM_EMPTY: usize = 1; -const SEM_EXISTED: usize = 2; +const SEM_AVAIL: usize = 2; const BUFFER_SIZE: usize = 8; static mut BUFFER: [usize; BUFFER_SIZE] = [0; BUFFER_SIZE]; static mut FRONT: usize = 0; @@ -27,20 +27,20 @@ unsafe fn producer(id: *const usize) -> ! { for _ in 0..NUMBER_PER_PRODUCER { semaphore_down(SEM_EMPTY); semaphore_down(SEM_MUTEX); - BUFFER[FRONT] = id; - FRONT = (FRONT + 1) % BUFFER_SIZE; + BUFFER[TAIL] = id; + TAIL = (TAIL + 1) % BUFFER_SIZE; semaphore_up(SEM_MUTEX); - semaphore_up(SEM_EXISTED); + semaphore_up(SEM_AVAIL); } exit(0) } unsafe fn consumer() -> ! { for _ in 0..PRODUCER_COUNT * NUMBER_PER_PRODUCER { - semaphore_down(SEM_EXISTED); + semaphore_down(SEM_AVAIL); semaphore_down(SEM_MUTEX); - print!("{} ", BUFFER[TAIL]); - TAIL = (TAIL + 1) % BUFFER_SIZE; + print!("{} ", BUFFER[FRONT]); + FRONT = (FRONT + 1) % BUFFER_SIZE; semaphore_up(SEM_MUTEX); semaphore_up(SEM_EMPTY); } @@ -53,7 +53,7 @@ pub fn main() -> i32 { // create semaphores assert_eq!(semaphore_create(1) as usize, SEM_MUTEX); assert_eq!(semaphore_create(BUFFER_SIZE) as usize, SEM_EMPTY); - assert_eq!(semaphore_create(0) as usize, SEM_EXISTED); + assert_eq!(semaphore_create(0) as usize, SEM_AVAIL); // create threads let ids: Vec<_> = (0..PRODUCER_COUNT).collect(); let mut threads = Vec::new(); From 9d9d3f496b87cd3eaa0f489bc8004e547632c1db Mon Sep 17 00:00:00 2001 From: Yifan Wu Date: Wed, 1 Feb 2023 20:46:07 +0800 Subject: [PATCH 53/68] update condvar-related testcases. --- os/src/syscall/mod.rs | 2 +- os/src/syscall/sync.rs | 2 +- user/src/bin/barrier_condvar.rs | 2 +- .../{test_condvar.rs => condsync_condvar.rs} | 118 +++++++++--------- user/src/bin/condsync_sem.rs | 64 ++++++++++ user/src/sync.rs | 2 +- user/src/syscall.rs | 4 +- 7 files changed, 129 insertions(+), 65 deletions(-) rename user/src/bin/{test_condvar.rs => condsync_condvar.rs} (95%) create mode 100644 user/src/bin/condsync_sem.rs diff --git a/os/src/syscall/mod.rs b/os/src/syscall/mod.rs index d28073f..4052cf5 100644 --- a/os/src/syscall/mod.rs +++ b/os/src/syscall/mod.rs @@ -70,7 +70,7 @@ pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize { SYSCALL_SEMAPHORE_CREATE => sys_semaphore_create(args[0]), SYSCALL_SEMAPHORE_UP => sys_semaphore_up(args[0]), SYSCALL_SEMAPHORE_DOWN => sys_semaphore_down(args[0]), - SYSCALL_CONDVAR_CREATE => sys_condvar_create(args[0]), + SYSCALL_CONDVAR_CREATE => sys_condvar_create(), SYSCALL_CONDVAR_SIGNAL => sys_condvar_signal(args[0]), SYSCALL_CONDVAR_WAIT => sys_condvar_wait(args[0], args[1]), SYSCALL_FRAMEBUFFER => sys_framebuffer(), diff --git a/os/src/syscall/sync.rs b/os/src/syscall/sync.rs index e08f329..1180669 100644 --- a/os/src/syscall/sync.rs +++ b/os/src/syscall/sync.rs @@ -93,7 +93,7 @@ pub fn sys_semaphore_down(sem_id: usize) -> isize { 0 } -pub fn sys_condvar_create(_arg: usize) -> isize { +pub fn sys_condvar_create() -> isize { let process = current_process(); let mut process_inner = process.inner_exclusive_access(); let id = if let Some(id) = process_inner diff --git a/user/src/bin/barrier_condvar.rs b/user/src/bin/barrier_condvar.rs index db0a80b..ca0953b 100644 --- a/user/src/bin/barrier_condvar.rs +++ b/user/src/bin/barrier_condvar.rs @@ -28,7 +28,7 @@ impl Barrier { } pub fn block(&self) { mutex_lock(self.mutex_id); - let mut count = self.count.get(); + let count = self.count.get(); // SAFETY: Here, the accesses of the count is in the // critical section protected by the mutex. unsafe { *count = *count + 1; } diff --git a/user/src/bin/test_condvar.rs b/user/src/bin/condsync_condvar.rs similarity index 95% rename from user/src/bin/test_condvar.rs rename to user/src/bin/condsync_condvar.rs index 2db9d8a..78605ad 100644 --- a/user/src/bin/test_condvar.rs +++ b/user/src/bin/condsync_condvar.rs @@ -1,59 +1,59 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; - -extern crate alloc; - -use alloc::vec; -use user_lib::exit; -use user_lib::{ - condvar_create, condvar_signal, condvar_wait, mutex_blocking_create, mutex_lock, mutex_unlock, -}; -use user_lib::{sleep, thread_create, waittid}; - -static mut A: usize = 0; - -const CONDVAR_ID: usize = 0; -const MUTEX_ID: usize = 0; - -unsafe fn first() -> ! { - sleep(10); - println!("First work, Change A --> 1 and wakeup Second"); - mutex_lock(MUTEX_ID); - A = 1; - condvar_signal(CONDVAR_ID); - mutex_unlock(MUTEX_ID); - exit(0) -} - -unsafe fn second() -> ! { - println!("Second want to continue,but need to wait A=1"); - mutex_lock(MUTEX_ID); - while A == 0 { - println!("Second: A is {}", A); - condvar_wait(CONDVAR_ID, MUTEX_ID); - } - mutex_unlock(MUTEX_ID); - println!("A is {}, Second can work now", A); - exit(0) -} - -#[no_mangle] -pub fn main() -> i32 { - // create condvar & mutex - assert_eq!(condvar_create() as usize, CONDVAR_ID); - assert_eq!(mutex_blocking_create() as usize, MUTEX_ID); - // create threads - let threads = vec![ - thread_create(first as usize, 0), - thread_create(second as usize, 0), - ]; - // wait for all threads to complete - for thread in threads.iter() { - waittid(*thread as usize); - } - println!("test_condvar passed!"); - 0 -} +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +extern crate alloc; + +use alloc::vec; +use user_lib::exit; +use user_lib::{ + condvar_create, condvar_signal, condvar_wait, mutex_blocking_create, mutex_lock, mutex_unlock, +}; +use user_lib::{sleep, thread_create, waittid}; + +static mut A: usize = 0; + +const CONDVAR_ID: usize = 0; +const MUTEX_ID: usize = 0; + +unsafe fn first() -> ! { + sleep(10); + println!("First work, Change A --> 1 and wakeup Second"); + mutex_lock(MUTEX_ID); + A = 1; + condvar_signal(CONDVAR_ID); + mutex_unlock(MUTEX_ID); + exit(0) +} + +unsafe fn second() -> ! { + println!("Second want to continue,but need to wait A=1"); + mutex_lock(MUTEX_ID); + while A == 0 { + println!("Second: A is {}", A); + condvar_wait(CONDVAR_ID, MUTEX_ID); + } + println!("A is {}, Second can work now", A); + mutex_unlock(MUTEX_ID); + exit(0) +} + +#[no_mangle] +pub fn main() -> i32 { + // create condvar & mutex + assert_eq!(condvar_create() as usize, CONDVAR_ID); + assert_eq!(mutex_blocking_create() as usize, MUTEX_ID); + // create threads + let threads = vec![ + thread_create(first as usize, 0), + thread_create(second as usize, 0), + ]; + // wait for all threads to complete + for thread in threads.iter() { + waittid(*thread as usize); + } + println!("test_condvar passed!"); + 0 +} diff --git a/user/src/bin/condsync_sem.rs b/user/src/bin/condsync_sem.rs new file mode 100644 index 0000000..d7b875a --- /dev/null +++ b/user/src/bin/condsync_sem.rs @@ -0,0 +1,64 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +extern crate alloc; + +use alloc::vec; +use user_lib::exit; +use user_lib::{ + semaphore_create, semaphore_down, semaphore_up, mutex_blocking_create, mutex_lock, mutex_unlock, +}; +use user_lib::{sleep, thread_create, waittid}; + +static mut A: usize = 0; + +const SEM_ID: usize = 0; +const MUTEX_ID: usize = 0; + +unsafe fn first() -> ! { + sleep(10); + println!("First work, Change A --> 1 and wakeup Second"); + mutex_lock(MUTEX_ID); + A = 1; + semaphore_up(SEM_ID); + mutex_unlock(MUTEX_ID); + exit(0) +} + +unsafe fn second() -> ! { + println!("Second want to continue,but need to wait A=1"); + loop { + mutex_lock(MUTEX_ID); + if A == 0 { + println!("Second: A is {}", A); + mutex_unlock(MUTEX_ID); + semaphore_down(SEM_ID); + } else { + mutex_unlock(MUTEX_ID); + break; + } + } + println!("A is {}, Second can work now", A); + exit(0) +} + +#[no_mangle] +pub fn main() -> i32 { + // create semaphore & mutex + assert_eq!(semaphore_create(0) as usize, SEM_ID); + assert_eq!(mutex_blocking_create() as usize, MUTEX_ID); + // create threads + let threads = vec![ + thread_create(first as usize, 0), + thread_create(second as usize, 0), + ]; + // wait for all threads to complete + for thread in threads.iter() { + waittid(*thread as usize); + } + println!("test_condvar passed!"); + 0 +} diff --git a/user/src/sync.rs b/user/src/sync.rs index fbed4e3..c41e4d6 100644 --- a/user/src/sync.rs +++ b/user/src/sync.rs @@ -22,7 +22,7 @@ pub fn semaphore_down(sem_id: usize) { sys_semaphore_down(sem_id); } pub fn condvar_create() -> isize { - sys_condvar_create(0) + sys_condvar_create() } pub fn condvar_signal(condvar_id: usize) { sys_condvar_signal(condvar_id); diff --git a/user/src/syscall.rs b/user/src/syscall.rs index 530ea20..87885f5 100644 --- a/user/src/syscall.rs +++ b/user/src/syscall.rs @@ -147,8 +147,8 @@ pub fn sys_semaphore_down(sem_id: usize) -> isize { syscall(SYSCALL_SEMAPHORE_DOWN, [sem_id, 0, 0]) } -pub fn sys_condvar_create(_arg: usize) -> isize { - syscall(SYSCALL_CONDVAR_CREATE, [_arg, 0, 0]) +pub fn sys_condvar_create() -> isize { + syscall(SYSCALL_CONDVAR_CREATE, [0, 0, 0]) } pub fn sys_condvar_signal(condvar_id: usize) -> isize { From bc80eda2a4f856344b64257c3502fc01ec34079f Mon Sep 17 00:00:00 2001 From: Yifan Wu Date: Wed, 1 Feb 2023 20:50:53 +0800 Subject: [PATCH 54/68] update condvar-related testcases. --- os/src/syscall/mod.rs | 2 +- os/src/syscall/sync.rs | 2 +- user/src/bin/barrier_condvar.rs | 2 +- .../{test_condvar.rs => condsync_condvar.rs} | 118 +++++++++--------- user/src/bin/condsync_sem.rs | 64 ++++++++++ user/src/sync.rs | 2 +- user/src/syscall.rs | 4 +- 7 files changed, 129 insertions(+), 65 deletions(-) rename user/src/bin/{test_condvar.rs => condsync_condvar.rs} (95%) create mode 100644 user/src/bin/condsync_sem.rs diff --git a/os/src/syscall/mod.rs b/os/src/syscall/mod.rs index d28073f..4052cf5 100644 --- a/os/src/syscall/mod.rs +++ b/os/src/syscall/mod.rs @@ -70,7 +70,7 @@ pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize { SYSCALL_SEMAPHORE_CREATE => sys_semaphore_create(args[0]), SYSCALL_SEMAPHORE_UP => sys_semaphore_up(args[0]), SYSCALL_SEMAPHORE_DOWN => sys_semaphore_down(args[0]), - SYSCALL_CONDVAR_CREATE => sys_condvar_create(args[0]), + SYSCALL_CONDVAR_CREATE => sys_condvar_create(), SYSCALL_CONDVAR_SIGNAL => sys_condvar_signal(args[0]), SYSCALL_CONDVAR_WAIT => sys_condvar_wait(args[0], args[1]), SYSCALL_FRAMEBUFFER => sys_framebuffer(), diff --git a/os/src/syscall/sync.rs b/os/src/syscall/sync.rs index e08f329..1180669 100644 --- a/os/src/syscall/sync.rs +++ b/os/src/syscall/sync.rs @@ -93,7 +93,7 @@ pub fn sys_semaphore_down(sem_id: usize) -> isize { 0 } -pub fn sys_condvar_create(_arg: usize) -> isize { +pub fn sys_condvar_create() -> isize { let process = current_process(); let mut process_inner = process.inner_exclusive_access(); let id = if let Some(id) = process_inner diff --git a/user/src/bin/barrier_condvar.rs b/user/src/bin/barrier_condvar.rs index db0a80b..ca0953b 100644 --- a/user/src/bin/barrier_condvar.rs +++ b/user/src/bin/barrier_condvar.rs @@ -28,7 +28,7 @@ impl Barrier { } pub fn block(&self) { mutex_lock(self.mutex_id); - let mut count = self.count.get(); + let count = self.count.get(); // SAFETY: Here, the accesses of the count is in the // critical section protected by the mutex. unsafe { *count = *count + 1; } diff --git a/user/src/bin/test_condvar.rs b/user/src/bin/condsync_condvar.rs similarity index 95% rename from user/src/bin/test_condvar.rs rename to user/src/bin/condsync_condvar.rs index 2db9d8a..78605ad 100644 --- a/user/src/bin/test_condvar.rs +++ b/user/src/bin/condsync_condvar.rs @@ -1,59 +1,59 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; - -extern crate alloc; - -use alloc::vec; -use user_lib::exit; -use user_lib::{ - condvar_create, condvar_signal, condvar_wait, mutex_blocking_create, mutex_lock, mutex_unlock, -}; -use user_lib::{sleep, thread_create, waittid}; - -static mut A: usize = 0; - -const CONDVAR_ID: usize = 0; -const MUTEX_ID: usize = 0; - -unsafe fn first() -> ! { - sleep(10); - println!("First work, Change A --> 1 and wakeup Second"); - mutex_lock(MUTEX_ID); - A = 1; - condvar_signal(CONDVAR_ID); - mutex_unlock(MUTEX_ID); - exit(0) -} - -unsafe fn second() -> ! { - println!("Second want to continue,but need to wait A=1"); - mutex_lock(MUTEX_ID); - while A == 0 { - println!("Second: A is {}", A); - condvar_wait(CONDVAR_ID, MUTEX_ID); - } - mutex_unlock(MUTEX_ID); - println!("A is {}, Second can work now", A); - exit(0) -} - -#[no_mangle] -pub fn main() -> i32 { - // create condvar & mutex - assert_eq!(condvar_create() as usize, CONDVAR_ID); - assert_eq!(mutex_blocking_create() as usize, MUTEX_ID); - // create threads - let threads = vec![ - thread_create(first as usize, 0), - thread_create(second as usize, 0), - ]; - // wait for all threads to complete - for thread in threads.iter() { - waittid(*thread as usize); - } - println!("test_condvar passed!"); - 0 -} +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +extern crate alloc; + +use alloc::vec; +use user_lib::exit; +use user_lib::{ + condvar_create, condvar_signal, condvar_wait, mutex_blocking_create, mutex_lock, mutex_unlock, +}; +use user_lib::{sleep, thread_create, waittid}; + +static mut A: usize = 0; + +const CONDVAR_ID: usize = 0; +const MUTEX_ID: usize = 0; + +unsafe fn first() -> ! { + sleep(10); + println!("First work, Change A --> 1 and wakeup Second"); + mutex_lock(MUTEX_ID); + A = 1; + condvar_signal(CONDVAR_ID); + mutex_unlock(MUTEX_ID); + exit(0) +} + +unsafe fn second() -> ! { + println!("Second want to continue,but need to wait A=1"); + mutex_lock(MUTEX_ID); + while A == 0 { + println!("Second: A is {}", A); + condvar_wait(CONDVAR_ID, MUTEX_ID); + } + println!("A is {}, Second can work now", A); + mutex_unlock(MUTEX_ID); + exit(0) +} + +#[no_mangle] +pub fn main() -> i32 { + // create condvar & mutex + assert_eq!(condvar_create() as usize, CONDVAR_ID); + assert_eq!(mutex_blocking_create() as usize, MUTEX_ID); + // create threads + let threads = vec![ + thread_create(first as usize, 0), + thread_create(second as usize, 0), + ]; + // wait for all threads to complete + for thread in threads.iter() { + waittid(*thread as usize); + } + println!("test_condvar passed!"); + 0 +} diff --git a/user/src/bin/condsync_sem.rs b/user/src/bin/condsync_sem.rs new file mode 100644 index 0000000..d7b875a --- /dev/null +++ b/user/src/bin/condsync_sem.rs @@ -0,0 +1,64 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +extern crate alloc; + +use alloc::vec; +use user_lib::exit; +use user_lib::{ + semaphore_create, semaphore_down, semaphore_up, mutex_blocking_create, mutex_lock, mutex_unlock, +}; +use user_lib::{sleep, thread_create, waittid}; + +static mut A: usize = 0; + +const SEM_ID: usize = 0; +const MUTEX_ID: usize = 0; + +unsafe fn first() -> ! { + sleep(10); + println!("First work, Change A --> 1 and wakeup Second"); + mutex_lock(MUTEX_ID); + A = 1; + semaphore_up(SEM_ID); + mutex_unlock(MUTEX_ID); + exit(0) +} + +unsafe fn second() -> ! { + println!("Second want to continue,but need to wait A=1"); + loop { + mutex_lock(MUTEX_ID); + if A == 0 { + println!("Second: A is {}", A); + mutex_unlock(MUTEX_ID); + semaphore_down(SEM_ID); + } else { + mutex_unlock(MUTEX_ID); + break; + } + } + println!("A is {}, Second can work now", A); + exit(0) +} + +#[no_mangle] +pub fn main() -> i32 { + // create semaphore & mutex + assert_eq!(semaphore_create(0) as usize, SEM_ID); + assert_eq!(mutex_blocking_create() as usize, MUTEX_ID); + // create threads + let threads = vec![ + thread_create(first as usize, 0), + thread_create(second as usize, 0), + ]; + // wait for all threads to complete + for thread in threads.iter() { + waittid(*thread as usize); + } + println!("test_condvar passed!"); + 0 +} diff --git a/user/src/sync.rs b/user/src/sync.rs index fbed4e3..c41e4d6 100644 --- a/user/src/sync.rs +++ b/user/src/sync.rs @@ -22,7 +22,7 @@ pub fn semaphore_down(sem_id: usize) { sys_semaphore_down(sem_id); } pub fn condvar_create() -> isize { - sys_condvar_create(0) + sys_condvar_create() } pub fn condvar_signal(condvar_id: usize) { sys_condvar_signal(condvar_id); diff --git a/user/src/syscall.rs b/user/src/syscall.rs index 530ea20..87885f5 100644 --- a/user/src/syscall.rs +++ b/user/src/syscall.rs @@ -147,8 +147,8 @@ pub fn sys_semaphore_down(sem_id: usize) -> isize { syscall(SYSCALL_SEMAPHORE_DOWN, [sem_id, 0, 0]) } -pub fn sys_condvar_create(_arg: usize) -> isize { - syscall(SYSCALL_CONDVAR_CREATE, [_arg, 0, 0]) +pub fn sys_condvar_create() -> isize { + syscall(SYSCALL_CONDVAR_CREATE, [0, 0, 0]) } pub fn sys_condvar_signal(condvar_id: usize) -> isize { From 8cfd457341fa697f5292abfdf58f16c502d19532 Mon Sep 17 00:00:00 2001 From: Yifan Wu Date: Wed, 1 Feb 2023 21:00:34 +0800 Subject: [PATCH 55/68] update usertests --- user/src/bin/usertests.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/user/src/bin/usertests.rs b/user/src/bin/usertests.rs index 9ee0340..b522af2 100644 --- a/user/src/bin/usertests.rs +++ b/user/src/bin/usertests.rs @@ -36,7 +36,8 @@ static SUCC_TESTS: &[(&str, &str, &str, &str, i32)] = &[ ("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), + ("condsync_sem\0", "\0", "\0", "\0", 0), + ("condsync_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), From 642c2aa9a894e21ae330eeb47cdd3e5f98caef35 Mon Sep 17 00:00:00 2001 From: Yifan Wu Date: Wed, 1 Feb 2023 21:03:07 +0800 Subject: [PATCH 56/68] update usertests --- user/src/bin/usertests.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/user/src/bin/usertests.rs b/user/src/bin/usertests.rs index 9ee0340..b522af2 100644 --- a/user/src/bin/usertests.rs +++ b/user/src/bin/usertests.rs @@ -36,7 +36,8 @@ static SUCC_TESTS: &[(&str, &str, &str, &str, i32)] = &[ ("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), + ("condsync_sem\0", "\0", "\0", "\0", 0), + ("condsync_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), From 191eb13c21ceb00a020678a020fcbcf1de7a7ae5 Mon Sep 17 00:00:00 2001 From: Yifan Wu Date: Wed, 1 Feb 2023 21:17:43 +0800 Subject: [PATCH 57/68] Remove unnecessary output. --- easy-fs-fuse/src/main.rs | 6 +++--- user/Makefile | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/easy-fs-fuse/src/main.rs b/easy-fs-fuse/src/main.rs index 17b2465..bb9ff76 100644 --- a/easy-fs-fuse/src/main.rs +++ b/easy-fs-fuse/src/main.rs @@ -85,9 +85,9 @@ fn easy_fs_pack() -> std::io::Result<()> { inode.write_at(0, all_data.as_slice()); } // list apps - for app in root_inode.ls() { - println!("{}", app); - } + // for app in root_inode.ls() { + // println!("{}", app); + // } Ok(()) } diff --git a/user/Makefile b/user/Makefile index c09b5e9..5170327 100644 --- a/user/Makefile +++ b/user/Makefile @@ -19,7 +19,7 @@ ifeq ($(TEST), 1) endif binary: elf - $(foreach elf, $(ELFS), $(OBJCOPY) $(elf) --strip-all -O binary $(patsubst $(TARGET_DIR)/%, $(TARGET_DIR)/%.bin, $(elf));) + @$(foreach elf, $(ELFS), $(OBJCOPY) $(elf) --strip-all -O binary $(patsubst $(TARGET_DIR)/%, $(TARGET_DIR)/%.bin, $(elf));) build: binary From f358ece527b91b2401268c2afd768be02ebba4c2 Mon Sep 17 00:00:00 2001 From: Yifan Wu Date: Wed, 1 Feb 2023 21:18:27 +0800 Subject: [PATCH 58/68] Remove unnecessary output. --- easy-fs-fuse/src/main.rs | 6 +++--- user/Makefile | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/easy-fs-fuse/src/main.rs b/easy-fs-fuse/src/main.rs index 17b2465..bb9ff76 100644 --- a/easy-fs-fuse/src/main.rs +++ b/easy-fs-fuse/src/main.rs @@ -85,9 +85,9 @@ fn easy_fs_pack() -> std::io::Result<()> { inode.write_at(0, all_data.as_slice()); } // list apps - for app in root_inode.ls() { - println!("{}", app); - } + // for app in root_inode.ls() { + // println!("{}", app); + // } Ok(()) } diff --git a/user/Makefile b/user/Makefile index c09b5e9..5170327 100644 --- a/user/Makefile +++ b/user/Makefile @@ -19,7 +19,7 @@ ifeq ($(TEST), 1) endif binary: elf - $(foreach elf, $(ELFS), $(OBJCOPY) $(elf) --strip-all -O binary $(patsubst $(TARGET_DIR)/%, $(TARGET_DIR)/%.bin, $(elf));) + @$(foreach elf, $(ELFS), $(OBJCOPY) $(elf) --strip-all -O binary $(patsubst $(TARGET_DIR)/%, $(TARGET_DIR)/%.bin, $(elf));) build: binary From e80b7057a46a7c810003b7979b0cd89426a00d3e Mon Sep 17 00:00:00 2001 From: yufeng <321353225@qq.com> Date: Mon, 6 Feb 2023 19:12:45 +0800 Subject: [PATCH 59/68] add alloc_more --- os/src/mm/frame_allocator.rs | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/os/src/mm/frame_allocator.rs b/os/src/mm/frame_allocator.rs index 1ecfe99..3635e18 100644 --- a/os/src/mm/frame_allocator.rs +++ b/os/src/mm/frame_allocator.rs @@ -35,6 +35,7 @@ impl Drop for FrameTracker { trait FrameAllocator { fn new() -> Self; fn alloc(&mut self) -> Option; + fn alloc_more(&mut self, pages: usize) -> Option>; fn dealloc(&mut self, ppn: PhysPageNum); } @@ -69,6 +70,16 @@ impl FrameAllocator for StackFrameAllocator { Some((self.current - 1).into()) } } + fn alloc_more(&mut self, pages: usize) -> Option> { + if self.current + pages >= self.end { + None + } else { + self.current += pages; + let arr:Vec = (1..pages + 1).collect(); + let v = arr.iter().map(|x| (self.current - x).into()).collect(); + Some(v) + } + } fn dealloc(&mut self, ppn: PhysPageNum) { let ppn = ppn.0; // validity check @@ -104,6 +115,13 @@ pub fn frame_alloc() -> Option { .map(FrameTracker::new) } +pub fn frame_alloc_more(num: usize) -> Option> { + FRAME_ALLOCATOR + .exclusive_access() + .alloc_more(num) + .map(|x| x.iter().map(|&t| FrameTracker::new(t)).collect()) +} + pub fn frame_dealloc(ppn: PhysPageNum) { FRAME_ALLOCATOR.exclusive_access().dealloc(ppn); } @@ -125,3 +143,21 @@ pub fn frame_allocator_test() { drop(v); println!("frame_allocator_test passed!"); } + + +#[allow(unused)] +pub fn frame_allocator_alloc_more_test() { + let mut v: Vec = Vec::new(); + let frames = frame_alloc_more(5).unwrap(); + for frame in &frames { + println!("{:?}", frame); + } + v.extend(frames); + v.clear(); + let frames = frame_alloc_more(5).unwrap(); + for frame in &frames { + println!("{:?}", frame); + } + drop(v); + println!("frame_allocator_test passed!"); +} From 680f7fed2698cd8b0c3ca8793639a788eb664712 Mon Sep 17 00:00:00 2001 From: yufeng <321353225@qq.com> Date: Mon, 6 Feb 2023 19:15:46 +0800 Subject: [PATCH 60/68] use frame_alloc_more in VirtioHal --- os/src/drivers/bus/virtio.rs | 14 ++++---------- os/src/mm/mod.rs | 2 +- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/os/src/drivers/bus/virtio.rs b/os/src/drivers/bus/virtio.rs index 6871eb8..d9a6121 100644 --- a/os/src/drivers/bus/virtio.rs +++ b/os/src/drivers/bus/virtio.rs @@ -1,6 +1,6 @@ use crate::mm::{ frame_alloc, frame_dealloc, kernel_token, FrameTracker, PageTable, PhysAddr, PhysPageNum, - StepByOne, VirtAddr, + StepByOne, VirtAddr, frame_alloc_more, }; use crate::sync::UPIntrFreeCell; use alloc::vec::Vec; @@ -16,15 +16,9 @@ pub struct VirtioHal; impl Hal for VirtioHal { fn dma_alloc(pages: usize) -> usize { - let mut ppn_base = PhysPageNum(0); - for i in 0..pages { - let frame = frame_alloc().unwrap(); - if i == 0 { - ppn_base = frame.ppn; - } - assert_eq!(frame.ppn.0, ppn_base.0 + i); - QUEUE_FRAMES.exclusive_access().push(frame); - } + let trakcers = frame_alloc_more(pages); + let ppn_base = trakcers.as_ref().unwrap().last().unwrap().ppn; + QUEUE_FRAMES.exclusive_access().append(&mut trakcers.unwrap()); let pa: PhysAddr = ppn_base.into(); pa.0 } diff --git a/os/src/mm/mod.rs b/os/src/mm/mod.rs index 34220c4..05e52ea 100644 --- a/os/src/mm/mod.rs +++ b/os/src/mm/mod.rs @@ -6,7 +6,7 @@ mod page_table; use address::VPNRange; pub use address::{PhysAddr, PhysPageNum, StepByOne, VirtAddr, VirtPageNum}; -pub use frame_allocator::{frame_alloc, frame_dealloc, FrameTracker}; +pub use frame_allocator::{frame_alloc, frame_alloc_more, frame_dealloc, FrameTracker}; pub use memory_set::remap_test; pub use memory_set::{kernel_token, MapPermission, MemorySet, KERNEL_SPACE}; use page_table::PTEFlags; From 9355acf9039021dfc98f6cd2f94b778322934cf1 Mon Sep 17 00:00:00 2001 From: yufeng <321353225@qq.com> Date: Mon, 6 Feb 2023 19:21:43 +0800 Subject: [PATCH 61/68] add net support --- os/Cargo.toml | 1 + os/Makefile | 4 ++ os/src/drivers/mod.rs | 2 + os/src/drivers/net/mod.rs | 41 +++++++++++++++++ os/src/main.rs | 1 + os/src/net/mod.rs | 92 ++++++++++++++++++++++++++++++++++++++ os/src/net/socket.rs | 93 ++++++++++++++++++++++++++++++++++++++ os/src/net/udp.rs | 94 +++++++++++++++++++++++++++++++++++++++ os/src/syscall/mod.rs | 4 ++ os/src/syscall/net.rs | 14 ++++++ user/src/lib.rs | 3 ++ user/src/syscall.rs | 5 +++ 12 files changed, 354 insertions(+) create mode 100644 os/src/drivers/net/mod.rs create mode 100644 os/src/net/mod.rs create mode 100644 os/src/net/socket.rs create mode 100644 os/src/net/udp.rs create mode 100644 os/src/syscall/net.rs diff --git a/os/Cargo.toml b/os/Cargo.toml index 3cae609..4f7f709 100644 --- a/os/Cargo.toml +++ b/os/Cargo.toml @@ -15,6 +15,7 @@ bitflags = "1.2.1" xmas-elf = "0.7.0" volatile = "0.3" virtio-drivers = { git = "https://github.com/rcore-os/virtio-drivers", rev = "4ee80e5" } +lose-net-stack = { git = "https://github.com/yfblock/lose-net-stack", rev = "3f467dd" } easy-fs = { path = "../easy-fs" } virtio-input-decoder = "0.1.4" embedded-graphics = "0.7.1" diff --git a/os/Makefile b/os/Makefile index 6b7e9cf..ac0fd27 100644 --- a/os/Makefile +++ b/os/Makefile @@ -85,6 +85,8 @@ run-inner-none: build # -device virtio-gpu-device \ -device virtio-keyboard-device \ -device virtio-mouse-device \ + -device virtio-net-device,netdev=net0 \ + -netdev user,id=net0,hostfwd=udp::6200-:2000 \ -serial stdio run-inner: build @@ -99,6 +101,8 @@ run-inner: build -device virtio-gpu-device \ -device virtio-keyboard-device \ -device virtio-mouse-device \ + -device virtio-net-device,netdev=net0 \ + -netdev user,id=net0,hostfwd=udp::6200-:2000 \ -serial stdio fdt: diff --git a/os/src/drivers/mod.rs b/os/src/drivers/mod.rs index 57a15f0..e4f4172 100644 --- a/os/src/drivers/mod.rs +++ b/os/src/drivers/mod.rs @@ -3,6 +3,7 @@ pub mod bus; pub mod chardev; pub mod gpu; pub mod input; +pub mod net; pub mod plic; pub use block::BLOCK_DEVICE; @@ -10,3 +11,4 @@ pub use bus::*; pub use chardev::UART; pub use gpu::*; pub use input::*; +pub use net::*; \ No newline at end of file diff --git a/os/src/drivers/net/mod.rs b/os/src/drivers/net/mod.rs new file mode 100644 index 0000000..e1f76b0 --- /dev/null +++ b/os/src/drivers/net/mod.rs @@ -0,0 +1,41 @@ +use core::any::Any; + +use alloc::sync::Arc; +use lazy_static::*; +use virtio_drivers::{VirtIONet, VirtIOHeader}; +use crate::drivers::virtio::VirtioHal; +use crate::sync::UPIntrFreeCell; + +const VIRTIO8: usize = 0x10004000; + +lazy_static! { + pub static ref NET_DEVICE: Arc = Arc::new(VirtIONetWrapper::new()); +} + +pub trait NetDevice: Send + Sync + Any { + fn transmit(&self, data: &[u8]); + fn receive(&self, data: &mut [u8]) -> usize; +} + +pub struct VirtIONetWrapper(UPIntrFreeCell>); + +impl NetDevice for VirtIONetWrapper { + fn transmit(&self, data: &[u8]) { + self.0.exclusive_access().send(data).expect("can't send data") + } + + fn receive(&self, data: &mut [u8]) -> usize { + self.0.exclusive_access().recv(data).expect("can't receive data") + } +} + +impl VirtIONetWrapper { + pub fn new() -> Self { + unsafe { + let virtio = + VirtIONet::::new(&mut *(VIRTIO8 as *mut VirtIOHeader)) + .expect("can't create net device by virtio"); + VirtIONetWrapper(UPIntrFreeCell::new(virtio)) + } + } +} \ No newline at end of file diff --git a/os/src/main.rs b/os/src/main.rs index b9b5f15..500e913 100644 --- a/os/src/main.rs +++ b/os/src/main.rs @@ -29,6 +29,7 @@ mod syscall; mod task; mod timer; mod trap; +mod net; use riscv::register::*; // mod riscvreg; diff --git a/os/src/net/mod.rs b/os/src/net/mod.rs new file mode 100644 index 0000000..57673d3 --- /dev/null +++ b/os/src/net/mod.rs @@ -0,0 +1,92 @@ +pub mod udp; +pub mod socket; + +pub use lose_net_stack::IPv4; + +use alloc::{vec, sync::Arc}; +use lose_net_stack::{LoseStack, MacAddress, results::Packet}; + +use crate::{drivers::NET_DEVICE, sync::UPIntrFreeCell, net::socket::{get_socket, push_data}}; + +pub struct NetStack(UPIntrFreeCell); + +impl NetStack { + pub fn new() -> Self { + unsafe { + NetStack(UPIntrFreeCell::new(LoseStack::new( + IPv4::new(10, 0, 2, 15), + MacAddress::new([0x52, 0x54, 0x00, 0x12, 0x34, 0x56]) + ))) + } + } +} + +lazy_static::lazy_static! { + static ref LOSE_NET_STACK: Arc = Arc::new(NetStack::new()); +} + + +pub fn net_interrupt_handler() { + let mut recv_buf = vec![0u8; 1024]; + + let len = NET_DEVICE.receive(&mut recv_buf); + + let packet = LOSE_NET_STACK.0.exclusive_access().analysis(&recv_buf[..len]); + + // println!("[kernel] receive a packet"); + // hexdump(&recv_buf[..len]); + + match packet { + Packet::ARP(arp_packet) => { + let lose_stack = LOSE_NET_STACK.0.exclusive_access(); + let reply_packet = arp_packet.reply_packet(lose_stack.ip, lose_stack.mac).expect("can't build reply"); + let reply_data = reply_packet.build_data(); + NET_DEVICE.transmit(&reply_data) + }, + + Packet::UDP(udp_packet) => { + let target = udp_packet.source_ip; + let lport = udp_packet.dest_port; + let rport = udp_packet.source_port; + + if let Some(socket_index) = get_socket(target, lport, rport) { + push_data(socket_index, udp_packet.data.to_vec()); + } + } + _ => {} + } +} + +#[allow(unused)] +pub fn hexdump(data: &[u8]) { + const PRELAND_WIDTH: usize = 70; + println!("[kernel] {:-^1$}", " hexdump ", PRELAND_WIDTH); + for offset in (0..data.len()).step_by(16) { + print!("[kernel] "); + for i in 0..16 { + if offset + i < data.len() { + print!("{:02x} ", data[offset + i]); + } else { + print!("{:02} ", ""); + } + } + + print!("{:>6}", ' '); + + for i in 0..16 { + if offset + i < data.len() { + let c = data[offset + i]; + if c >= 0x20 && c <= 0x7e { + print!("{}", c as char); + } else { + print!("."); + } + } else { + print!("{:02} ", ""); + } + } + + println!(""); + } + println!("[kernel] {:-^1$}", " hexdump end ", PRELAND_WIDTH); +} \ No newline at end of file diff --git a/os/src/net/socket.rs b/os/src/net/socket.rs new file mode 100644 index 0000000..4e92a00 --- /dev/null +++ b/os/src/net/socket.rs @@ -0,0 +1,93 @@ +use alloc::collections::VecDeque; +use alloc::vec::Vec; +use lazy_static::lazy_static; +use lose_net_stack::IPv4; + +use crate::sync::UPIntrFreeCell; + + +// TODO: specify the protocol, TCP or UDP +pub struct Socket { + pub raddr: IPv4, // remote address + pub lport: u16, // local port + pub rport: u16, // rempote port + pub buffers: VecDeque> // datas +} + +lazy_static! { + static ref SOCKET_TABLE:UPIntrFreeCell>> = unsafe { + UPIntrFreeCell::new(Vec::new()) + }; +} + +pub fn get_socket(raddr: IPv4, lport: u16, rport: u16) -> Option { + let socket_table = SOCKET_TABLE.exclusive_access(); + for i in 0..socket_table.len() { + let sock = &socket_table[i]; + if sock.is_none() { + continue; + } + + let sock = sock.as_ref().unwrap(); + if sock.raddr == raddr && sock.lport == lport && sock.rport == rport { + return Some(i) + } + } + None +} + +pub fn add_socket(raddr: IPv4, lport: u16, rport: u16) -> Option { + if get_socket(raddr, lport, rport).is_some() { + return None; + } + + let mut socket_table = SOCKET_TABLE.exclusive_access(); + let mut index = usize::MAX; + for i in 0..socket_table.len() { + if socket_table[i].is_none() { + index = i; + break; + } + } + + let socket = Socket { + raddr, + lport, + rport, + buffers: VecDeque::new() + }; + + if index == usize::MAX { + socket_table.push(Some(socket)); + Some(socket_table.len() - 1) + } else { + socket_table[index] = Some(socket); + Some(index) + } +} + +pub fn remove_socket(index: usize) { + let mut socket_table = SOCKET_TABLE.exclusive_access(); + + assert!(socket_table.len() > index); + + socket_table[index] = None; +} + +pub fn push_data(index: usize, data: Vec) { + let mut socket_table = SOCKET_TABLE.exclusive_access(); + + assert!(socket_table.len() > index); + assert!(socket_table[index].is_some()); + + socket_table[index].as_mut().unwrap().buffers.push_back(data); +} + +pub fn pop_data(index: usize) -> Option> { + let mut socket_table = SOCKET_TABLE.exclusive_access(); + + assert!(socket_table.len() > index); + assert!(socket_table[index].is_some()); + + socket_table[index].as_mut().unwrap().buffers.pop_front() +} \ No newline at end of file diff --git a/os/src/net/udp.rs b/os/src/net/udp.rs new file mode 100644 index 0000000..afa26d0 --- /dev/null +++ b/os/src/net/udp.rs @@ -0,0 +1,94 @@ +use alloc::vec; +use lose_net_stack::MacAddress; +use lose_net_stack::packets::udp::UDPPacket; +use lose_net_stack::IPv4; +use crate::fs::File; +use super::net_interrupt_handler; +use super::socket::{add_socket, remove_socket, pop_data}; +use super::LOSE_NET_STACK; +use super::NET_DEVICE; + +pub struct UDP{ + pub target: IPv4, + pub sport: u16, + pub dport: u16, + pub socket_index: usize +} + +impl UDP { + pub fn new(target: IPv4, sport: u16, dport: u16) -> Self { + let index = add_socket(target, sport, dport).expect("can't add socket"); + + Self { + target, + sport, + dport, + socket_index: index + } + } +} + +impl File for UDP { + fn readable(&self) -> bool { + true + } + + fn writable(&self) -> bool { + true + } + + fn read(&self, mut buf: crate::mm::UserBuffer) -> usize { + loop { + if let Some(data) = pop_data(self.socket_index) { + let data_len = data.len(); + let mut left = 0; + for i in 0..buf.buffers.len() { + let buffer_i_len = buf.buffers[i].len().min(data_len - left); + + buf.buffers[i][..buffer_i_len].copy_from_slice(&data[left..(left + buffer_i_len)]); + + left += buffer_i_len; + if left == data_len { + break; + } + } + return left; + } else { + net_interrupt_handler(); + } + } + } + + fn write(&self, buf: crate::mm::UserBuffer) -> usize { + let lose_net_stack = LOSE_NET_STACK.0.exclusive_access(); + + let mut data = vec![0u8; buf.len()]; + + let mut left = 0; + for i in 0..buf.buffers.len() { + data[left..(left + buf.buffers[i].len())].copy_from_slice(buf.buffers[i]); + left += buf.buffers[i].len(); + } + + let len = data.len(); + + let udp_packet = UDPPacket::new( + lose_net_stack.ip, + lose_net_stack.mac, + self.sport, + self.target, + MacAddress::new([0xff, 0xff, 0xff, 0xff, 0xff, 0xff]), + self.dport, + len, + data.as_ref() + ); + NET_DEVICE.transmit(&udp_packet.build_data()); + len + } +} + +impl Drop for UDP { + fn drop(&mut self) { + remove_socket(self.socket_index) + } +} \ No newline at end of file diff --git a/os/src/syscall/mod.rs b/os/src/syscall/mod.rs index fa4a4cf..1766f3e 100644 --- a/os/src/syscall/mod.rs +++ b/os/src/syscall/mod.rs @@ -1,4 +1,5 @@ const SYSCALL_DUP: usize = 24; +const SYSCALL_CONNECT: usize = 29; const SYSCALL_OPEN: usize = 56; const SYSCALL_CLOSE: usize = 57; const SYSCALL_PIPE: usize = 59; @@ -30,15 +31,18 @@ mod fs; mod process; mod sync; mod thread; +mod net; use fs::*; use process::*; use sync::*; use thread::*; +use net::*; pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize { match syscall_id { SYSCALL_DUP => sys_dup(args[0]), + SYSCALL_CONNECT => sys_connect(args[0] as _, args[1] as _, args[2] as _), SYSCALL_OPEN => sys_open(args[0] as *const u8, args[1] as u32), SYSCALL_CLOSE => sys_close(args[0]), SYSCALL_PIPE => sys_pipe(args[0] as *mut usize), diff --git a/os/src/syscall/net.rs b/os/src/syscall/net.rs new file mode 100644 index 0000000..4ed4466 --- /dev/null +++ b/os/src/syscall/net.rs @@ -0,0 +1,14 @@ +use alloc::sync::Arc; +use crate::net::IPv4; +use crate::net::udp::UDP; +use crate::task::current_process; + +// just support udp +pub fn sys_connect(raddr: u32, lport: u16, rport: u16) -> isize { + let process = current_process(); + let mut inner = process.inner_exclusive_access(); + let fd = inner.alloc_fd(); + let udp_node = UDP::new(IPv4::from_u32(raddr), lport, rport); + inner.fd_table[fd] = Some(Arc::new(udp_node)); + fd as isize +} \ No newline at end of file diff --git a/user/src/lib.rs b/user/src/lib.rs index 729eaef..6f30d75 100644 --- a/user/src/lib.rs +++ b/user/src/lib.rs @@ -72,6 +72,9 @@ bitflags! { pub fn dup(fd: usize) -> isize { sys_dup(fd) } +pub fn connect(ip: u32, sport: u16, dport: u16) -> isize { + sys_connect(ip, sport, dport) +} pub fn open(path: &str, flags: OpenFlags) -> isize { sys_open(path, flags.bits) } diff --git a/user/src/syscall.rs b/user/src/syscall.rs index b4bb67a..1e5e405 100644 --- a/user/src/syscall.rs +++ b/user/src/syscall.rs @@ -1,4 +1,5 @@ const SYSCALL_DUP: usize = 24; +const SYSCALL_CONNECT: usize = 29; const SYSCALL_OPEN: usize = 56; const SYSCALL_CLOSE: usize = 57; const SYSCALL_PIPE: usize = 59; @@ -44,6 +45,10 @@ pub fn sys_dup(fd: usize) -> isize { syscall(SYSCALL_DUP, [fd, 0, 0]) } +pub fn sys_connect(dest: u32, sport: u16, dport: u16) -> isize { + syscall(SYSCALL_CONNECT, [dest as usize, sport as usize, dport as usize]) +} + pub fn sys_open(path: &str, flags: u32) -> isize { syscall(SYSCALL_OPEN, [path.as_ptr() as usize, flags as usize, 0]) } From d31be8cba0165a6715c32fd1e58cde2e6ec1ec2c Mon Sep 17 00:00:00 2001 From: yufeng <321353225@qq.com> Date: Mon, 6 Feb 2023 19:22:44 +0800 Subject: [PATCH 62/68] Add a udp program and a ping test script --- ping.py | 18 ++++++++++++++++++ user/src/bin/udp.rs | 45 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 ping.py create mode 100644 user/src/bin/udp.rs diff --git a/ping.py b/ping.py new file mode 100644 index 0000000..c68fc71 --- /dev/null +++ b/ping.py @@ -0,0 +1,18 @@ +import socket +import sys +import time + +sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) +addr = ('localhost', 26099) +sock.bind(addr) + + +print("pinging...", file=sys.stderr) +while True: + buf, raddr = sock.recvfrom(4096) + print("receive: " + buf.decode("utf-8")) + buf = "this is a ping to port 6200!".encode('utf-8') + sock.sendto(buf, ("127.0.0.1", 6200)) + buf = "this is a ping to reply!".encode('utf-8') + sock.sendto(buf, raddr) + time.sleep(1) diff --git a/user/src/bin/udp.rs b/user/src/bin/udp.rs new file mode 100644 index 0000000..dda6005 --- /dev/null +++ b/user/src/bin/udp.rs @@ -0,0 +1,45 @@ +#![no_std] +#![no_main] + +use alloc::string::String; +use user_lib::{connect, write, read}; + +#[macro_use] +extern crate user_lib; +#[macro_use] +extern crate alloc; + +#[no_mangle] +pub fn main() -> i32 { + println!("udp test open!"); + + let udp_fd = connect(10 << 24 | 0 << 16 | 2 << 8 | 2, 2001, 26099); + + if udp_fd < 0 { + println!("failed to create udp connection."); + return -1; + } + + let buf = "Hello rCoreOS user program!"; + + println!("send <{}>", buf); + + write(udp_fd as usize, buf.as_bytes()); + + println!("udp send done, waiting for reply."); + + let mut buf = vec![0u8; 1024]; + + let len = read(udp_fd as usize, &mut buf); + + if len < 0 { + println!("can't receive udp packet"); + return -1; + } + + let recv_str = String::from_utf8_lossy(&buf[..len as usize]); + + println!("receive reply <{}>", recv_str); + + 0 +} \ No newline at end of file From 4ce5f89c9cd8d390c9fac557581ffd160608a1d5 Mon Sep 17 00:00:00 2001 From: yufeng <321353225@qq.com> Date: Mon, 6 Feb 2023 19:12:45 +0800 Subject: [PATCH 63/68] add alloc_more --- os/src/mm/frame_allocator.rs | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/os/src/mm/frame_allocator.rs b/os/src/mm/frame_allocator.rs index 1ecfe99..3635e18 100644 --- a/os/src/mm/frame_allocator.rs +++ b/os/src/mm/frame_allocator.rs @@ -35,6 +35,7 @@ impl Drop for FrameTracker { trait FrameAllocator { fn new() -> Self; fn alloc(&mut self) -> Option; + fn alloc_more(&mut self, pages: usize) -> Option>; fn dealloc(&mut self, ppn: PhysPageNum); } @@ -69,6 +70,16 @@ impl FrameAllocator for StackFrameAllocator { Some((self.current - 1).into()) } } + fn alloc_more(&mut self, pages: usize) -> Option> { + if self.current + pages >= self.end { + None + } else { + self.current += pages; + let arr:Vec = (1..pages + 1).collect(); + let v = arr.iter().map(|x| (self.current - x).into()).collect(); + Some(v) + } + } fn dealloc(&mut self, ppn: PhysPageNum) { let ppn = ppn.0; // validity check @@ -104,6 +115,13 @@ pub fn frame_alloc() -> Option { .map(FrameTracker::new) } +pub fn frame_alloc_more(num: usize) -> Option> { + FRAME_ALLOCATOR + .exclusive_access() + .alloc_more(num) + .map(|x| x.iter().map(|&t| FrameTracker::new(t)).collect()) +} + pub fn frame_dealloc(ppn: PhysPageNum) { FRAME_ALLOCATOR.exclusive_access().dealloc(ppn); } @@ -125,3 +143,21 @@ pub fn frame_allocator_test() { drop(v); println!("frame_allocator_test passed!"); } + + +#[allow(unused)] +pub fn frame_allocator_alloc_more_test() { + let mut v: Vec = Vec::new(); + let frames = frame_alloc_more(5).unwrap(); + for frame in &frames { + println!("{:?}", frame); + } + v.extend(frames); + v.clear(); + let frames = frame_alloc_more(5).unwrap(); + for frame in &frames { + println!("{:?}", frame); + } + drop(v); + println!("frame_allocator_test passed!"); +} From 1a2838d670bb3fbc2f004f0284db6ea07aac0fb6 Mon Sep 17 00:00:00 2001 From: yufeng <321353225@qq.com> Date: Mon, 6 Feb 2023 19:15:46 +0800 Subject: [PATCH 64/68] use frame_alloc_more in VirtioHal --- os/src/drivers/bus/virtio.rs | 14 ++++---------- os/src/mm/mod.rs | 2 +- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/os/src/drivers/bus/virtio.rs b/os/src/drivers/bus/virtio.rs index 6871eb8..d9a6121 100644 --- a/os/src/drivers/bus/virtio.rs +++ b/os/src/drivers/bus/virtio.rs @@ -1,6 +1,6 @@ use crate::mm::{ frame_alloc, frame_dealloc, kernel_token, FrameTracker, PageTable, PhysAddr, PhysPageNum, - StepByOne, VirtAddr, + StepByOne, VirtAddr, frame_alloc_more, }; use crate::sync::UPIntrFreeCell; use alloc::vec::Vec; @@ -16,15 +16,9 @@ pub struct VirtioHal; impl Hal for VirtioHal { fn dma_alloc(pages: usize) -> usize { - let mut ppn_base = PhysPageNum(0); - for i in 0..pages { - let frame = frame_alloc().unwrap(); - if i == 0 { - ppn_base = frame.ppn; - } - assert_eq!(frame.ppn.0, ppn_base.0 + i); - QUEUE_FRAMES.exclusive_access().push(frame); - } + let trakcers = frame_alloc_more(pages); + let ppn_base = trakcers.as_ref().unwrap().last().unwrap().ppn; + QUEUE_FRAMES.exclusive_access().append(&mut trakcers.unwrap()); let pa: PhysAddr = ppn_base.into(); pa.0 } diff --git a/os/src/mm/mod.rs b/os/src/mm/mod.rs index 77d62f4..574cea0 100644 --- a/os/src/mm/mod.rs +++ b/os/src/mm/mod.rs @@ -6,7 +6,7 @@ mod page_table; pub use address::VPNRange; pub use address::{PhysAddr, PhysPageNum, StepByOne, VirtAddr, VirtPageNum}; -pub use frame_allocator::{frame_alloc, frame_dealloc, FrameTracker}; +pub use frame_allocator::{frame_alloc, frame_alloc_more, frame_dealloc, FrameTracker}; pub use memory_set::remap_test; pub use memory_set::{kernel_token, MapArea, MapPermission, MapType, MemorySet, KERNEL_SPACE}; use page_table::PTEFlags; From 2e81c8960c2d4fe523e75e0ea7bb55ab33bd5525 Mon Sep 17 00:00:00 2001 From: yufeng <321353225@qq.com> Date: Mon, 6 Feb 2023 19:21:43 +0800 Subject: [PATCH 65/68] add net support, fix merge error --- os/Cargo.toml | 1 + os/Makefile | 18 ++++++++ os/src/drivers/mod.rs | 2 + os/src/drivers/net/mod.rs | 41 +++++++++++++++++ os/src/main.rs | 1 + os/src/net/mod.rs | 92 ++++++++++++++++++++++++++++++++++++++ os/src/net/socket.rs | 93 ++++++++++++++++++++++++++++++++++++++ os/src/net/udp.rs | 94 +++++++++++++++++++++++++++++++++++++++ os/src/syscall/mod.rs | 4 ++ os/src/syscall/net.rs | 14 ++++++ user/src/syscall.rs | 5 +++ 11 files changed, 365 insertions(+) create mode 100644 os/src/drivers/net/mod.rs create mode 100644 os/src/net/mod.rs create mode 100644 os/src/net/socket.rs create mode 100644 os/src/net/udp.rs create mode 100644 os/src/syscall/net.rs diff --git a/os/Cargo.toml b/os/Cargo.toml index d8f4216..e23fe16 100644 --- a/os/Cargo.toml +++ b/os/Cargo.toml @@ -14,6 +14,7 @@ bitflags = "1.2.1" xmas-elf = "0.7.0" volatile = "0.3" virtio-drivers = { git = "https://github.com/rcore-os/virtio-drivers", rev = "4ee80e5" } +lose-net-stack = { git = "https://github.com/yfblock/lose-net-stack", rev = "3f467dd" } easy-fs = { path = "../easy-fs" } embedded-graphics = "0.7.1" tinybmp = "0.3.1" diff --git a/os/Makefile b/os/Makefile index e02bc81..db3be5d 100644 --- a/os/Makefile +++ b/os/Makefile @@ -73,6 +73,22 @@ disasm-vim: kernel run: run-inner +run-inner-none: build + @qemu-system-riscv64 \ + -M 128m \ + -machine virt \ + -bios none \ + $(GUI_OPTION) \ + -kernel $(KERNEL_ELF) \ + -drive file=$(FS_IMG),if=none,format=raw,id=x0 \ + -device virtio-blk-device,drive=x0 \ +# -device virtio-gpu-device \ + -device virtio-keyboard-device \ + -device virtio-mouse-device \ + -device virtio-net-device,netdev=net0 \ + -netdev user,id=net0,hostfwd=udp::6200-:2000 \ + -serial stdio + run-inner: build @qemu-system-riscv64 \ -M 128m \ @@ -85,6 +101,8 @@ run-inner: build -device virtio-gpu-device \ -device virtio-keyboard-device \ -device virtio-mouse-device \ + -device virtio-net-device,netdev=net0 \ + -netdev user,id=net0,hostfwd=udp::6200-:2000 \ -serial stdio fdt: diff --git a/os/src/drivers/mod.rs b/os/src/drivers/mod.rs index 57a15f0..e4f4172 100644 --- a/os/src/drivers/mod.rs +++ b/os/src/drivers/mod.rs @@ -3,6 +3,7 @@ pub mod bus; pub mod chardev; pub mod gpu; pub mod input; +pub mod net; pub mod plic; pub use block::BLOCK_DEVICE; @@ -10,3 +11,4 @@ pub use bus::*; pub use chardev::UART; pub use gpu::*; pub use input::*; +pub use net::*; \ No newline at end of file diff --git a/os/src/drivers/net/mod.rs b/os/src/drivers/net/mod.rs new file mode 100644 index 0000000..e1f76b0 --- /dev/null +++ b/os/src/drivers/net/mod.rs @@ -0,0 +1,41 @@ +use core::any::Any; + +use alloc::sync::Arc; +use lazy_static::*; +use virtio_drivers::{VirtIONet, VirtIOHeader}; +use crate::drivers::virtio::VirtioHal; +use crate::sync::UPIntrFreeCell; + +const VIRTIO8: usize = 0x10004000; + +lazy_static! { + pub static ref NET_DEVICE: Arc = Arc::new(VirtIONetWrapper::new()); +} + +pub trait NetDevice: Send + Sync + Any { + fn transmit(&self, data: &[u8]); + fn receive(&self, data: &mut [u8]) -> usize; +} + +pub struct VirtIONetWrapper(UPIntrFreeCell>); + +impl NetDevice for VirtIONetWrapper { + fn transmit(&self, data: &[u8]) { + self.0.exclusive_access().send(data).expect("can't send data") + } + + fn receive(&self, data: &mut [u8]) -> usize { + self.0.exclusive_access().recv(data).expect("can't receive data") + } +} + +impl VirtIONetWrapper { + pub fn new() -> Self { + unsafe { + let virtio = + VirtIONet::::new(&mut *(VIRTIO8 as *mut VirtIOHeader)) + .expect("can't create net device by virtio"); + VirtIONetWrapper(UPIntrFreeCell::new(virtio)) + } + } +} \ No newline at end of file diff --git a/os/src/main.rs b/os/src/main.rs index 1103c57..98dbcd6 100644 --- a/os/src/main.rs +++ b/os/src/main.rs @@ -26,6 +26,7 @@ mod syscall; mod task; mod timer; mod trap; +mod net; use crate::drivers::chardev::CharDevice; use crate::drivers::chardev::UART; diff --git a/os/src/net/mod.rs b/os/src/net/mod.rs new file mode 100644 index 0000000..57673d3 --- /dev/null +++ b/os/src/net/mod.rs @@ -0,0 +1,92 @@ +pub mod udp; +pub mod socket; + +pub use lose_net_stack::IPv4; + +use alloc::{vec, sync::Arc}; +use lose_net_stack::{LoseStack, MacAddress, results::Packet}; + +use crate::{drivers::NET_DEVICE, sync::UPIntrFreeCell, net::socket::{get_socket, push_data}}; + +pub struct NetStack(UPIntrFreeCell); + +impl NetStack { + pub fn new() -> Self { + unsafe { + NetStack(UPIntrFreeCell::new(LoseStack::new( + IPv4::new(10, 0, 2, 15), + MacAddress::new([0x52, 0x54, 0x00, 0x12, 0x34, 0x56]) + ))) + } + } +} + +lazy_static::lazy_static! { + static ref LOSE_NET_STACK: Arc = Arc::new(NetStack::new()); +} + + +pub fn net_interrupt_handler() { + let mut recv_buf = vec![0u8; 1024]; + + let len = NET_DEVICE.receive(&mut recv_buf); + + let packet = LOSE_NET_STACK.0.exclusive_access().analysis(&recv_buf[..len]); + + // println!("[kernel] receive a packet"); + // hexdump(&recv_buf[..len]); + + match packet { + Packet::ARP(arp_packet) => { + let lose_stack = LOSE_NET_STACK.0.exclusive_access(); + let reply_packet = arp_packet.reply_packet(lose_stack.ip, lose_stack.mac).expect("can't build reply"); + let reply_data = reply_packet.build_data(); + NET_DEVICE.transmit(&reply_data) + }, + + Packet::UDP(udp_packet) => { + let target = udp_packet.source_ip; + let lport = udp_packet.dest_port; + let rport = udp_packet.source_port; + + if let Some(socket_index) = get_socket(target, lport, rport) { + push_data(socket_index, udp_packet.data.to_vec()); + } + } + _ => {} + } +} + +#[allow(unused)] +pub fn hexdump(data: &[u8]) { + const PRELAND_WIDTH: usize = 70; + println!("[kernel] {:-^1$}", " hexdump ", PRELAND_WIDTH); + for offset in (0..data.len()).step_by(16) { + print!("[kernel] "); + for i in 0..16 { + if offset + i < data.len() { + print!("{:02x} ", data[offset + i]); + } else { + print!("{:02} ", ""); + } + } + + print!("{:>6}", ' '); + + for i in 0..16 { + if offset + i < data.len() { + let c = data[offset + i]; + if c >= 0x20 && c <= 0x7e { + print!("{}", c as char); + } else { + print!("."); + } + } else { + print!("{:02} ", ""); + } + } + + println!(""); + } + println!("[kernel] {:-^1$}", " hexdump end ", PRELAND_WIDTH); +} \ No newline at end of file diff --git a/os/src/net/socket.rs b/os/src/net/socket.rs new file mode 100644 index 0000000..4e92a00 --- /dev/null +++ b/os/src/net/socket.rs @@ -0,0 +1,93 @@ +use alloc::collections::VecDeque; +use alloc::vec::Vec; +use lazy_static::lazy_static; +use lose_net_stack::IPv4; + +use crate::sync::UPIntrFreeCell; + + +// TODO: specify the protocol, TCP or UDP +pub struct Socket { + pub raddr: IPv4, // remote address + pub lport: u16, // local port + pub rport: u16, // rempote port + pub buffers: VecDeque> // datas +} + +lazy_static! { + static ref SOCKET_TABLE:UPIntrFreeCell>> = unsafe { + UPIntrFreeCell::new(Vec::new()) + }; +} + +pub fn get_socket(raddr: IPv4, lport: u16, rport: u16) -> Option { + let socket_table = SOCKET_TABLE.exclusive_access(); + for i in 0..socket_table.len() { + let sock = &socket_table[i]; + if sock.is_none() { + continue; + } + + let sock = sock.as_ref().unwrap(); + if sock.raddr == raddr && sock.lport == lport && sock.rport == rport { + return Some(i) + } + } + None +} + +pub fn add_socket(raddr: IPv4, lport: u16, rport: u16) -> Option { + if get_socket(raddr, lport, rport).is_some() { + return None; + } + + let mut socket_table = SOCKET_TABLE.exclusive_access(); + let mut index = usize::MAX; + for i in 0..socket_table.len() { + if socket_table[i].is_none() { + index = i; + break; + } + } + + let socket = Socket { + raddr, + lport, + rport, + buffers: VecDeque::new() + }; + + if index == usize::MAX { + socket_table.push(Some(socket)); + Some(socket_table.len() - 1) + } else { + socket_table[index] = Some(socket); + Some(index) + } +} + +pub fn remove_socket(index: usize) { + let mut socket_table = SOCKET_TABLE.exclusive_access(); + + assert!(socket_table.len() > index); + + socket_table[index] = None; +} + +pub fn push_data(index: usize, data: Vec) { + let mut socket_table = SOCKET_TABLE.exclusive_access(); + + assert!(socket_table.len() > index); + assert!(socket_table[index].is_some()); + + socket_table[index].as_mut().unwrap().buffers.push_back(data); +} + +pub fn pop_data(index: usize) -> Option> { + let mut socket_table = SOCKET_TABLE.exclusive_access(); + + assert!(socket_table.len() > index); + assert!(socket_table[index].is_some()); + + socket_table[index].as_mut().unwrap().buffers.pop_front() +} \ No newline at end of file diff --git a/os/src/net/udp.rs b/os/src/net/udp.rs new file mode 100644 index 0000000..afa26d0 --- /dev/null +++ b/os/src/net/udp.rs @@ -0,0 +1,94 @@ +use alloc::vec; +use lose_net_stack::MacAddress; +use lose_net_stack::packets::udp::UDPPacket; +use lose_net_stack::IPv4; +use crate::fs::File; +use super::net_interrupt_handler; +use super::socket::{add_socket, remove_socket, pop_data}; +use super::LOSE_NET_STACK; +use super::NET_DEVICE; + +pub struct UDP{ + pub target: IPv4, + pub sport: u16, + pub dport: u16, + pub socket_index: usize +} + +impl UDP { + pub fn new(target: IPv4, sport: u16, dport: u16) -> Self { + let index = add_socket(target, sport, dport).expect("can't add socket"); + + Self { + target, + sport, + dport, + socket_index: index + } + } +} + +impl File for UDP { + fn readable(&self) -> bool { + true + } + + fn writable(&self) -> bool { + true + } + + fn read(&self, mut buf: crate::mm::UserBuffer) -> usize { + loop { + if let Some(data) = pop_data(self.socket_index) { + let data_len = data.len(); + let mut left = 0; + for i in 0..buf.buffers.len() { + let buffer_i_len = buf.buffers[i].len().min(data_len - left); + + buf.buffers[i][..buffer_i_len].copy_from_slice(&data[left..(left + buffer_i_len)]); + + left += buffer_i_len; + if left == data_len { + break; + } + } + return left; + } else { + net_interrupt_handler(); + } + } + } + + fn write(&self, buf: crate::mm::UserBuffer) -> usize { + let lose_net_stack = LOSE_NET_STACK.0.exclusive_access(); + + let mut data = vec![0u8; buf.len()]; + + let mut left = 0; + for i in 0..buf.buffers.len() { + data[left..(left + buf.buffers[i].len())].copy_from_slice(buf.buffers[i]); + left += buf.buffers[i].len(); + } + + let len = data.len(); + + let udp_packet = UDPPacket::new( + lose_net_stack.ip, + lose_net_stack.mac, + self.sport, + self.target, + MacAddress::new([0xff, 0xff, 0xff, 0xff, 0xff, 0xff]), + self.dport, + len, + data.as_ref() + ); + NET_DEVICE.transmit(&udp_packet.build_data()); + len + } +} + +impl Drop for UDP { + fn drop(&mut self) { + remove_socket(self.socket_index) + } +} \ No newline at end of file diff --git a/os/src/syscall/mod.rs b/os/src/syscall/mod.rs index 4052cf5..a336a96 100644 --- a/os/src/syscall/mod.rs +++ b/os/src/syscall/mod.rs @@ -1,4 +1,5 @@ const SYSCALL_DUP: usize = 24; +const SYSCALL_CONNECT: usize = 29; const SYSCALL_OPEN: usize = 56; const SYSCALL_CLOSE: usize = 57; const SYSCALL_PIPE: usize = 59; @@ -36,6 +37,7 @@ mod input; mod process; mod sync; mod thread; +mod net; use fs::*; use gui::*; @@ -43,10 +45,12 @@ use input::*; use process::*; use sync::*; use thread::*; +use net::*; pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize { match syscall_id { SYSCALL_DUP => sys_dup(args[0]), + SYSCALL_CONNECT => sys_connect(args[0] as _, args[1] as _, args[2] as _), SYSCALL_OPEN => sys_open(args[0] as *const u8, args[1] as u32), SYSCALL_CLOSE => sys_close(args[0]), SYSCALL_PIPE => sys_pipe(args[0] as *mut usize), diff --git a/os/src/syscall/net.rs b/os/src/syscall/net.rs new file mode 100644 index 0000000..4ed4466 --- /dev/null +++ b/os/src/syscall/net.rs @@ -0,0 +1,14 @@ +use alloc::sync::Arc; +use crate::net::IPv4; +use crate::net::udp::UDP; +use crate::task::current_process; + +// just support udp +pub fn sys_connect(raddr: u32, lport: u16, rport: u16) -> isize { + let process = current_process(); + let mut inner = process.inner_exclusive_access(); + let fd = inner.alloc_fd(); + let udp_node = UDP::new(IPv4::from_u32(raddr), lport, rport); + inner.fd_table[fd] = Some(Arc::new(udp_node)); + fd as isize +} \ No newline at end of file diff --git a/user/src/syscall.rs b/user/src/syscall.rs index 87885f5..c5fb48d 100644 --- a/user/src/syscall.rs +++ b/user/src/syscall.rs @@ -1,4 +1,5 @@ const SYSCALL_DUP: usize = 24; +const SYSCALL_CONNECT: usize = 29; const SYSCALL_OPEN: usize = 56; const SYSCALL_CLOSE: usize = 57; const SYSCALL_PIPE: usize = 59; @@ -48,6 +49,10 @@ pub fn sys_dup(fd: usize) -> isize { syscall(SYSCALL_DUP, [fd, 0, 0]) } +pub fn sys_connect(dest: u32, sport: u16, dport: u16) -> isize { + syscall(SYSCALL_CONNECT, [dest as usize, sport as usize, dport as usize]) +} + pub fn sys_open(path: &str, flags: u32) -> isize { syscall(SYSCALL_OPEN, [path.as_ptr() as usize, flags as usize, 0]) } From dd4678ff0e6c9b9a51a71a1942cbe6c83ec9c6b6 Mon Sep 17 00:00:00 2001 From: yufeng <321353225@qq.com> Date: Mon, 6 Feb 2023 19:22:44 +0800 Subject: [PATCH 66/68] Add a udp program and a ping test script --- ping.py | 18 ++++++++++++++++++ user/src/bin/udp.rs | 45 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 ping.py create mode 100644 user/src/bin/udp.rs diff --git a/ping.py b/ping.py new file mode 100644 index 0000000..c68fc71 --- /dev/null +++ b/ping.py @@ -0,0 +1,18 @@ +import socket +import sys +import time + +sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) +addr = ('localhost', 26099) +sock.bind(addr) + + +print("pinging...", file=sys.stderr) +while True: + buf, raddr = sock.recvfrom(4096) + print("receive: " + buf.decode("utf-8")) + buf = "this is a ping to port 6200!".encode('utf-8') + sock.sendto(buf, ("127.0.0.1", 6200)) + buf = "this is a ping to reply!".encode('utf-8') + sock.sendto(buf, raddr) + time.sleep(1) diff --git a/user/src/bin/udp.rs b/user/src/bin/udp.rs new file mode 100644 index 0000000..dda6005 --- /dev/null +++ b/user/src/bin/udp.rs @@ -0,0 +1,45 @@ +#![no_std] +#![no_main] + +use alloc::string::String; +use user_lib::{connect, write, read}; + +#[macro_use] +extern crate user_lib; +#[macro_use] +extern crate alloc; + +#[no_mangle] +pub fn main() -> i32 { + println!("udp test open!"); + + let udp_fd = connect(10 << 24 | 0 << 16 | 2 << 8 | 2, 2001, 26099); + + if udp_fd < 0 { + println!("failed to create udp connection."); + return -1; + } + + let buf = "Hello rCoreOS user program!"; + + println!("send <{}>", buf); + + write(udp_fd as usize, buf.as_bytes()); + + println!("udp send done, waiting for reply."); + + let mut buf = vec![0u8; 1024]; + + let len = read(udp_fd as usize, &mut buf); + + if len < 0 { + println!("can't receive udp packet"); + return -1; + } + + let recv_str = String::from_utf8_lossy(&buf[..len as usize]); + + println!("receive reply <{}>", recv_str); + + 0 +} \ No newline at end of file From 02be18684da4adc90f1d7ccae4fdb94fa5e51a70 Mon Sep 17 00:00:00 2001 From: Yu Chen Date: Wed, 8 Feb 2023 00:04:50 +0800 Subject: [PATCH 67/68] fix net support for user net app --- user/src/bin/udp.rs | 3 ++- user/src/lib.rs | 2 ++ user/src/net.rs | 5 +++++ 3 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 user/src/net.rs diff --git a/user/src/bin/udp.rs b/user/src/bin/udp.rs index dda6005..f2f0093 100644 --- a/user/src/bin/udp.rs +++ b/user/src/bin/udp.rs @@ -2,13 +2,14 @@ #![no_main] use alloc::string::String; -use user_lib::{connect, write, read}; #[macro_use] extern crate user_lib; #[macro_use] extern crate alloc; +use user_lib::{connect, write, read}; + #[no_mangle] pub fn main() -> i32 { println!("udp test open!"); diff --git a/user/src/lib.rs b/user/src/lib.rs index 0d0db85..1b5b2f3 100644 --- a/user/src/lib.rs +++ b/user/src/lib.rs @@ -12,6 +12,7 @@ mod file; mod task; mod sync; mod io; +mod net; extern crate alloc; #[macro_use] @@ -24,6 +25,7 @@ pub use file::*; pub use task::*; pub use sync::*; pub use io::*; +pub use net::*; const USER_HEAP_SIZE: usize = 32768; diff --git a/user/src/net.rs b/user/src/net.rs new file mode 100644 index 0000000..40ebca4 --- /dev/null +++ b/user/src/net.rs @@ -0,0 +1,5 @@ +use super::*; + +pub fn connect(ip: u32, sport: u16, dport: u16) -> isize { + sys_connect(ip, sport, dport) +} \ No newline at end of file From 09232ae31f98b197d4d6f7ff92ba5bf748d40942 Mon Sep 17 00:00:00 2001 From: Yu Chen Date: Wed, 8 Feb 2023 00:15:59 +0800 Subject: [PATCH 68/68] remove connect fun in usr/src/task.rs --- user/src/task.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/user/src/task.rs b/user/src/task.rs index 1f60e03..46eee79 100644 --- a/user/src/task.rs +++ b/user/src/task.rs @@ -18,9 +18,7 @@ pub fn fork() -> isize { pub fn exec(path: &str, args: &[*const u8]) -> isize { sys_exec(path, args) } -pub fn connect(raddr: u32, lport: u16, rport: u16) -> isize { - sys_connect(raddr, lport, rport) -} + pub fn wait(exit_code: &mut i32) -> isize { loop { match sys_waitpid(-1, exit_code as *mut _) {