diff --git a/.dockerignore b/.dockerignore index 8971c06..df3359d 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,2 +1 @@ -*/* -!rust-toolchain.toml \ No newline at end of file +*/* \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 30731a7..a365475 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,72 +1,88 @@ # syntax=docker/dockerfile:1 - -# Stage 1 Build QEMU -# - https://www.qemu.org/download/ -# - https://wiki.qemu.org/Hosts/Linux#Building_QEMU_for_Linux -# - https://wiki.qemu.org/Documentation/Platforms/RISCV - -FROM ubuntu:20.04 as build_qemu +# This Dockerfile is adapted from https://github.com/LearningOS/rCore-Tutorial-v3/blob/main/Dockerfile +# with the following major updates: +# - ubuntu 18.04 -> 20.04 +# - qemu 5.0.0 -> 7.0.0 +# - Extensive comments linking to relevant documentation +FROM ubuntu:20.04 ARG QEMU_VERSION=7.0.0 +ARG GDB_VERSION=14.1 +ARG HOME=/root -RUN sed -i 's/archive.ubuntu.com/mirrors.tuna.tsinghua.edu.cn/g' /etc/apt/sources.list && \ - sed -i 's/security.ubuntu.com/mirrors.tuna.tsinghua.edu.cn/g' /etc/apt/sources.list && \ - apt-get update && \ - DEBIAN_FRONTEND=noninteractive apt-get install -y wget build-essential libglib2.0-dev libfdt-dev libpixman-1-dev zlib1g-dev ninja-build +# 0. Install general tools +ARG DEBIAN_FRONTEND=noninteractive +RUN apt-get update && \ + apt-get install -y \ + curl \ + git \ + python3 \ + wget +# 1. Set up QEMU RISC-V +# - https://learningos.github.io/rust-based-os-comp2022/0setup-devel-env.html#qemu +# - https://www.qemu.org/download/ +# - https://wiki.qemu.org/Documentation/Platforms/RISCV +# - https://risc-v-getting-started-guide.readthedocs.io/en/latest/linux-qemu.html + +# 1.1. Download source +WORKDIR ${HOME} RUN wget https://download.qemu.org/qemu-${QEMU_VERSION}.tar.xz && \ - tar xf qemu-${QEMU_VERSION}.tar.xz && \ - cd qemu-${QEMU_VERSION} && \ - ./configure --target-list=riscv64-softmmu,riscv64-linux-user && \ + tar xvJf qemu-${QEMU_VERSION}.tar.xz + +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 && \ make -j$(nproc) && \ make install -# Stage 2 Set Lab Environment -FROM ubuntu:20.04 as build +WORKDIR ${HOME}/gdb-${GDB_VERSION} +RUN ./configure --prefix=/usr/local --target=riscv64-unknown-elf --enable-tui=yes && \ + make -j$(nproc) && \ + make install -WORKDIR /tmp +# 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 -# 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 +# 1.5. Sanity checking +RUN qemu-system-riscv64 --version && \ + qemu-riscv64 --version -# 2.1. Copy qemu -COPY --from=build_qemu /usr/local/bin/* /usr/local/bin - -# 2.2. Install Rust +# 2. Set up Rust +# - https://learningos.github.io/rust-based-os-comp2022/0setup-devel-env.html#qemu # - https://www.rust-lang.org/tools/install +# - https://github.com/rust-lang/docker-rust/blob/master/Dockerfile-debian.template + +# 2.1. Install ENV RUSTUP_HOME=/usr/local/rustup \ CARGO_HOME=/usr/local/cargo \ PATH=/usr/local/cargo/bin:$PATH \ - RUSTUP_DIST_SERVER=https://mirrors.ustc.edu.cn/rust-static \ - RUSTUP_UPDATE_ROOT=https://mirrors.ustc.edu.cn/rust-static/rustup -RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | \ - sh -s -- -y --no-modify-path --profile minimal --default-toolchain nightly + RUST_VERSION=nightly +RUN set -eux; \ + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs -o rustup-init; \ + chmod +x rustup-init; \ + ./rustup-init -y --no-modify-path --profile minimal --default-toolchain $RUST_VERSION; \ + rm rustup-init; \ + chmod -R a+w $RUSTUP_HOME $CARGO_HOME; -# 2.3. Build env for labs -# See os/Makefile `env:` for example. -# This avoids having to wait for these steps each time using a new container. -COPY rust-toolchain.toml rust-toolchain.toml -RUN rustup target add riscv64gc-unknown-none-elf && \ - cargo install toml-cli cargo-binutils && \ - RUST_VERSION=$(toml get -r rust-toolchain.toml toolchain.channel) && \ - Components=$(toml get -r rust-toolchain.toml toolchain.components | jq -r 'join(" ")') && \ - rustup install $RUST_VERSION && \ - rustup component add --toolchain $RUST_VERSION $Components - -# 2.4. Set GDB -RUN ln -s /usr/bin/gdb-multiarch /usr/bin/riscv64-unknown-elf-gdb - -# Stage 3 Sanity checking -FROM build as test -RUN qemu-system-riscv64 --version && \ - qemu-riscv64 --version && \ - rustup --version && \ +# 2.2. Sanity checking +RUN rustup --version && \ cargo --version && \ - rustc --version && \ - riscv64-unknown-elf-gdb --version \ No newline at end of file + rustc --version + +# Ready to go +WORKDIR ${HOME} diff --git a/Makefile b/Makefile index ee4d7d1..bd267f4 100644 --- a/Makefile +++ b/Makefile @@ -1,11 +1,11 @@ -DOCKER_TAG ?= rcore-tutorial-v3:latest +DOCKER_NAME ?= rcore-tutorial-v3 .PHONY: docker build_docker docker: - docker run --rm -it -v ${PWD}:/mnt -w /mnt --name rcore-tutorial-v3 ${DOCKER_TAG} bash + docker run --rm -it -v ${PWD}:/mnt -w /mnt ${DOCKER_NAME} bash build_docker: - docker build -t ${DOCKER_TAG} --target build . + docker build -t ${DOCKER_NAME} . fmt: cd 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.toml b/os/.cargo/config similarity index 100% rename from os/.cargo/config.toml rename to os/.cargo/config diff --git a/os/Makefile b/os/Makefile index b0c3463..5956c0e 100644 --- a/os/Makefile +++ b/os/Makefile @@ -90,23 +90,20 @@ fdt: @qemu-system-riscv64 -M 128m -machine virt,dumpdtb=virt.out fdtdump virt.out -QEMU_NAME := qemu-system-riscv64 -qemu-version-check: - @sh scripts/qemu-ver-check.sh $(QEMU_NAME) - -run-inner: qemu-version-check build +run-inner: build @qemu-system-riscv64 $(QEMU_ARGS) -debug: qemu-version-check build +debug: 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: qemu-version-check build + +gdbserver: 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 qemu-version-check +.PHONY: build env kernel clean disasm disasm-vim run-inner fs-img gdbserver gdbclient fdt diff --git a/os/scripts/qemu-ver-check.sh b/os/scripts/qemu-ver-check.sh deleted file mode 100644 index 8c20456..0000000 --- a/os/scripts/qemu-ver-check.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/sh - -# Argument1: The filename of qemu executable, e.g. qemu-system-riscv64 -QEMU_PATH=$(which $1) -RET=$? -MINIMUM_MAJOR_VERSION=7 -RED='\033[0;31m' -GREEN='\033[0;32m' -NC='\033[0m' -if [ $RET != 0 ] -then - echo "$1 not found" - exit 1 -else - QEMU_VERSION=$($1 --version|head -n 1|awk '{print $4}') - MAJOR_VERSION=$(echo $QEMU_VERSION|cut -c1-1) - if [ $MAJOR_VERSION -lt $MINIMUM_MAJOR_VERSION ] - then - echo "${RED}Error: Required major version of QEMU is ${MINIMUM_MAJOR_VERSION}, " \ - "but current is ${QEMU_VERSION}.${NC}" - exit 1 - else - echo "${GREEN}QEMU version is ${QEMU_VERSION}(>=${MINIMUM_MAJOR_VERSION}), OK!${NC}" - exit 0 - fi -fi diff --git a/os/src/mm/memory_set.rs b/os/src/mm/memory_set.rs index d607c88..7cdd394 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(&self.page_table, data); + map_area.copy_data(&mut 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: &PageTable, data: &[u8]) { + pub fn copy_data(&mut self, page_table: &mut 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 fe1343b..ca97e21 100644 --- a/os/src/task/mod.rs +++ b/os/src/task/mod.rs @@ -127,13 +127,6 @@ 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 c65d258..61bbf13 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-05-01" -components = ["rust-src", "llvm-tools", "rustfmt", "clippy"] +channel = "nightly-2024-01-18" +components = ["rust-src", "llvm-tools-preview", "rustfmt", "clippy"] targets = ["riscv64gc-unknown-none-elf"] diff --git a/user/.cargo/config.toml b/user/.cargo/config similarity index 100% rename from user/.cargo/config.toml rename to user/.cargo/config diff --git a/user/src/bin/adder_peterson_spin.rs b/user/src/bin/adder_peterson_spin.rs index 44e8096..1e9af5d 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_mut; +use core::ptr::{addr_of, addr_of_mut, read_volatile}; 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 vload!(FLAG[j]) && vload!(TURN) == j {} + while read_volatile(addr_of!(FLAG[j])) && read_volatile(addr_of!(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 be99d28..57d9fa5 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_mut; +use core::ptr::{addr_of, addr_of_mut, read_volatile}; 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 vload!(OCCUPIED) {} + while read_volatile(addr_of!(OCCUPIED)) {} OCCUPIED = true; } diff --git a/user/src/bin/eisenberg.rs b/user/src/bin/eisenberg.rs index 49a1d45..b16d3a7 100644 --- a/user/src/bin/eisenberg.rs +++ b/user/src/bin/eisenberg.rs @@ -8,6 +8,7 @@ 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}; @@ -43,15 +44,15 @@ unsafe fn eisenberg_enter_critical(id: usize) { /* announce that we want to enter */ loop { println!("Thread[{}] try enter", id); - vstore!(FLAG[id], FlagState::Want); + write_volatile(addr_of_mut!(FLAG[id]), FlagState::Want); loop { /* check if any with higher priority is `Want` or `In` */ let mut prior_thread: Option = None; - let turn = vload!(TURN); + let turn = read_volatile(addr_of!(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 vload!(FLAG[i % THREAD_NUM]) != FlagState::Out { + if read_volatile(addr_of!(FLAG[i % THREAD_NUM])) != FlagState::Out { prior_thread = Some(i % THREAD_NUM); break; } @@ -67,13 +68,13 @@ unsafe fn eisenberg_enter_critical(id: usize) { sleep(1); } /* now tentatively claim the resource */ - vstore!(FLAG[id], FlagState::In); + write_volatile(addr_of_mut!(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 && vload!(FLAG[i]) == FlagState::In { + if i != id && read_volatile(addr_of!(FLAG[i])) == FlagState::In { conflict = true; } } @@ -84,7 +85,7 @@ unsafe fn eisenberg_enter_critical(id: usize) { /* no need to sleep */ } /* clain the trun */ - vstore!(TURN, id); + write_volatile(addr_of_mut!(TURN), id); println!("Thread[{}] enter", id); } @@ -94,14 +95,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 vload!(FLAG[idx]) == FlagState::Want { + if read_volatile(addr_of!(FLAG[idx])) == FlagState::Want { next = idx; break; } } - vstore!(TURN, next); + write_volatile(addr_of_mut!(TURN), next); /* All done */ - vstore!(FLAG[id], FlagState::Out); + write_volatile(addr_of_mut!(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 deleted file mode 100644 index 240ff8f..0000000 --- a/user/src/bin/gui_move.rs +++ /dev/null @@ -1,82 +0,0 @@ -#![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_shape.rs b/user/src/bin/gui_rect.rs similarity index 78% rename from user/src/bin/gui_shape.rs rename to user/src/bin/gui_rect.rs index df03df3..1f377de 100644 --- a/user/src/bin/gui_shape.rs +++ b/user/src/bin/gui_rect.rs @@ -44,6 +44,18 @@ 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] @@ -52,8 +64,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_tri.rs b/user/src/bin/gui_simple.rs similarity index 97% rename from user/src/bin/gui_tri.rs rename to user/src/bin/gui_simple.rs index 69d47f5..f30b1fc 100644 --- a/user/src/bin/gui_tri.rs +++ b/user/src/bin/gui_simple.rs @@ -19,6 +19,5 @@ pub fn main() -> i32 { } } }); - disp.flush(); 0 } diff --git a/user/src/bin/gui_snake.rs b/user/src/bin/gui_snake.rs index 6dd4052..0411824 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, 200); + 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() { @@ -345,8 +345,7 @@ pub fn main() -> i32 { } let _ = disp.clear(Rgb888::BLACK).unwrap(); game.draw(&mut disp); - disp.flush(); - sleep(40); + sleep(10); } 0 } diff --git a/user/src/bin/gui_uart.rs b/user/src/bin/gui_uart.rs new file mode 100644 index 0000000..8e9c9b8 --- /dev/null +++ b/user/src/bin/gui_uart.rs @@ -0,0 +1,125 @@ +#![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 e03e2a4..c370c87 100644 --- a/user/src/bin/peterson.rs +++ b/user/src/bin/peterson.rs @@ -7,6 +7,7 @@ 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; @@ -29,10 +30,10 @@ fn critical_test_exit() { unsafe fn peterson_enter_critical(id: usize, peer_id: usize) { // println!("Thread[{}] try enter", id); - vstore!(FLAG[id], true); - vstore!(TURN, peer_id); + write_volatile(addr_of_mut!(FLAG[id]), true); + write_volatile(addr_of_mut!(TURN), peer_id); memory_fence!(); - while vload!(FLAG[peer_id]) && vload!(TURN) == peer_id { + while read_volatile(addr_of!(FLAG[peer_id])) && read_volatile(addr_of!(TURN)) == peer_id { // println!("Thread[{}] enter fail", id); sleep(1); // println!("Thread[{}] retry enter", id); @@ -41,7 +42,7 @@ unsafe fn peterson_enter_critical(id: usize, peer_id: usize) { } unsafe fn peterson_exit_critical(id: usize) { - vstore!(FLAG[id], false); + write_volatile(addr_of_mut!(FLAG[id]), false); // println!("Thread[{}] exit", id); } diff --git a/user/src/io.rs b/user/src/io.rs index d2c2a0a..30e7a1c 100644 --- a/user/src/io.rs +++ b/user/src/io.rs @@ -32,8 +32,6 @@ impl Display { } pub fn paint_on_framebuffer(&mut self, p: impl FnOnce(&mut [u8]) -> ()) { p(self.framebuffer()); - } - pub fn flush(&self) { framebuffer_flush(); } } @@ -62,6 +60,7 @@ 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 8c709fc..ca6181f 100644 --- a/user/src/lib.rs +++ b/user/src/lib.rs @@ -70,17 +70,15 @@ fn main(_argc: usize, _argv: &[&str]) -> i32 { #[macro_export] macro_rules! vstore { - ($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); } + ($var_ref: expr, $value: expr) => { + unsafe { core::intrinsics::volatile_store($var_ref as *const _ as _, $value) } }; } #[macro_export] macro_rules! vload { - ($var: expr) => { - // unsafe { core::intrinsics::volatile_load($var_ref as *const _ as _) } - unsafe { core::ptr::read_volatile(core::ptr::addr_of!($var)) } + ($var_ref: expr) => { + unsafe { core::intrinsics::volatile_load($var_ref as *const _ as _) } }; }