Compare commits
11 commits
35948f351c
...
8f24c0f16a
Author | SHA1 | Date | |
---|---|---|---|
![]() |
8f24c0f16a | ||
![]() |
9c3a12a342 | ||
![]() |
60483378d7 | ||
![]() |
53f615b30f | ||
![]() |
dc1f9c9585 | ||
![]() |
4b77f293a6 | ||
![]() |
2cd7a39e48 | ||
![]() |
88a4a0ad11 | ||
![]() |
3fb0dbcf06 | ||
![]() |
a0a1cfb338 | ||
![]() |
4709a3f2a6 |
21 changed files with 216 additions and 247 deletions
|
@ -1 +1,2 @@
|
||||||
*/*
|
*/*
|
||||||
|
!rust-toolchain.toml
|
124
Dockerfile
124
Dockerfile
|
@ -1,88 +1,72 @@
|
||||||
# syntax=docker/dockerfile:1
|
# syntax=docker/dockerfile:1
|
||||||
# This Dockerfile is adapted from https://github.com/LearningOS/rCore-Tutorial-v3/blob/main/Dockerfile
|
|
||||||
# with the following major updates:
|
# Stage 1 Build QEMU
|
||||||
# - ubuntu 18.04 -> 20.04
|
# - https://www.qemu.org/download/
|
||||||
# - qemu 5.0.0 -> 7.0.0
|
# - https://wiki.qemu.org/Hosts/Linux#Building_QEMU_for_Linux
|
||||||
# - Extensive comments linking to relevant documentation
|
# - https://wiki.qemu.org/Documentation/Platforms/RISCV
|
||||||
FROM ubuntu:20.04
|
|
||||||
|
FROM ubuntu:20.04 as build_qemu
|
||||||
|
|
||||||
ARG QEMU_VERSION=7.0.0
|
ARG QEMU_VERSION=7.0.0
|
||||||
ARG GDB_VERSION=14.1
|
|
||||||
ARG HOME=/root
|
|
||||||
|
|
||||||
# 0. Install general tools
|
RUN sed -i 's/archive.ubuntu.com/mirrors.tuna.tsinghua.edu.cn/g' /etc/apt/sources.list && \
|
||||||
ARG DEBIAN_FRONTEND=noninteractive
|
sed -i 's/security.ubuntu.com/mirrors.tuna.tsinghua.edu.cn/g' /etc/apt/sources.list && \
|
||||||
RUN apt-get update && \
|
apt-get update && \
|
||||||
apt-get install -y \
|
DEBIAN_FRONTEND=noninteractive apt-get install -y wget build-essential libglib2.0-dev libfdt-dev libpixman-1-dev zlib1g-dev ninja-build
|
||||||
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 && \
|
RUN wget https://download.qemu.org/qemu-${QEMU_VERSION}.tar.xz && \
|
||||||
tar xvJf qemu-${QEMU_VERSION}.tar.xz
|
tar xf qemu-${QEMU_VERSION}.tar.xz && \
|
||||||
|
cd qemu-${QEMU_VERSION} && \
|
||||||
RUN wget https://ftp.gnu.org/gnu/gdb/gdb-${GDB_VERSION}.tar.xz && \
|
./configure --target-list=riscv64-softmmu,riscv64-linux-user && \
|
||||||
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 -j$(nproc) && \
|
||||||
make install
|
make install
|
||||||
|
|
||||||
WORKDIR ${HOME}/gdb-${GDB_VERSION}
|
# Stage 2 Set Lab Environment
|
||||||
RUN ./configure --prefix=/usr/local --target=riscv64-unknown-elf --enable-tui=yes && \
|
FROM ubuntu:20.04 as build
|
||||||
make -j$(nproc) && \
|
|
||||||
make install
|
|
||||||
|
|
||||||
# 1.4. Clean up
|
WORKDIR /tmp
|
||||||
WORKDIR ${HOME}
|
|
||||||
RUN rm -rf qemu-${QEMU_VERSION} qemu-${QEMU_VERSION}.tar.xz ${HOME}/gdb-${GDB_VERSION} gdb-${GDB_VERSION}.tar.xz
|
|
||||||
|
|
||||||
# 1.5. Sanity checking
|
# 2.0. Install general tools
|
||||||
RUN qemu-system-riscv64 --version && \
|
RUN sed -i 's/archive.ubuntu.com/mirrors.tuna.tsinghua.edu.cn/g' /etc/apt/sources.list && \
|
||||||
qemu-riscv64 --version
|
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
|
# 2.1. Copy qemu
|
||||||
# - https://learningos.github.io/rust-based-os-comp2022/0setup-devel-env.html#qemu
|
COPY --from=build_qemu /usr/local/bin/* /usr/local/bin
|
||||||
|
|
||||||
|
# 2.2. Install Rust
|
||||||
# - https://www.rust-lang.org/tools/install
|
# - 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 \
|
ENV RUSTUP_HOME=/usr/local/rustup \
|
||||||
CARGO_HOME=/usr/local/cargo \
|
CARGO_HOME=/usr/local/cargo \
|
||||||
PATH=/usr/local/cargo/bin:$PATH \
|
PATH=/usr/local/cargo/bin:$PATH \
|
||||||
RUST_VERSION=nightly
|
RUSTUP_DIST_SERVER=https://mirrors.ustc.edu.cn/rust-static \
|
||||||
RUN set -eux; \
|
RUSTUP_UPDATE_ROOT=https://mirrors.ustc.edu.cn/rust-static/rustup
|
||||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs -o rustup-init; \
|
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | \
|
||||||
chmod +x rustup-init; \
|
sh -s -- -y --no-modify-path --profile minimal --default-toolchain nightly
|
||||||
./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
|
# 2.3. Build env for labs
|
||||||
RUN rustup --version && \
|
# 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 && \
|
cargo --version && \
|
||||||
rustc --version
|
rustc --version && \
|
||||||
|
riscv64-unknown-elf-gdb --version
|
||||||
# Ready to go
|
|
||||||
WORKDIR ${HOME}
|
|
6
Makefile
6
Makefile
|
@ -1,11 +1,11 @@
|
||||||
DOCKER_NAME ?= rcore-tutorial-v3
|
DOCKER_TAG ?= rcore-tutorial-v3:latest
|
||||||
.PHONY: docker build_docker
|
.PHONY: docker build_docker
|
||||||
|
|
||||||
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:
|
build_docker:
|
||||||
docker build -t ${DOCKER_NAME} .
|
docker build -t ${DOCKER_TAG} --target build .
|
||||||
|
|
||||||
fmt:
|
fmt:
|
||||||
cd easy-fs; cargo fmt; cd ../easy-fs-fuse cargo fmt; cd ../os ; cargo fmt; cd ../user; cargo fmt; cd ..
|
cd easy-fs; cargo fmt; cd ../easy-fs-fuse cargo fmt; cd ../os ; cargo fmt; cd ../user; cargo fmt; cd ..
|
||||||
|
|
13
os/Makefile
13
os/Makefile
|
@ -90,20 +90,23 @@ fdt:
|
||||||
@qemu-system-riscv64 -M 128m -machine virt,dumpdtb=virt.out
|
@qemu-system-riscv64 -M 128m -machine virt,dumpdtb=virt.out
|
||||||
fdtdump 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)
|
@qemu-system-riscv64 $(QEMU_ARGS)
|
||||||
|
|
||||||
debug: build
|
debug: qemu-version-check build
|
||||||
@tmux new-session -d \
|
@tmux new-session -d \
|
||||||
"qemu-system-riscv64 $(QEMU_ARGS) -s -S" && \
|
"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 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
|
tmux -2 attach-session -d
|
||||||
|
|
||||||
|
gdbserver: qemu-version-check build
|
||||||
gdbserver: build
|
|
||||||
@qemu-system-riscv64 $(QEMU_ARGS) -s -S
|
@qemu-system-riscv64 $(QEMU_ARGS) -s -S
|
||||||
|
|
||||||
gdbclient:
|
gdbclient:
|
||||||
@riscv64-unknown-elf-gdb -ex 'file $(KERNEL_ELF)' -ex 'set arch riscv:rv64' -ex 'target remote localhost:1234'
|
@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
|
||||||
|
|
26
os/scripts/qemu-ver-check.sh
Normal file
26
os/scripts/qemu-ver-check.sh
Normal file
|
@ -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
|
|
@ -77,7 +77,7 @@ impl MemorySet {
|
||||||
pub fn push(&mut self, mut map_area: MapArea, data: Option<&[u8]>) {
|
pub fn push(&mut self, mut map_area: MapArea, data: Option<&[u8]>) {
|
||||||
map_area.map(&mut self.page_table);
|
map_area.map(&mut self.page_table);
|
||||||
if let Some(data) = data {
|
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);
|
self.areas.push(map_area);
|
||||||
}
|
}
|
||||||
|
@ -316,7 +316,7 @@ impl MapArea {
|
||||||
}
|
}
|
||||||
/// data: start-aligned but maybe with shorter length
|
/// data: start-aligned but maybe with shorter length
|
||||||
/// assume that all frames were cleared before
|
/// 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);
|
assert_eq!(self.map_type, MapType::Framed);
|
||||||
let mut start: usize = 0;
|
let mut start: usize = 0;
|
||||||
let mut current_vpn = self.vpn_range.get_start();
|
let mut current_vpn = self.vpn_range.get_start();
|
||||||
|
|
|
@ -127,6 +127,13 @@ pub fn exit_current_and_run_next(exit_code: i32) {
|
||||||
process_inner.memory_set.recycle_data_pages();
|
process_inner.memory_set.recycle_data_pages();
|
||||||
// drop file descriptors
|
// drop file descriptors
|
||||||
process_inner.fd_table.clear();
|
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);
|
drop(process);
|
||||||
// we do not have to save task context
|
// we do not have to save task context
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[toolchain]
|
[toolchain]
|
||||||
profile = "minimal"
|
profile = "minimal"
|
||||||
# use the nightly version of the last stable toolchain, see <https://forge.rust-lang.org/>
|
# use the nightly version of the last stable toolchain, see <https://forge.rust-lang.org/>
|
||||||
channel = "nightly-2024-01-18"
|
channel = "nightly-2024-05-01"
|
||||||
components = ["rust-src", "llvm-tools-preview", "rustfmt", "clippy"]
|
components = ["rust-src", "llvm-tools", "rustfmt", "clippy"]
|
||||||
targets = ["riscv64gc-unknown-none-elf"]
|
targets = ["riscv64gc-unknown-none-elf"]
|
||||||
|
|
|
@ -8,7 +8,7 @@ extern crate user_lib;
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
use alloc::vec::Vec;
|
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 core::sync::atomic::{compiler_fence, Ordering};
|
||||||
use user_lib::{exit, get_time, thread_create, waittid};
|
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
|
// Otherwise the compiler will assume that they will never
|
||||||
// be changed on this thread. Thus, they will be accessed
|
// be changed on this thread. Thus, they will be accessed
|
||||||
// only once!
|
// 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) {
|
unsafe fn unlock(id: usize) {
|
||||||
|
|
|
@ -6,7 +6,7 @@ extern crate user_lib;
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
use alloc::vec::Vec;
|
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};
|
use user_lib::{exit, get_time, thread_create, waittid};
|
||||||
|
|
||||||
static mut A: usize = 0;
|
static mut A: usize = 0;
|
||||||
|
@ -25,7 +25,7 @@ unsafe fn critical_section(t: &mut usize) {
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn lock() {
|
unsafe fn lock() {
|
||||||
while read_volatile(addr_of!(OCCUPIED)) {}
|
while vload!(OCCUPIED) {}
|
||||||
OCCUPIED = true;
|
OCCUPIED = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,6 @@ extern crate core;
|
||||||
|
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use core::{
|
use core::{
|
||||||
ptr::{addr_of, addr_of_mut, read_volatile, write_volatile},
|
|
||||||
sync::atomic::{AtomicUsize, Ordering},
|
sync::atomic::{AtomicUsize, Ordering},
|
||||||
};
|
};
|
||||||
use user_lib::{exit, sleep, thread_create, waittid};
|
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 */
|
/* announce that we want to enter */
|
||||||
loop {
|
loop {
|
||||||
println!("Thread[{}] try enter", id);
|
println!("Thread[{}] try enter", id);
|
||||||
write_volatile(addr_of_mut!(FLAG[id]), FlagState::Want);
|
vstore!(FLAG[id], FlagState::Want);
|
||||||
loop {
|
loop {
|
||||||
/* check if any with higher priority is `Want` or `In` */
|
/* check if any with higher priority is `Want` or `In` */
|
||||||
let mut prior_thread: Option<usize> = None;
|
let mut prior_thread: Option<usize> = None;
|
||||||
let turn = read_volatile(addr_of!(TURN));
|
let turn = vload!(TURN);
|
||||||
let ring_id = if id < turn { id + THREAD_NUM } else { id };
|
let ring_id = if id < turn { id + THREAD_NUM } else { id };
|
||||||
// FLAG.iter() may lead to some errors, use for-loop instead
|
// FLAG.iter() may lead to some errors, use for-loop instead
|
||||||
for i in turn..ring_id {
|
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);
|
prior_thread = Some(i % THREAD_NUM);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -68,13 +67,13 @@ unsafe fn eisenberg_enter_critical(id: usize) {
|
||||||
sleep(1);
|
sleep(1);
|
||||||
}
|
}
|
||||||
/* now tentatively claim the resource */
|
/* 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`*/
|
/* enforce the order of `claim` and `conflict check`*/
|
||||||
memory_fence!();
|
memory_fence!();
|
||||||
/* check if anthor thread is also `In`, which imply a conflict*/
|
/* check if anthor thread is also `In`, which imply a conflict*/
|
||||||
let mut conflict = false;
|
let mut conflict = false;
|
||||||
for i in 0..THREAD_NUM {
|
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;
|
conflict = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -85,7 +84,7 @@ unsafe fn eisenberg_enter_critical(id: usize) {
|
||||||
/* no need to sleep */
|
/* no need to sleep */
|
||||||
}
|
}
|
||||||
/* clain the trun */
|
/* clain the trun */
|
||||||
write_volatile(addr_of_mut!(TURN), id);
|
vstore!(TURN, id);
|
||||||
println!("Thread[{}] enter", id);
|
println!("Thread[{}] enter", id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,14 +94,14 @@ unsafe fn eisenberg_exit_critical(id: usize) {
|
||||||
let ring_id = id + THREAD_NUM;
|
let ring_id = id + THREAD_NUM;
|
||||||
for i in (id + 1)..ring_id {
|
for i in (id + 1)..ring_id {
|
||||||
let idx = i % THREAD_NUM;
|
let idx = i % THREAD_NUM;
|
||||||
if read_volatile(addr_of!(FLAG[idx])) == FlagState::Want {
|
if vload!(FLAG[idx]) == FlagState::Want {
|
||||||
next = idx;
|
next = idx;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
write_volatile(addr_of_mut!(TURN), next);
|
vstore!(TURN, next);
|
||||||
/* All done */
|
/* All done */
|
||||||
write_volatile(addr_of_mut!(FLAG[id]), FlagState::Out);
|
vstore!(FLAG[id], FlagState::Out);
|
||||||
println!("Thread[{}] exit, give turn to {}", id, next);
|
println!("Thread[{}] exit, give turn to {}", id, next);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
82
user/src/bin/gui_move.rs
Normal file
82
user/src/bin/gui_move.rs
Normal file
|
@ -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
|
||||||
|
}
|
|
@ -44,18 +44,6 @@ impl DrawingBoard {
|
||||||
.draw(&mut self.disp)
|
.draw(&mut self.disp)
|
||||||
.ok();
|
.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]
|
#[no_mangle]
|
||||||
|
@ -64,8 +52,8 @@ pub fn main() -> i32 {
|
||||||
let _ = board.disp.clear(Rgb888::BLACK).unwrap();
|
let _ = board.disp.clear(Rgb888::BLACK).unwrap();
|
||||||
for _ in 0..5 {
|
for _ in 0..5 {
|
||||||
board.latest_pos.x += RECT_SIZE as i32 + 20;
|
board.latest_pos.x += RECT_SIZE as i32 + 20;
|
||||||
//board.latest_pos.y += i;
|
|
||||||
board.paint();
|
board.paint();
|
||||||
}
|
}
|
||||||
|
board.disp.flush();
|
||||||
0
|
0
|
||||||
}
|
}
|
|
@ -328,7 +328,7 @@ const CR: u8 = 0x0du8;
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub fn main() -> i32 {
|
pub fn main() -> i32 {
|
||||||
let mut disp = Display::new(Size::new(VIRTGPU_XRES, VIRTGPU_YRES));
|
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();
|
let _ = disp.clear(Rgb888::BLACK).unwrap();
|
||||||
loop {
|
loop {
|
||||||
if key_pressed() {
|
if key_pressed() {
|
||||||
|
@ -345,7 +345,8 @@ pub fn main() -> i32 {
|
||||||
}
|
}
|
||||||
let _ = disp.clear(Rgb888::BLACK).unwrap();
|
let _ = disp.clear(Rgb888::BLACK).unwrap();
|
||||||
game.draw(&mut disp);
|
game.draw(&mut disp);
|
||||||
sleep(10);
|
disp.flush();
|
||||||
|
sleep(40);
|
||||||
}
|
}
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,5 +19,6 @@ pub fn main() -> i32 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
disp.flush();
|
||||||
0
|
0
|
||||||
}
|
}
|
|
@ -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<I>(&mut self, pixels: I) -> Result<(), Self::Error>
|
|
||||||
where
|
|
||||||
I: IntoIterator<Item = embedded_graphics::Pixel<Self::Color>>,
|
|
||||||
{
|
|
||||||
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
|
|
||||||
}
|
|
|
@ -7,7 +7,6 @@ extern crate alloc;
|
||||||
extern crate core;
|
extern crate core;
|
||||||
|
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use core::ptr::{addr_of, addr_of_mut, read_volatile, write_volatile};
|
|
||||||
use core::sync::atomic::{AtomicUsize, Ordering};
|
use core::sync::atomic::{AtomicUsize, Ordering};
|
||||||
use user_lib::{exit, sleep, thread_create, waittid};
|
use user_lib::{exit, sleep, thread_create, waittid};
|
||||||
const N: usize = 1000;
|
const N: usize = 1000;
|
||||||
|
@ -30,10 +29,10 @@ fn critical_test_exit() {
|
||||||
|
|
||||||
unsafe fn peterson_enter_critical(id: usize, peer_id: usize) {
|
unsafe fn peterson_enter_critical(id: usize, peer_id: usize) {
|
||||||
// println!("Thread[{}] try enter", id);
|
// println!("Thread[{}] try enter", id);
|
||||||
write_volatile(addr_of_mut!(FLAG[id]), true);
|
vstore!(FLAG[id], true);
|
||||||
write_volatile(addr_of_mut!(TURN), peer_id);
|
vstore!(TURN, peer_id);
|
||||||
memory_fence!();
|
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);
|
// println!("Thread[{}] enter fail", id);
|
||||||
sleep(1);
|
sleep(1);
|
||||||
// println!("Thread[{}] retry enter", id);
|
// 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) {
|
unsafe fn peterson_exit_critical(id: usize) {
|
||||||
write_volatile(addr_of_mut!(FLAG[id]), false);
|
vstore!(FLAG[id], false);
|
||||||
// println!("Thread[{}] exit", id);
|
// println!("Thread[{}] exit", id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,8 @@ impl Display {
|
||||||
}
|
}
|
||||||
pub fn paint_on_framebuffer(&mut self, p: impl FnOnce(&mut [u8]) -> ()) {
|
pub fn paint_on_framebuffer(&mut self, p: impl FnOnce(&mut [u8]) -> ()) {
|
||||||
p(self.framebuffer());
|
p(self.framebuffer());
|
||||||
|
}
|
||||||
|
pub fn flush(&self) {
|
||||||
framebuffer_flush();
|
framebuffer_flush();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -60,7 +62,6 @@ impl DrawTarget for Display {
|
||||||
self.fb[idx + 1] = px.1.g();
|
self.fb[idx + 1] = px.1.g();
|
||||||
self.fb[idx + 2] = px.1.r();
|
self.fb[idx + 2] = px.1.r();
|
||||||
});
|
});
|
||||||
framebuffer_flush();
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,15 +70,17 @@ fn main(_argc: usize, _argv: &[&str]) -> i32 {
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! vstore {
|
macro_rules! vstore {
|
||||||
($var_ref: expr, $value: expr) => {
|
($var: expr, $value: expr) => {
|
||||||
unsafe { core::intrinsics::volatile_store($var_ref as *const _ as _, $value) }
|
// 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_export]
|
||||||
macro_rules! vload {
|
macro_rules! vload {
|
||||||
($var_ref: expr) => {
|
($var: expr) => {
|
||||||
unsafe { core::intrinsics::volatile_load($var_ref as *const _ as _) }
|
// unsafe { core::intrinsics::volatile_load($var_ref as *const _ as _) }
|
||||||
|
unsafe { core::ptr::read_volatile(core::ptr::addr_of!($var)) }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue