diff --git a/.dockerignore b/.dockerignore index df3359d..8971c06 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1 +1,2 @@ -*/* \ No newline at end of file +*/* +!rust-toolchain.toml \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index a365475..30731a7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,88 +1,72 @@ # 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 + +# Stage 1 Build QEMU +# - https://www.qemu.org/download/ +# - https://wiki.qemu.org/Hosts/Linux#Building_QEMU_for_Linux +# - https://wiki.qemu.org/Documentation/Platforms/RISCV + +FROM ubuntu:20.04 as build_qemu ARG QEMU_VERSION=7.0.0 -ARG GDB_VERSION=14.1 -ARG HOME=/root -# 0. Install general tools -ARG DEBIAN_FRONTEND=noninteractive -RUN apt-get update && \ - apt-get install -y \ - curl \ - git \ - python3 \ - wget +RUN sed -i 's/archive.ubuntu.com/mirrors.tuna.tsinghua.edu.cn/g' /etc/apt/sources.list && \ + sed -i 's/security.ubuntu.com/mirrors.tuna.tsinghua.edu.cn/g' /etc/apt/sources.list && \ + apt-get update && \ + DEBIAN_FRONTEND=noninteractive apt-get install -y wget build-essential libglib2.0-dev libfdt-dev libpixman-1-dev zlib1g-dev ninja-build -# 1. Set up QEMU RISC-V -# - https://learningos.github.io/rust-based-os-comp2022/0setup-devel-env.html#qemu -# - https://www.qemu.org/download/ -# - https://wiki.qemu.org/Documentation/Platforms/RISCV -# - https://risc-v-getting-started-guide.readthedocs.io/en/latest/linux-qemu.html - -# 1.1. Download source -WORKDIR ${HOME} RUN wget https://download.qemu.org/qemu-${QEMU_VERSION}.tar.xz && \ - tar xvJf qemu-${QEMU_VERSION}.tar.xz - -RUN wget https://ftp.gnu.org/gnu/gdb/gdb-${GDB_VERSION}.tar.xz && \ - tar xvJf gdb-${GDB_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 \ - libncurses5-dev python2 python2-dev libreadline-dev tmux - - -# 1.3. Build and install from source -WORKDIR ${HOME}/qemu-${QEMU_VERSION} -RUN ./configure --target-list=riscv64-softmmu,riscv64-linux-user && \ + tar xf qemu-${QEMU_VERSION}.tar.xz && \ + cd qemu-${QEMU_VERSION} && \ + ./configure --target-list=riscv64-softmmu,riscv64-linux-user && \ make -j$(nproc) && \ make install -WORKDIR ${HOME}/gdb-${GDB_VERSION} -RUN ./configure --prefix=/usr/local --target=riscv64-unknown-elf --enable-tui=yes && \ - make -j$(nproc) && \ - make install +# Stage 2 Set Lab Environment +FROM ubuntu:20.04 as build -# 1.4. Clean up -WORKDIR ${HOME} -RUN rm -rf qemu-${QEMU_VERSION} qemu-${QEMU_VERSION}.tar.xz ${HOME}/gdb-${GDB_VERSION} gdb-${GDB_VERSION}.tar.xz +WORKDIR /tmp -# 1.5. Sanity checking -RUN qemu-system-riscv64 --version && \ - qemu-riscv64 --version +# 2.0. Install general tools +RUN sed -i 's/archive.ubuntu.com/mirrors.tuna.tsinghua.edu.cn/g' /etc/apt/sources.list && \ + apt-get update && \ + DEBIAN_FRONTEND=noninteractive apt-get install -y jq curl git python3 wget build-essential \ + # qemu dependency + libglib2.0-0 libfdt1 libpixman-1-0 zlib1g \ + # gdb + gdb-multiarch -# 2. Set up Rust -# - https://learningos.github.io/rust-based-os-comp2022/0setup-devel-env.html#qemu +# 2.1. Copy qemu +COPY --from=build_qemu /usr/local/bin/* /usr/local/bin + +# 2.2. Install Rust # - 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; + RUSTUP_DIST_SERVER=https://mirrors.ustc.edu.cn/rust-static \ + RUSTUP_UPDATE_ROOT=https://mirrors.ustc.edu.cn/rust-static/rustup +RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | \ + sh -s -- -y --no-modify-path --profile minimal --default-toolchain nightly -# 2.2. Sanity checking -RUN rustup --version && \ +# 2.3. Build env for labs +# See os/Makefile `env:` for example. +# This avoids having to wait for these steps each time using a new container. +COPY rust-toolchain.toml rust-toolchain.toml +RUN rustup target add riscv64gc-unknown-none-elf && \ + cargo install toml-cli cargo-binutils && \ + RUST_VERSION=$(toml get -r rust-toolchain.toml toolchain.channel) && \ + Components=$(toml get -r rust-toolchain.toml toolchain.components | jq -r 'join(" ")') && \ + rustup install $RUST_VERSION && \ + rustup component add --toolchain $RUST_VERSION $Components + +# 2.4. Set GDB +RUN ln -s /usr/bin/gdb-multiarch /usr/bin/riscv64-unknown-elf-gdb + +# Stage 3 Sanity checking +FROM build as test +RUN qemu-system-riscv64 --version && \ + qemu-riscv64 --version && \ + rustup --version && \ cargo --version && \ - rustc --version - -# Ready to go -WORKDIR ${HOME} + rustc --version && \ + riscv64-unknown-elf-gdb --version \ No newline at end of file diff --git a/Makefile b/Makefile index bd267f4..ee4d7d1 100644 --- a/Makefile +++ b/Makefile @@ -1,11 +1,11 @@ -DOCKER_NAME ?= rcore-tutorial-v3 +DOCKER_TAG ?= rcore-tutorial-v3:latest .PHONY: docker build_docker docker: - docker run --rm -it -v ${PWD}:/mnt -w /mnt ${DOCKER_NAME} bash + docker run --rm -it -v ${PWD}:/mnt -w /mnt --name rcore-tutorial-v3 ${DOCKER_TAG} bash build_docker: - docker build -t ${DOCKER_NAME} . + docker build -t ${DOCKER_TAG} --target build . fmt: cd easy-fs; cargo fmt; cd ../easy-fs-fuse cargo fmt; cd ../os ; cargo fmt; cd ../user; cargo fmt; cd .. diff --git a/os/.cargo/config b/os/.cargo/config.toml similarity index 100% rename from os/.cargo/config rename to os/.cargo/config.toml diff --git a/os/Makefile b/os/Makefile index 5956c0e..b0c3463 100644 --- a/os/Makefile +++ b/os/Makefile @@ -90,20 +90,23 @@ fdt: @qemu-system-riscv64 -M 128m -machine virt,dumpdtb=virt.out fdtdump virt.out -run-inner: build +QEMU_NAME := qemu-system-riscv64 +qemu-version-check: + @sh scripts/qemu-ver-check.sh $(QEMU_NAME) + +run-inner: qemu-version-check build @qemu-system-riscv64 $(QEMU_ARGS) -debug: build +debug: qemu-version-check build @tmux new-session -d \ "qemu-system-riscv64 $(QEMU_ARGS) -s -S" && \ tmux split-window -h "riscv64-unknown-elf-gdb -ex 'file $(KERNEL_ELF)' -ex 'set arch riscv:rv64' -ex 'target remote localhost:1234'" && \ tmux -2 attach-session -d - -gdbserver: build +gdbserver: qemu-version-check build @qemu-system-riscv64 $(QEMU_ARGS) -s -S gdbclient: @riscv64-unknown-elf-gdb -ex 'file $(KERNEL_ELF)' -ex 'set arch riscv:rv64' -ex 'target remote localhost:1234' -.PHONY: build env kernel clean disasm disasm-vim run-inner fs-img gdbserver gdbclient fdt +.PHONY: build env kernel clean disasm disasm-vim run-inner fs-img gdbserver gdbclient fdt qemu-version-check diff --git a/os/scripts/qemu-ver-check.sh b/os/scripts/qemu-ver-check.sh new file mode 100644 index 0000000..8c20456 --- /dev/null +++ b/os/scripts/qemu-ver-check.sh @@ -0,0 +1,26 @@ +#!/bin/sh + +# Argument1: The filename of qemu executable, e.g. qemu-system-riscv64 +QEMU_PATH=$(which $1) +RET=$? +MINIMUM_MAJOR_VERSION=7 +RED='\033[0;31m' +GREEN='\033[0;32m' +NC='\033[0m' +if [ $RET != 0 ] +then + echo "$1 not found" + exit 1 +else + QEMU_VERSION=$($1 --version|head -n 1|awk '{print $4}') + MAJOR_VERSION=$(echo $QEMU_VERSION|cut -c1-1) + if [ $MAJOR_VERSION -lt $MINIMUM_MAJOR_VERSION ] + then + echo "${RED}Error: Required major version of QEMU is ${MINIMUM_MAJOR_VERSION}, " \ + "but current is ${QEMU_VERSION}.${NC}" + exit 1 + else + echo "${GREEN}QEMU version is ${QEMU_VERSION}(>=${MINIMUM_MAJOR_VERSION}), OK!${NC}" + exit 0 + fi +fi diff --git a/os/src/mm/memory_set.rs b/os/src/mm/memory_set.rs index 7cdd394..d607c88 100644 --- a/os/src/mm/memory_set.rs +++ b/os/src/mm/memory_set.rs @@ -77,7 +77,7 @@ impl MemorySet { 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); + map_area.copy_data(&self.page_table, data); } self.areas.push(map_area); } @@ -316,7 +316,7 @@ impl MapArea { } /// data: start-aligned but maybe with shorter length /// assume that all frames were cleared before - pub fn copy_data(&mut self, page_table: &mut PageTable, data: &[u8]) { + pub fn copy_data(&mut self, page_table: &PageTable, data: &[u8]) { assert_eq!(self.map_type, MapType::Framed); let mut start: usize = 0; let mut current_vpn = self.vpn_range.get_start(); diff --git a/os/src/task/mod.rs b/os/src/task/mod.rs index ca97e21..fe1343b 100644 --- a/os/src/task/mod.rs +++ b/os/src/task/mod.rs @@ -127,6 +127,13 @@ pub fn exit_current_and_run_next(exit_code: i32) { process_inner.memory_set.recycle_data_pages(); // drop file descriptors process_inner.fd_table.clear(); + // Remove all tasks except for the main thread itself. + // This is because we are still using the kstack under the TCB + // of the main thread. This TCB, including its kstack, will be + // deallocated when the process is reaped via waitpid. + while process_inner.tasks.len() > 1 { + process_inner.tasks.pop(); + } } drop(process); // we do not have to save task context diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 61bbf13..c65d258 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,6 +1,6 @@ [toolchain] profile = "minimal" # use the nightly version of the last stable toolchain, see -channel = "nightly-2024-01-18" -components = ["rust-src", "llvm-tools-preview", "rustfmt", "clippy"] +channel = "nightly-2024-05-01" +components = ["rust-src", "llvm-tools", "rustfmt", "clippy"] targets = ["riscv64gc-unknown-none-elf"] diff --git a/user/.cargo/config b/user/.cargo/config.toml similarity index 100% rename from user/.cargo/config rename to user/.cargo/config.toml diff --git a/user/src/bin/adder_peterson_spin.rs b/user/src/bin/adder_peterson_spin.rs index 1e9af5d..44e8096 100644 --- a/user/src/bin/adder_peterson_spin.rs +++ b/user/src/bin/adder_peterson_spin.rs @@ -8,7 +8,7 @@ extern crate user_lib; extern crate alloc; use alloc::vec::Vec; -use core::ptr::{addr_of, addr_of_mut, read_volatile}; +use core::ptr::addr_of_mut; use core::sync::atomic::{compiler_fence, Ordering}; use user_lib::{exit, get_time, thread_create, waittid}; @@ -39,7 +39,7 @@ unsafe fn lock(id: usize) { // Otherwise the compiler will assume that they will never // be changed on this thread. Thus, they will be accessed // only once! - while read_volatile(addr_of!(FLAG[j])) && read_volatile(addr_of!(TURN)) == j {} + while vload!(FLAG[j]) && vload!(TURN) == j {} } unsafe fn unlock(id: usize) { diff --git a/user/src/bin/adder_simple_spin.rs b/user/src/bin/adder_simple_spin.rs index 57d9fa5..be99d28 100644 --- a/user/src/bin/adder_simple_spin.rs +++ b/user/src/bin/adder_simple_spin.rs @@ -6,7 +6,7 @@ extern crate user_lib; extern crate alloc; use alloc::vec::Vec; -use core::ptr::{addr_of, addr_of_mut, read_volatile}; +use core::ptr::addr_of_mut; use user_lib::{exit, get_time, thread_create, waittid}; static mut A: usize = 0; @@ -25,7 +25,7 @@ unsafe fn critical_section(t: &mut usize) { } unsafe fn lock() { - while read_volatile(addr_of!(OCCUPIED)) {} + while vload!(OCCUPIED) {} OCCUPIED = true; } diff --git a/user/src/bin/eisenberg.rs b/user/src/bin/eisenberg.rs index b16d3a7..49a1d45 100644 --- a/user/src/bin/eisenberg.rs +++ b/user/src/bin/eisenberg.rs @@ -8,7 +8,6 @@ extern crate core; use alloc::vec::Vec; use core::{ - ptr::{addr_of, addr_of_mut, read_volatile, write_volatile}, sync::atomic::{AtomicUsize, Ordering}, }; use user_lib::{exit, sleep, thread_create, waittid}; @@ -44,15 +43,15 @@ unsafe fn eisenberg_enter_critical(id: usize) { /* announce that we want to enter */ loop { println!("Thread[{}] try enter", id); - write_volatile(addr_of_mut!(FLAG[id]), FlagState::Want); + vstore!(FLAG[id], FlagState::Want); loop { /* check if any with higher priority is `Want` or `In` */ let mut prior_thread: Option = None; - let turn = read_volatile(addr_of!(TURN)); + let turn = vload!(TURN); let ring_id = if id < turn { id + THREAD_NUM } else { id }; // FLAG.iter() may lead to some errors, use for-loop instead for i in turn..ring_id { - if read_volatile(addr_of!(FLAG[i % THREAD_NUM])) != FlagState::Out { + if vload!(FLAG[i % THREAD_NUM]) != FlagState::Out { prior_thread = Some(i % THREAD_NUM); break; } @@ -68,13 +67,13 @@ unsafe fn eisenberg_enter_critical(id: usize) { sleep(1); } /* now tentatively claim the resource */ - write_volatile(addr_of_mut!(FLAG[id]), FlagState::In); + vstore!(FLAG[id], FlagState::In); /* enforce the order of `claim` and `conflict check`*/ memory_fence!(); /* check if anthor thread is also `In`, which imply a conflict*/ let mut conflict = false; for i in 0..THREAD_NUM { - if i != id && read_volatile(addr_of!(FLAG[i])) == FlagState::In { + if i != id && vload!(FLAG[i]) == FlagState::In { conflict = true; } } @@ -85,7 +84,7 @@ unsafe fn eisenberg_enter_critical(id: usize) { /* no need to sleep */ } /* clain the trun */ - write_volatile(addr_of_mut!(TURN), id); + vstore!(TURN, id); println!("Thread[{}] enter", id); } @@ -95,14 +94,14 @@ unsafe fn eisenberg_exit_critical(id: usize) { let ring_id = id + THREAD_NUM; for i in (id + 1)..ring_id { let idx = i % THREAD_NUM; - if read_volatile(addr_of!(FLAG[idx])) == FlagState::Want { + if vload!(FLAG[idx]) == FlagState::Want { next = idx; break; } } - write_volatile(addr_of_mut!(TURN), next); + vstore!(TURN, next); /* All done */ - write_volatile(addr_of_mut!(FLAG[id]), FlagState::Out); + vstore!(FLAG[id], FlagState::Out); println!("Thread[{}] exit, give turn to {}", id, next); } diff --git a/user/src/bin/gui_move.rs b/user/src/bin/gui_move.rs new file mode 100644 index 0000000..240ff8f --- /dev/null +++ b/user/src/bin/gui_move.rs @@ -0,0 +1,82 @@ +#![no_std] +#![no_main] + +extern crate user_lib; +extern crate alloc; + +use user_lib::console::getchar; +use user_lib::{Display, VIRTGPU_XRES, VIRTGPU_YRES}; + +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; + +const INIT_X: i32 = 640; +const INIT_Y: i32 = 400; +const RECT_SIZE: u32 = 40; + +pub struct DrawingBoard { + disp: Display, + latest_pos: Point, +} + +impl DrawingBoard { + pub fn new() -> Self { + Self { + disp: Display::new(Size::new(VIRTGPU_XRES, VIRTGPU_YRES)), + 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) { + let new_x = self.latest_pos.x + dx; + let new_y = self.latest_pos.y + dy; + let r = (RECT_SIZE / 2) as i32; + if new_x > r && new_x + r < (VIRTGPU_XRES as i32) && new_y > r && new_y + r < (VIRTGPU_YRES as i32) { + self.unpaint(); + self.latest_pos.x = new_x; + self.latest_pos.y = new_y; + self.paint(); + } + } +} + +const LF: u8 = 0x0au8; +const CR: u8 = 0x0du8; +#[no_mangle] +pub fn main() -> i32 { + let mut board = DrawingBoard::new(); + let _ = board.disp.clear(Rgb888::BLACK).unwrap(); + board.disp.flush(); + loop { + let c = getchar(); + if c == LF || c == CR { + break; + } + let mut moved = true; + match c { + b'w' => board.move_rect(0, -10), + b'a' => board.move_rect(-10, 0), + b's' => board.move_rect(0, 10), + b'd' => board.move_rect(10, 0), + _ => moved = false, + } + if moved { + board.disp.flush(); + } + } + 0 +} diff --git a/user/src/bin/gui_rect.rs b/user/src/bin/gui_shape.rs similarity index 78% rename from user/src/bin/gui_rect.rs rename to user/src/bin/gui_shape.rs index 1f377de..df03df3 100644 --- a/user/src/bin/gui_rect.rs +++ b/user/src/bin/gui_shape.rs @@ -44,18 +44,6 @@ impl DrawingBoard { .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, 10)) - .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(); - } } #[no_mangle] @@ -64,8 +52,8 @@ pub fn main() -> i32 { let _ = board.disp.clear(Rgb888::BLACK).unwrap(); for _ in 0..5 { board.latest_pos.x += RECT_SIZE as i32 + 20; - //board.latest_pos.y += i; board.paint(); } + board.disp.flush(); 0 } diff --git a/user/src/bin/gui_snake.rs b/user/src/bin/gui_snake.rs index 0411824..6dd4052 100644 --- a/user/src/bin/gui_snake.rs +++ b/user/src/bin/gui_snake.rs @@ -328,7 +328,7 @@ const CR: u8 = 0x0du8; #[no_mangle] pub fn main() -> i32 { 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 mut game = SnakeGame::<20, Rgb888>::new(1280, 800, 20, 20, Rgb888::RED, Rgb888::YELLOW, 200); let _ = disp.clear(Rgb888::BLACK).unwrap(); loop { if key_pressed() { @@ -345,7 +345,8 @@ pub fn main() -> i32 { } let _ = disp.clear(Rgb888::BLACK).unwrap(); game.draw(&mut disp); - sleep(10); + disp.flush(); + sleep(40); } 0 } diff --git a/user/src/bin/gui_simple.rs b/user/src/bin/gui_tri.rs similarity index 97% rename from user/src/bin/gui_simple.rs rename to user/src/bin/gui_tri.rs index f30b1fc..69d47f5 100644 --- a/user/src/bin/gui_simple.rs +++ b/user/src/bin/gui_tri.rs @@ -19,5 +19,6 @@ pub fn main() -> i32 { } } }); + disp.flush(); 0 } diff --git a/user/src/bin/gui_uart.rs b/user/src/bin/gui_uart.rs deleted file mode 100644 index 8e9c9b8..0000000 --- a/user/src/bin/gui_uart.rs +++ /dev/null @@ -1,125 +0,0 @@ -#![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(); - let _ = board.disp.clear(Rgb888::BLACK).unwrap(); - 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/peterson.rs b/user/src/bin/peterson.rs index c370c87..e03e2a4 100644 --- a/user/src/bin/peterson.rs +++ b/user/src/bin/peterson.rs @@ -7,7 +7,6 @@ extern crate alloc; extern crate core; use alloc::vec::Vec; -use core::ptr::{addr_of, addr_of_mut, read_volatile, write_volatile}; use core::sync::atomic::{AtomicUsize, Ordering}; use user_lib::{exit, sleep, thread_create, waittid}; const N: usize = 1000; @@ -30,10 +29,10 @@ fn critical_test_exit() { unsafe fn peterson_enter_critical(id: usize, peer_id: usize) { // println!("Thread[{}] try enter", id); - write_volatile(addr_of_mut!(FLAG[id]), true); - write_volatile(addr_of_mut!(TURN), peer_id); + vstore!(FLAG[id], true); + vstore!(TURN, peer_id); memory_fence!(); - while read_volatile(addr_of!(FLAG[peer_id])) && read_volatile(addr_of!(TURN)) == peer_id { + while vload!(FLAG[peer_id]) && vload!(TURN) == peer_id { // println!("Thread[{}] enter fail", id); sleep(1); // println!("Thread[{}] retry enter", id); @@ -42,7 +41,7 @@ unsafe fn peterson_enter_critical(id: usize, peer_id: usize) { } unsafe fn peterson_exit_critical(id: usize) { - write_volatile(addr_of_mut!(FLAG[id]), false); + vstore!(FLAG[id], false); // println!("Thread[{}] exit", id); } diff --git a/user/src/io.rs b/user/src/io.rs index 30e7a1c..d2c2a0a 100644 --- a/user/src/io.rs +++ b/user/src/io.rs @@ -32,6 +32,8 @@ impl Display { } pub fn paint_on_framebuffer(&mut self, p: impl FnOnce(&mut [u8]) -> ()) { p(self.framebuffer()); + } + pub fn flush(&self) { framebuffer_flush(); } } @@ -60,7 +62,6 @@ impl DrawTarget for Display { 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 ca6181f..8c709fc 100644 --- a/user/src/lib.rs +++ b/user/src/lib.rs @@ -70,15 +70,17 @@ fn main(_argc: usize, _argv: &[&str]) -> i32 { #[macro_export] macro_rules! vstore { - ($var_ref: expr, $value: expr) => { - unsafe { core::intrinsics::volatile_store($var_ref as *const _ as _, $value) } + ($var: expr, $value: expr) => { + // unsafe { core::intrinsics::volatile_store($var_ref as *const _ as _, $value) } + unsafe { core::ptr::write_volatile(core::ptr::addr_of_mut!($var), $value); } }; } #[macro_export] macro_rules! vload { - ($var_ref: expr) => { - unsafe { core::intrinsics::volatile_load($var_ref as *const _ as _) } + ($var: expr) => { + // unsafe { core::intrinsics::volatile_load($var_ref as *const _ as _) } + unsafe { core::ptr::read_volatile(core::ptr::addr_of!($var)) } }; }