Compare commits

..

1 Commits

Author SHA1 Message Date
Luoyuan Xiao b18d038e8d
Fix riscv64 build error
Fix riscv64 build error:
error: instruction requires the following: 'M' (Integer Multiplication and Division)
        mul t0, t0, a0
        ^
2022-03-21 16:51:03 +08:00
218 changed files with 2106 additions and 5844 deletions

View File

@ -1,16 +0,0 @@
[alias]
xtask = "run --package xtask --release --"
git-proxy = "xtask git-proxy"
setup = "xtask setup"
update-all = "xtask update-all"
check-style = "xtask check-style"
rootfs = "xtask rootfs"
libc-test = "xtask libc-test"
other-test = "xtask other-test"
image = "xtask image"
asm = "xtask asm"
qemu = "xtask qemu"
gdb = "xtask gdb"

View File

@ -1,13 +0,0 @@
#!/usr/bin/env bash
cat > target/doc/index.html << EOF
<html>
<head>
<meta http-equiv="refresh" content="0;URL=kernel_hal/index.html">
<title>Redirection</title>
</head>
<body onload="window.location = 'kernel_hal/index.html'">
<p>Redirecting to <a href="kernel_hal/index.html">kernel_hal/index.html</a>...</p>
</body>
</html>
EOF

View File

@ -1,5 +0,0 @@
#!/usr/bin/env bash
sudo apt-get update
sudo apt-get install -y $@
pip3 install -r tests/requirements.txt

View File

@ -1,7 +0,0 @@
#!/usr/bin/env bash
wget https://download.qemu.org/qemu-$1.tar.xz
tar -xJf qemu-$1.tar.xz
cd qemu-$1
./configure --target-list=x86_64-softmmu,riscv64-softmmu
make -j$nproc > /dev/null 2>&1

View File

@ -6,58 +6,65 @@ on:
schedule:
- cron: '0 22 * * *' # every day at 22:00 UTC
env:
rust_toolchain: nightly-2022-01-20
jobs:
workspace:
check:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: ${{ env.rust_toolchain }}
toolchain: nightly-2022-01-20
override: true
components: rust-src, rustfmt, clippy
- name: Check code format
run: cargo fmt --all -- --check
- name: Clippy LibOS
run: cargo clippy --all-features
- name: Clippy x86_64 bare-metal
run: cd zCore && make clippy ARCH=x86_64
- name: Clippy riscv64 bare-metal
run: cd zCore && make clippy ARCH=riscv64 LINUX=1
- name: Check format
uses: actions-rs/cargo@v1
build:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-20.04, macos-latest]
steps:
- uses: actions/checkout@v2
with:
command: fmt
args: --all -- --check
- name: Build
uses: actions-rs/cargo@v1
submodules: 'recursive'
- uses: actions-rs/toolchain@v1
with:
command: build
args: --all-features
- name: Clippy
uses: actions-rs/cargo@v1
profile: minimal
toolchain: nightly-2022-01-20
components: rust-src, llvm-tools-preview
- uses: actions-rs/install@v0.1
with:
command: clippy
args: --all-features
- name: Build docs
uses: actions-rs/cargo@v1
with:
command: doc
args: --all-features --no-deps
crate: cargo-binutils
version: latest
- name: Build all packages
run: cargo build
- name: Build linux LibOS
run: cargo build --features "linux libos"
- name: Build zircon LibOS
run: cargo build --features "zircon libos"
- name: Build x86_64 bare-metal
run: cd zCore && make build ARCH=x86_64
- name: Build riscv64 bare-metal
run: cd zCore && make build ARCH=riscv64 LINUX=1
build-aarch64:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: ${{ env.rust_toolchain }}
toolchain: nightly-2022-01-20
override: true
target: aarch64-unknown-linux-gnu
- uses: actions-rs/cargo@v1
with:
command: build
@ -65,85 +72,25 @@ jobs:
args: --target aarch64-unknown-linux-gnu --workspace --exclude linux-syscall --exclude zcore-loader --exclude zcore
build-user:
runs-on: ubuntu-20.04
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-20.04, macos-latest]
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v2
- name: Pull prebuilt images
run: git lfs pull -I prebuilt/zircon/x64/libc.so,prebuilt/zircon/x64/libfdio.so,prebuilt/zircon/x64/libunwind.so,prebuilt/zircon/x64/libzircon.so,prebuilt/zircon/x64/Scrt1.o
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: ${{ env.rust_toolchain }}
toolchain: nightly-2022-01-20
target: x86_64-fuchsia
- name: Build Zircon user programs
run: cd zircon-user && make build MODE=release
test-libos:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
mode: [linux, zircon]
os: [ubuntu-latest, macos-latest]
build-doc:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: ${{ env.rust_toolchain }}
components: rust-src, llvm-tools-preview, clippy
- name: Build
uses: actions-rs/cargo@v1
with:
command: build
args: --package zcore --features "${{ matrix.mode }} libos"
- name: Clippy
uses: actions-rs/cargo@v1
with:
command: clippy
args: --package zcore --features "${{ matrix.mode }} libos"
test-bare-metal:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
arch: [x86_64, riscv64]
os: [ubuntu-latest, macos-latest]
steps:
- uses: actions/checkout@v3
with:
submodules: 'recursive'
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: ${{ env.rust_toolchain }}
components: rust-src, llvm-tools-preview, clippy
- uses: actions-rs/install@v0.1
with:
crate: cargo-binutils
version: latest
- name: Build ${{ matrix.arch }} bare-metal zircon
if: matrix.arch == 'x86_64'
run: cd zCore && make build ARCH=${{ matrix.arch }}
- name: Clippy ${{ matrix.arch }} bare-metal zircon
if: matrix.arch == 'x86_64'
run: cd zCore && make clippy ARCH=${{ matrix.arch }}
- name: Build ${{ matrix.arch }} bare-metal linux
if: matrix.arch == 'riscv64'
run: cd zCore && make build ARCH=${{ matrix.arch }} LINUX=1
- name: Clippy ${{ matrix.arch }} bare-metal linux
if: matrix.arch == 'riscv64'
run: cd zCore && make clippy ARCH=${{ matrix.arch }} LINUX=1
- uses: actions/checkout@v2
- name: Build docs
run: cargo doc --no-deps --all-features

View File

@ -4,25 +4,25 @@ on:
push:
pull_request:
env:
rust_toolchain: nightly-2022-01-20
jobs:
doc:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: ${{ env.rust_toolchain }}
- uses: actions/checkout@v2
- name: Build docs
run: |
cargo doc --no-deps --all-features
.github/scripts/add-doc-index.sh
cat >target/doc/index.html <<EOF
<html>
<head>
<meta http-equiv="refresh" content="0;URL=kernel_hal/index.html">
<title>Redirection</title>
</head>
<body onload="window.location = 'kernel_hal/index.html'">
<p>Redirecting to <a href="kernel_hal/index.html">kernel_hal/index.html</a>...</p>
</body>
</html>
EOF
- name: Deploy to Github Pages
if: ${{ github.ref == 'refs/heads/master' }}
uses: JamesIves/github-pages-deploy-action@releases/v3

View File

@ -6,39 +6,26 @@ on:
schedule:
- cron: '0 22 * * *' # every day at 22:00 UTC
env:
rust_toolchain: nightly-2022-01-20
qemu_version: 7.0.0
jobs:
unit-test:
name: Unit Test
test:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: ${{ env.rust_toolchain }}
components: rust-src, llvm-tools-preview, rustfmt, clippy
- name: Run unit test
uses: actions-rs/cargo@v1
with:
command: test
args: --no-fail-fast
- uses: actions/checkout@v2
- name: Pull prebuilt images
run: git lfs pull -I prebuilt/linux/libc-libos.so,prebuilt/zircon/x64/bringup.zbi,prebuilt/zircon/x64/libzircon-libos.so,prebuilt/zircon/x64/userboot-libos.so
- name: Prepare rootfs
run: make rootfs
- name: Test
run: cargo test --no-fail-fast
env:
CARGO_INCREMENTAL: '0'
RUSTFLAGS: '-Zprofile -Ccodegen-units=1 -Copt-level=0 -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort'
RUSTDOCFLAGS: '-Zprofile -Ccodegen-units=1 -Copt-level=0 -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort'
- name: Cache grcov
uses: actions/cache@v3
uses: actions/cache@v2
with:
path: ~/.cargo/bin
key: ${{ runner.os }}-grcov
- name: Gather coverage data
id: coverage
uses: actions-rs/grcov@v0.1
@ -49,233 +36,142 @@ jobs:
# github-token: ${{ secrets.GITHUB_TOKEN }}
# path-to-lcov: ${{ steps.coverage.outputs.report }}
bench-test:
name: Bench Test
bench:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: ${{ env.rust_toolchain }}
components: rust-src, llvm-tools-preview, rustfmt, clippy
- name: Run bench test
uses: actions-rs/cargo@v1
with:
command: bench
- uses: actions/checkout@v2
- name: Run benchmarks
run: cargo bench
zircon-core-test-libos:
name: Zircon Core Test Libos
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v2
with:
submodules: 'recursive'
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: ${{ env.rust_toolchain }}
components: rust-src, llvm-tools-preview, rustfmt, clippy
- name: Pull prebuilt images
run: |
git lfs pull -I prebuilt/zircon/x64/core-tests.zbi
git lfs pull -I prebuilt/zircon/x64/libzircon-libos.so
git lfs pull -I prebuilt/zircon/x64/userboot-libos.so
- name: Install python dependencies
run: .github/scripts/install-deps.sh
run: git lfs pull -I prebuilt/zircon/x64/core-tests.zbi,prebuilt/zircon/x64/libzircon-libos.so,prebuilt/zircon/x64/userboot-libos.so
- name: Install dependencies
run: pip3 install -r tests/requirements.txt
- name: Run fast tests
if: github.event_name != 'schedule'
run: cd tests && python3 zircon_core_test.py --libos --fast --no-failed
run: cd tests && python3 zircon_core_test.py --libos --fast
- name: Run full tests
if: github.event_name == 'schedule'
run: cd tests && python3 zircon_core_test.py --libos
linux-libc-test-libos:
name: Linux Libc Test Libos
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3
with:
submodules: 'recursive'
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: ${{ env.rust_toolchain }}
components: rust-src, llvm-tools-preview, rustfmt, clippy
- name: Install dependencies
run: .github/scripts/install-deps.sh musl-tools musl-dev
- name: Prepare rootfs
run: make libc-test
- name: Run fast tests
if: github.event_name != 'schedule'
run: cd tests && python3 linux_libc_test.py --libos --fast
- name: Run full tests
if: github.event_name == 'schedule'
run: cd tests && python3 linux_libc_test.py --libos
zircon-core-test-baremetal:
name: Zircon Core Test Baremetal
runs-on: ubuntu-20.04
strategy:
fail-fast: false
matrix:
arch: [x86_64]
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v2
with:
submodules: 'recursive'
- name: Pull prebuilt images
run: git lfs pull -I prebuilt/zircon/x64/core-tests.zbi,prebuilt/zircon/x64/libzircon.so,prebuilt/zircon/x64/userboot.so
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: ${{ env.rust_toolchain }}
components: rust-src, llvm-tools-preview, rustfmt, clippy
- name: Pull prebuilt images
run: |
git lfs pull -I prebuilt/zircon/x64/core-tests.zbi
git lfs pull -I prebuilt/zircon/x64/libzircon.so
git lfs pull -I prebuilt/zircon/x64/userboot.so
toolchain: nightly-2022-01-20
components: rust-src
- name: Install dependencies
run: .github/scripts/install-deps.sh ninja-build
run: |
sudo apt-get update
sudo apt-get install ninja-build -y
pip3 install -r tests/requirements.txt
- name: Cache QEMU
id: cache-qemu
uses: actions/cache@v3
uses: actions/cache@v1
with:
path: qemu-${{ env.qemu_version }}
key: qemu-${{ env.qemu_version }}-x86_64-riscv64
- name: Download and Compile QEMU
if: steps.cache-qemu.outputs.cache-hit != 'true'
run: .github/scripts/install-qemu.sh ${{ env.qemu_version }}
path: qemu-6.1.0
key: qemu-6.1.0-${{ matrix.arch }}
- name: Install QEMU
run: |
cd qemu-${{ env.qemu_version }} && sudo make install
qemu-system-x86_64 --version
[ ! -d qemu-6.1.0 ] && wget https://download.qemu.org/qemu-6.1.0.tar.xz \
&& tar xJf qemu-6.1.0.tar.xz > /dev/null \
&& cd qemu-6.1.0 && ./configure --target-list=${{ matrix.arch }}-softmmu && cd ..
cd qemu-6.1.0 && sudo make install -j
qemu-system-${{ matrix.arch }} --version
- name: Run fast tests
if: github.event_name != 'schedule'
run: cd tests && python3 zircon_core_test.py --fast
- name: Run full tests
if: github.event_name == 'schedule'
run: cd tests && python3 zircon_core_test.py
linux-libc-test-libos:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
with:
submodules: 'recursive'
- name: Pull prebuilt images
run: git lfs pull -I prebuilt/linux/libc-libos.so
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install musl-tools musl-dev -y
pip3 install -r tests/requirements.txt
- name: Prepare rootfs
run: make rootfs && make libc-test
- name: Run fast tests
if: github.event_name != 'schedule'
run: cd tests && python3 linux_libc_test.py --libos --fast
- name: Run full tests
if: github.event_name == 'schedule'
run: cd tests && python3 linux_libc_test.py --libos
linux-libc-test-baremetal:
name: Linux Libc Test Baremetal
runs-on: ubuntu-20.04
strategy:
fail-fast: false
matrix:
arch: [x86_64, riscv64]
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v2
with:
submodules: 'recursive'
- name: Pull prebuilt images
run: git lfs pull -I prebuilt/linux/libc-libos.so
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: ${{ env.rust_toolchain }}
components: rust-src, llvm-tools-preview, rustfmt, clippy
toolchain: nightly-2022-01-20
components: rust-src, llvm-tools-preview
- if: matrix.arch == 'riscv64'
uses: actions-rs/install@v0.1
with:
crate: cargo-binutils
version: latest
- name: Install dependencies
run: .github/scripts/install-deps.sh musl-tools musl-dev ninja-build
run: |
sudo apt-get update
sudo apt-get install musl-tools musl-dev ninja-build -y
pip3 install -r tests/requirements.txt
- name: Cache QEMU
id: cache-qemu
uses: actions/cache@v3
uses: actions/cache@v1
with:
path: qemu-${{ env.qemu_version }}
key: qemu-${{ env.qemu_version }}-x86_64-riscv64
- name: Download and Compile QEMU
if: steps.cache-qemu.outputs.cache-hit != 'true'
run: .github/scripts/install-qemu.sh ${{ env.qemu_version }}
path: qemu-6.1.0
key: qemu-6.1.0-${{ matrix.arch }}
- name: Install QEMU
run: |
cd qemu-${{ env.qemu_version }} && sudo make install
[ ! -d qemu-6.1.0 ] && wget https://download.qemu.org/qemu-6.1.0.tar.xz \
&& tar xJf qemu-6.1.0.tar.xz > /dev/null \
&& cd qemu-6.1.0 && ./configure --target-list=${{ matrix.arch }}-softmmu && cd ..
cd qemu-6.1.0 && sudo make install -j
qemu-system-${{ matrix.arch }} --version
- name: Prepare rootfs
run: make libc-test ARCH=${{ matrix.arch }} && make image ARCH=${{ matrix.arch }}
run: |
if [ "${{ matrix.arch }}" = "x86_64" ]; then
make baremetal-test-img
elif [ "${{ matrix.arch }}" = "riscv64" ]; then
make riscv-image
fi
- name: Run fast tests
if: github.event_name != 'schedule'
run: cd tests && python3 linux_libc_test.py --arch ${{ matrix.arch }} --fast
- name: Run full tests
if: github.event_name == 'schedule'
run: cd tests && python3 linux_libc_test.py --arch ${{ matrix.arch }}
linux-other-test-baremetal:
name: Linux Other Test Baremetal
runs-on: ubuntu-20.04
strategy:
fail-fast: false
matrix:
arch: [x86_64, riscv64]
steps:
- uses: actions/checkout@v3
with:
submodules: 'recursive'
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: ${{ env.rust_toolchain }}
components: rust-src, llvm-tools-preview, rustfmt, clippy
- if: matrix.arch == 'riscv64'
uses: actions-rs/install@v0.1
with:
crate: cargo-binutils
version: latest
- name: Install dependencies
run: .github/scripts/install-deps.sh musl-tools musl-dev ninja-build
- name: Cache QEMU
id: cache-qemu
uses: actions/cache@v3
with:
path: qemu-${{ env.qemu_version }}
key: qemu-${{ env.qemu_version }}-x86_64-riscv64
- name: Download and Compile QEMU
if: steps.cache-qemu.outputs.cache-hit != 'true'
run: .github/scripts/install-qemu.sh ${{ env.qemu_version }}
- name: Install QEMU
run: |
cd qemu-${{ env.qemu_version }} && sudo make install
qemu-system-${{ matrix.arch }} --version
- name: Prepare rootfs
run: make other-test ARCH=${{ matrix.arch }} && make image ARCH=${{ matrix.arch }}
- name: Run fast tests
if: github.event_name != 'schedule'
run: cd tests && python3 linux_other_test.py --arch ${{ matrix.arch }} --fast
- name: Run full tests
if: github.event_name == 'schedule'
run: cd tests && python3 linux_other_test.py --arch ${{ matrix.arch }}

21
.gitignore vendored
View File

@ -1,18 +1,15 @@
**/.*
!.github/
!.cargo/
!.vscode/settings.json
/target
**/target
**/*.rs.bk
*.img
*.bin
*.log
Cargo.lock
/ignored
/rootfs
zCore/src/platform/riscv/kernel-vars.ld
/riscv_rootfs
/prebuilt/linux/alpine*
/prebuilt/linux/riscv64/prebuild*
zCore/src/platform/riscv/boot/kernel-vars.ld
*.img
*.log
.idea
.DS_Store
.vscode/
__pycache__

3
.gitmodules vendored
View File

@ -4,6 +4,3 @@
[submodule "tests"]
path = tests
url = https://github.com/rcore-os/zcore-tests.git
[submodule "libc-test"]
path = libc-test
url = https://github.com/rcore-os/libc-test

10
.vscode/settings.json vendored
View File

@ -1,10 +0,0 @@
{
// Prevent "can't find crate for `test`" error on no_std
// Ref: https://github.com/rust-lang/vscode-rust/issues/729
// For vscode-rust plugin users:
"rust.target": "riscv64imac-unknown-none-elf",
"rust.all_targets": false,
// For Rust Analyzer plugin users:
"rust-analyzer.cargo.target": "riscv64imac-unknown-none-elf",
"rust-analyzer.checkOnSave.enable": false
}

View File

@ -8,10 +8,12 @@ members = [
"linux-syscall",
"loader",
"zCore",
"xtask",
]
default-members = ["xtask"]
exclude = ["zircon-user", "rboot"]
exclude = [
"zircon-user",
"rboot",
]
[profile.release]
lto = true

121
Makefile
View File

@ -1,53 +1,100 @@
# Makefile for top level of zCore
ROOTFS_TAR := alpine-minirootfs-3.12.0-x86_64.tar.gz
ROOTFS_URL := http://dl-cdn.alpinelinux.org/alpine/v3.12/releases/x86_64/$(ROOTFS_TAR)
RISCV64_ROOTFS_TAR := prebuild.tar.xz
RISCV64_ROOTFS_URL := https://github.com/rcore-os/libc-test-prebuilt/releases/download/0.1/$(RISCV64_ROOTFS_TAR)
ARCH ?= x86_64
rcore_fs_fuse_revision := 7f5eeac
OUT_IMG := zCore/$(ARCH).img
TMP_ROOTFS := /tmp/rootfs
.PHONY: help setup update rootfs libc-test other-test image check doc clean
# for linux syscall tests
TEST_DIR := linux-syscall/test/
DEST_DIR := rootfs/bin/
TEST_PATH := $(wildcard $(TEST_DIR)*.c)
BASENAMES := $(notdir $(basename $(TEST_PATH)))
# print top level help
help:
cargo xtask help
CFLAG := -Wl,--dynamic-linker=/lib/ld-musl-x86_64.so.1
# setup git lfs and git submodules
setup:
cargo setup
.PHONY: rootfs libc-test rcore-fs-fuse image
# update toolchain and dependencies
update:
cargo update-all
prebuilt/linux/$(ROOTFS_TAR):
wget $(ROOTFS_URL) -O $@
# put rootfs for linux mode
rootfs:
cargo rootfs --arch $(ARCH)
prebuilt/linux/riscv64/$(RISCV64_ROOTFS_TAR):
@wget $(RISCV64_ROOTFS_URL) -O $@
rootfs: prebuilt/linux/$(ROOTFS_TAR)
rm -rf rootfs && mkdir -p rootfs
tar xf $< -C rootfs
# libc-libos.so (convert syscall to function call) is from https://github.com/rcore-os/musl/tree/rcore
cp prebuilt/linux/libc-libos.so rootfs/lib/ld-musl-x86_64.so.1
@for VAR in $(BASENAMES); do gcc $(TEST_DIR)$$VAR.c -o $(DEST_DIR)$$VAR $(CFLAG); done
riscv-rootfs:prebuilt/linux/riscv64/$(RISCV64_ROOTFS_TAR)
@rm -rf riscv_rootfs && mkdir -p riscv_rootfs
@tar -xvf $< -C riscv_rootfs --strip-components 1
@ln -s busybox riscv_rootfs/bin/ls
# put libc tests into rootfs
libc-test:
cargo libc-test --arch $(ARCH)
cd rootfs && git clone git://repo.or.cz/libc-test --depth 1
cd rootfs/libc-test && cp config.mak.def config.mak && echo 'CC := musl-gcc' >> config.mak && make -j
# put other tests into rootfs
other-test:
cargo other-test --arch $(ARCH)
rcore-fs-fuse:
ifneq ($(shell rcore-fs-fuse dir image git-version), $(rcore_fs_fuse_revision))
@echo Installing rcore-fs-fuse
@cargo install rcore-fs-fuse --git https://github.com/rcore-os/rcore-fs --rev $(rcore_fs_fuse_revision) --force
endif
# build image from rootfs
image:
cargo image --arch $(ARCH)
$(OUT_IMG): prebuilt/linux/$(ROOTFS_TAR) rcore-fs-fuse
@echo Generating $(ARCH).img
@rm -rf $(TMP_ROOTFS)
@mkdir -p $(TMP_ROOTFS)
@tar xf $< -C $(TMP_ROOTFS)
@cp $(TMP_ROOTFS)/lib/ld-musl-x86_64.so.1 rootfs/lib/
@rcore-fs-fuse $@ rootfs zip
# recover rootfs/ld-musl-x86_64.so.1 for zcore usr libos
# libc-libos.so (convert syscall to function call) is from https://github.com/rcore-os/musl/tree/rcore
@cp prebuilt/linux/libc-libos.so rootfs/lib/ld-musl-x86_64.so.1
# check code style
check:
cargo check-style
image: $(OUT_IMG)
@echo Resizing $(ARCH).img
@qemu-img resize $(OUT_IMG) +5M
riscv-image: rcore-fs-fuse riscv-rootfs
@echo building riscv.img
@rcore-fs-fuse zCore/riscv64.img riscv_rootfs zip
@qemu-img resize -f raw zCore/riscv64.img +5M
clean:
cargo clean
find zCore -maxdepth 1 -name "*.img" -delete
rm -rf rootfs
rm -rf riscv-rootfs
find zCore/target -type f -name "*.zbi" -delete
find zCore/target -type f -name "*.elf" -delete
cd linux-syscall/test-oscomp && make clean
cd linux-syscall/busybox && make clean
cd linux-syscall/lua && make clean
cd linux-syscall/lmbench && make clean
# build and open project document
doc:
cargo doc --open
# clean targets
clean:
cargo clean
rm -rf rootfs
rm -rf ignored/target
find zCore -maxdepth 1 -name "*.img" -delete
rt-test:
cd rootfs/x86_64 && git clone https://kernel.googlesource.com/pub/scm/linux/kernel/git/clrkwllms/rt-tests --depth 1
cd rootfs/x86_64/rt-tests && make
echo x86 gcc build rt-test,now need manual modificy.
baremetal-test-img: prebuilt/linux/$(ROOTFS_TAR) rcore-fs-fuse
@echo Generating $(ARCH).img
@rm -rf $(TMP_ROOTFS)
@mkdir -p $(TMP_ROOTFS)
@tar xf $< -C $(TMP_ROOTFS)
@mkdir -p rootfs/lib
@cp $(TMP_ROOTFS)/lib/ld-musl-x86_64.so.1 rootfs/lib/
@cd rootfs && rm -rf libc-test && git clone git://repo.or.cz/libc-test --depth 1
@cd rootfs/libc-test && cp config.mak.def config.mak && echo 'CC := musl-gcc' >> config.mak && make -j
@rcore-fs-fuse $(OUT_IMG) rootfs zip
# recover rootfs/ld-musl-x86_64.so.1 for zcore usr libos
# libc-libos.so (convert syscall to function call) is from https://github.com/rcore-os/musl/tree/rcore
@cp prebuilt/linux/libc-libos.so rootfs/lib/ld-musl-x86_64.so.1
@echo Resizing $(ARCH).img
@qemu-img resize $(OUT_IMG) +5M

View File

@ -6,10 +6,6 @@
Reimplement [Zircon][zircon] microkernel in safe Rust as a userspace program!
## Manual
[This](docs/Manual.md) is a new simple chinese manual.
## Dev Status
🚧 Working In Progress
@ -28,9 +24,9 @@ make run ARCH=riscv64 LINUX=1
Environments
- [Rust toolchain](http://rustup.rs)
- [QEMU](https://www.qemu.org)
- [Git LFS](https://git-lfs.github.com)
* [Rust toolchain](http://rustup.rs)
* [QEMU](https://www.qemu.org)
* [Git LFS](https://git-lfs.github.com)
### Developing environment info
@ -52,18 +48,15 @@ For users in China, there's a mirror you can try:
```sh
git clone https://github.com.cnpmjs.org/rcore-os/zCore --recursive
```
### Run zcore in libos mode
#### Run zcore in linux-libos mode
- step 1: Prepare Alpine Linux rootfs:
* step 1: Prepare Alpine Linux rootfs:
```sh
make rootfs
```
- step 2: Compile & Run native Linux program (Busybox) in libos mode:
* step 2: Compile & Run native Linux program (Busybox) in libos mode:
```sh
cargo run --release --features "linux libos" -- /bin/busybox [args]
@ -75,7 +68,7 @@ git clone https://github.com.cnpmjs.org/rcore-os/zCore --recursive
#### Run native Zircon program (shell) in zircon-libos mode:
- step 1: Compile and Run Zircon shell
* step 1: Compile and Run Zircon shell
```sh
cargo run --release --features "zircon libos" -- prebuilt/zircon/x64/bringup.zbi
@ -84,16 +77,15 @@ git clone https://github.com.cnpmjs.org/rcore-os/zCore --recursive
The `graphic` and `LOG` options are the same as Linux.
### Run zcore in bare-metal mode
#### Run Linux shell in linux-bare-metal mode:
- step 1: Prepare Alpine Linux rootfs:
* step 1: Prepare Alpine Linux rootfs:
```sh
make rootfs
```
- step 2: Create Linux rootfs image:
* step 2: Create Linux rootfs image:
Note: Before below step, you can add some special apps in zCore/rootfs
@ -101,7 +93,7 @@ git clone https://github.com.cnpmjs.org/rcore-os/zCore --recursive
make image
```
- step 3: Build and run zcore in linux-bare-metal mode:
* step 3: Build and run zcore in linux-bare-metal mode:
```sh
cd zCore && make run MODE=release LINUX=1 [LOG=warn] [GRAPHIC=on] [ACCEL=1]
@ -109,13 +101,13 @@ git clone https://github.com.cnpmjs.org/rcore-os/zCore --recursive
#### Run Zircon shell in zircon-bare-metal mode:
- step 1: Build and run zcore in zircon-bare-metal mode:
* step 1: Build and run zcore in zircon-bare-metal mode:
```sh
cd zCore && make run MODE=release [LOG=warn] [GRAPHIC=on] [ACCEL=1]
```
- step 2: Build and run your own Zircon user programs:
* step 2: Build and run your own Zircon user programs:
```sh
# See template in zircon-user
@ -126,7 +118,6 @@ git clone https://github.com.cnpmjs.org/rcore-os/zCore --recursive
```
## Testing
### LibOS Mode Testing
#### Zircon related
@ -157,7 +148,6 @@ cd scripts && python3 libos-libc-tests.py
```
### Bare-metal Mode Testing
#### Zircon related
Run Zircon official core-tests on bare-metal:
@ -177,7 +167,6 @@ cd scripts && python3 core-tests.py
#### x86-64 Linux related
Run Linux musl libc-tests for CI:
```sh
## Prepare rootfs with libc-test apps
make baremetal-test-img
@ -195,7 +184,6 @@ You can use [`scripts/baremetal-libc-test-ones.py`](./scripts/baremetal-libc-tes
#### riscv-64 Linux related
Run Linux musl libc-tests for CI:
```sh
## Prepare rootfs with libc-test & oscomp apps
make riscv-image
@ -204,28 +192,25 @@ cd scripts && python3 baremetal-test-riscv64.py
##
```
You can use[scripts/baremetal-libc-test-ones-riscv64.py](./scripts/baremetal-libc-test-ones-riscv64.py) & [`scripts/linux/baremetal-test-ones-rv64.txt`](scripts/linux/baremetal-test-ones-rv64.txt)to test
You can use[ `scripts/baremetal-libc-test-ones-riscv64.py`](./scripts/baremetal-libc-test-ones-riscv64.py) & [`scripts/linux/baremetal-test-ones-rv64.txt`](scripts/linux/baremetal-test-ones-rv64.txt)to test
specified apps.
[`scripts/linux/baremetal-test-fail-riscv64.txt`](./scripts/linux/baremetal-test-fail-riscv64.txt)includes all failed riscv-64 apps (We need YOUR HELP to fix bugs!)
## Graph/Game
snake game: <https://github.com/rcore-os/rcore-user/blob/master/app/src/snake.c>
snake game: https://github.com/rcore-os/rcore-user/blob/master/app/src/snake.c
### Step1: compile usr app
We can use musl-gcc compile it in x86_64 mode
### Step2: change zcore for run snake app first.
change zCore/zCore/main.rs L176
vec!["/bin/busybox".into(), "sh".into()]
TO
vec!["/bin/snake".into(), "sh".into()]
### Step3: prepare root fs image, run zcore in linux-bare-metal mode
exec:
```sh
@ -250,15 +235,12 @@ Operation
- `Middle`: Pause/Resume
## Doc
```
make doc
```
### RISC-V 64 porting info
- [porting riscv64 doc](./docs/porting-rv64.md)
## Components
### Overview
@ -278,5 +260,4 @@ make doc
| Exception Handling | Interrupt | Signal |
### Small Goal & Little Plans
- <https://github.com/rcore-os/zCore/wiki/Plans>
- https://github.com/rcore-os/zCore/wiki/Plans

View File

@ -1,86 +0,0 @@
# zCore 项目使用指南
## 预定功能
预定功能指的是 zCore 作为一个项目,为开发者和用户常用操作提供的封装。
由于历史原因,目前预定功能分为顶层预定功能和内核预定功能。
所有顶层提供的预定功能都定义于 [顶层 Makefile](../Makefile)
并且所有预定功能最终都将移动到顶层。
## 常规操作流程
对于一般开发者和用户,可以按以下步骤设置 zCore 项目。
1. 先决条件
目前已测试的开发环境包括 Ubuntu20.04、Ubuntu22.04 和 Debian11
Ubuntu22.04 不能正确编译 x86_64 的 libc 测试。
若不需要烧写到物理硬件,使用 WSL2 或其他虚拟机的操作与真机并无不同之处。
在开始之前,确保你的计算机上安装了 git 和 rustup。要在虚拟环境开发或测试需要 QEMU。
2. 克隆项目
```bash
git clone https://github.com/rcore-os/zCore.git
```
3. 初始化存储库
```bash
make setup
```
4. 保持更新
```bash
make update
```
5. 探索更多操作
```bash
make help
```
6. 推到仓库前,现在本机执行测试
```bash
make check # CI/build 的一部分,未来会实现更多快速测试指令
```
## Linux 模式
zCore 根据向用户提供的系统调用的不同,可分为 zircon 模式和 linux 模式。
要以 linux 模式启动,需要先构建 linux 的启动文件系统。
这个指令构建适于 x86_64 架构的启动文件系统。
```bash
make rootfs ARCH=x86_64
```
这个指令构建适于 riscv64 架构的启动文件系统。
```bash
make rootfs ARCH=riscv64
```
要执行 musl-libc 测试集,需要向文件系统中添加 libc 测试集:
```bash
make libc-test <ARCH=?>
```
要执行 CI 的其他测试,需要向文件系统中添加相应测试集:
```bash
make other-test <ARCH=?>
```
要以裸机模式启动 zCore需要构造将放到设备或虚拟环境中的镜像文件
```bash
make image <ARCH=?>
```

View File

@ -20,27 +20,19 @@ bitflags = "1.3"
lazy_static = "1.4"
numeric-enum-macro = "0.2"
device_tree = { git = "https://github.com/rcore-os/device_tree-rs", rev = "2f2e55f" }
bitmap-allocator = { git = "https://github.com/rcore-os/bitmap-allocator", rev = "88e871a5" }
pci = { git = "https://github.com/elliott10/pci-rs", rev = "8f33774b" }
bitmap-allocator = { git = "https://github.com/rcore-os/bitmap-allocator", rev = "b3f9f51" }
virtio-drivers = { git = "https://github.com/rcore-os/virtio-drivers", rev = "2aaf7d6", optional = true }
rcore-console = { git = "https://github.com/rcore-os/rcore-console", default-features = false, rev = "ca5b1bc", optional = true }
lock = { git = "https://github.com/DeathWish5/kernel-sync", rev = "01b2e70" }
isomorphic_drivers = { git = "https://github.com/rcore-os/isomorphic_drivers", rev = "f7cd97a8", features = ["log"] }
smoltcp = { git = "https://github.com/smoltcp-rs/smoltcp", rev = "35e833e3", default-features = false, features = ["log", "alloc", "verbose", "proto-ipv4", "proto-ipv6", "proto-igmp", "medium-ip", "medium-ethernet", "socket-raw", "socket-udp", "socket-tcp", "socket-icmp", "async"] }
# smoltcp = { git = "https://github.com/smoltcp-rs/smoltcp", rev = "35e833e3", default-features = false, features = ["log", "alloc", "verbose", "proto-ipv4", "proto-ipv6", "proto-igmp", "medium-ip", "medium-ethernet", "socket-raw", "socket-udp", "socket-tcp", "socket-icmp"] }
smoltcp = { git = "https://gitee.com/gcyyfun/smoltcp", rev="043eb60", default-features = false, features = ["alloc","log", "async", "medium-ethernet","proto-ipv4", "proto-igmp", "socket-icmp", "socket-udp", "socket-tcp", "socket-raw"] }
# LibOS mode
[target.'cfg(not(target_os = "none"))'.dependencies]
async-std = { version = "1.10", optional = true }
sdl2 = { version = "0.34", optional = true }
# Bare-metal mode
[target.'cfg(target_os = "none")'.dependencies]
[target.'cfg(target_arch = "x86_64")'.dependencies]
acpi = "4.1"
acpi = "4.0"
x2apic = "0.4"
x86_64 = "0.14"
[target.'cfg(any(target_arch = "riscv32", target_arch = "riscv64"))'.dependencies]
riscv = "0.8"
riscv = { git = "https://github.com/rust-embedded/riscv", rev = "cd31989", features = ["inline-asm"] }

View File

@ -1,18 +1,3 @@
// 解析设备树,创建已知的设备并为它们注册中断。
//
// 涉及到中断的设备包括:
//
// - 接收中断的中断控制器
// - 发出中断的设备
//
// 有效的中断控制器应该具有下列三个属性:
//
// - `interrupt-controller`: 指示这是一个中断控制器
// - `interrupt-cells`: 只是要向此控制器注册中断需要几个参数
// - `phandle`: 向此控制器注册中断时使用的一个号码,如果没有设备需要向它注册,可能不存在
//
// 设备注册中断需要 `interrupts_extended` 属性,这是一个 `Vec<u32>`,形式为 `[{phandle, ...,}*]`
// 即控制器引用和控制器指定数量的参数。
//! Probe devices and create drivers from device tree.
//!
//! Specification: <https://github.com/devicetree-org/devicetree-specification/releases/download/v0.3/devicetree-specification-v0.3.pdf>.
@ -20,27 +5,24 @@
use alloc::{collections::BTreeMap, sync::Arc, vec::Vec};
use super::IoMapper;
use crate::{
utils::devicetree::{
parse_interrupts, parse_reg, Devicetree, InheritProps, InterruptsProp, Node, StringList,
},
Device, DeviceError, DeviceResult, VirtAddr,
};
use crate::utils::devicetree::{parse_interrupts, parse_reg};
use crate::utils::devicetree::{Devicetree, InheritProps, InterruptsProp, Node, StringList};
use crate::{Device, DeviceError, DeviceResult, VirtAddr};
const MODULE: &str = "device-tree";
type DevWithInterrupt = (Device, InterruptsProp);
/// 设备树中中断控制器特有的属性
struct IntcProps {
phandle: u32,
interrupt_cells: u32,
}
/// 查找表保存的中断控制器信息
struct Intc {
index: usize,
cells: usize,
/// A wrapper of [`Device`] which provides interrupt information additionally.
#[derive(Debug)]
struct DevWithInterrupt {
/// For interrupt controller, represent the `phandle` property, otherwise
/// is `None`.
phandle: Option<u32>,
/// For interrupt controller, represent the `interrupt_cells` property,
/// otherwise is `None`.
interrupt_cells: Option<u32>,
/// A unified representation of the `interrupts` and `interrupts_extended`
/// properties for any interrupt generating device.
interrupts_extended: InterruptsProp,
/// The inner [`Device`] structure.
dev: Device,
}
/// A builder to probe devices and create drivers from device tree.
@ -60,78 +42,26 @@ impl<M: IoMapper> DevicetreeDriverBuilder<M> {
/// Parse the device tree from root, and returns an array of [`Device`] it found.
pub fn build(&self) -> DeviceResult<Vec<Device>> {
let mut intc_map = BTreeMap::new(); // phandle -> intc
let mut dev_list = Vec::new(); // devices
let mut intc_map = BTreeMap::new();
let mut dev_list = Vec::new();
// 解析设备树
self.dt.walk(&mut |node, comp, props| {
debug!(
"{MODULE}: parsing node {:?} with compatible {comp:?}",
node.name
);
// parse interrupt controller
let res = if node.has_prop("interrupt-controller") {
self.parse_intc(node, comp, props).map(|(dev, intc)| {
intc_map.insert(
intc.phandle,
Intc {
index: dev_list.len(),
cells: intc.interrupt_cells as _,
},
);
dev
})
} else {
// parse other device
match comp {
#[cfg(feature = "virtio")]
c if c.contains("virtio,mmio") => self.parse_virtio(node, props),
c if c.contains("allwinner,sunxi-gmac") => {
self.parse_ethernet(node, comp, props)
if let Ok(dev) = self.parse_device(node, comp, props) {
// create the phandle-device mapping
if node.has_prop("interrupt-controller") {
if let Some(phandle) = dev.phandle {
intc_map.insert(phandle, dev_list.len());
}
c if c.contains("ns16550a") || c.contains("allwinner,sun20i-uart") => {
self.parse_uart(node, comp, props)
}
_ => Err(DeviceError::NotSupported),
}
};
match res {
Ok(dev) => dev_list.push(dev),
Err(DeviceError::NotSupported) => {}
Err(err) => warn!("{MODULE}: failed to parsing node {:?}: {err:?}", node.name),
dev_list.push(dev);
}
});
// 注册中断
for (device, interrupts_extended) in &dev_list {
let mut extended = interrupts_extended.as_slice();
// 分解 interrupts_extended
while let [phandle, irq_num, ..] = extended {
if let Some(Intc { index, cells }) = intc_map.get(phandle) {
let (intc, _) = &dev_list[*index];
extended = &extended[1 + cells..];
if let Device::Irq(irq) = intc {
if *irq_num != 0xffff_ffff {
info!("{MODULE}: register interrupts for {intc:?}: {device:?}, irq_num={irq_num}");
if irq.register_device(*irq_num as _, device.inner()).is_ok() {
irq.unmask(*irq_num as _)?;
}
}
} else {
warn!("{MODULE}: node with phandle {phandle:#x} is not an interrupt-controller");
return Err(DeviceError::InvalidParam);
}
} else {
warn!(
"{MODULE}: no such node with phandle {phandle:#x} as the interrupt-parent"
);
return Err(DeviceError::InvalidParam);
}
}
for dev in &dev_list {
register_interrupt(dev, &dev_list, &intc_map).ok();
}
// 丢弃中断信息
Ok(dev_list.into_iter().map(|(dev, _)| dev).collect())
Ok(dev_list.into_iter().map(|d| d.dev).collect())
}
}
@ -140,20 +70,56 @@ impl<M: IoMapper> DevicetreeDriverBuilder<M> {
#[allow(unused_variables)]
#[allow(unreachable_code)]
impl<M: IoMapper> DevicetreeDriverBuilder<M> {
/// Parse device nodes
fn parse_device(
&self,
node: &Node,
comp: &StringList,
props: &InheritProps,
) -> DeviceResult<DevWithInterrupt> {
debug!(
"device-tree: parsing node {:?} with compatible {:?}",
node.name, comp
);
// parse interrupt controller
let res = if node.has_prop("interrupt-controller") {
self.parse_intc(node, comp, props)
} else {
// parse other device
match comp {
#[cfg(feature = "virtio")]
c if c.contains("virtio,mmio") => self.parse_virtio(node, props),
c if c.contains("allwinner,sunxi-gmac") => self.parse_ethernet(node, comp, props),
c if c.contains("ns16550a") => self.parse_uart(node, comp, props),
c if c.contains("allwinner,sun20i-uart") => self.parse_uart(node, comp, props),
_ => Err(DeviceError::NotSupported),
}
};
if let Err(err) = &res {
if !matches!(err, DeviceError::NotSupported) {
warn!(
"device-tree: failed to parsing node {:?}: {:?}",
node.name, err
);
}
}
res
}
/// Parse nodes for interrupt controllers.
fn parse_intc(
&self,
node: &Node,
comp: &StringList,
props: &InheritProps,
) -> DeviceResult<(DevWithInterrupt, IntcProps)> {
let phandle = node
.prop_u32("phandle")
.map_err(|_| DeviceError::InvalidParam)?;
let interrupt_cells = node
.prop_u32("#interrupt-cells")
.map_err(|_| DeviceError::InvalidParam)?;
) -> DeviceResult<DevWithInterrupt> {
let phandle = node.prop_u32("phandle").ok();
let interrupt_cells = node.prop_u32("#interrupt-cells").ok();
let interrupts_extended = parse_interrupts(node, props)?;
if phandle.is_none() || interrupt_cells.is_none() {
return Err(DeviceError::InvalidParam);
}
let base_vaddr = parse_reg(node, props).and_then(|(paddr, size)| {
self.io_mapper
.query_or_map(paddr as usize, size as usize)
@ -168,13 +134,12 @@ impl<M: IoMapper> DevicetreeDriverBuilder<M> {
_ => return Err(DeviceError::NotSupported),
});
Ok((
(dev, interrupts_extended),
IntcProps {
phandle,
interrupt_cells,
},
))
Ok(DevWithInterrupt {
phandle,
interrupt_cells,
interrupts_extended,
dev,
})
}
/// Parse nodes for virtio devices over MMIO.
@ -194,7 +159,7 @@ impl<M: IoMapper> DevicetreeDriverBuilder<M> {
return Err(DeviceError::NotSupported);
}
info!(
"{MODULE}: detected virtio device: vendor_id={:#X}, type={:?}",
"device-tree: detected virtio device: vendor_id={:#X}, type={:?}",
header.vendor_id(),
header.device_type()
);
@ -207,7 +172,12 @@ impl<M: IoMapper> DevicetreeDriverBuilder<M> {
_ => return Err(DeviceError::NotSupported),
};
Ok((dev, interrupts_extended))
Ok(DevWithInterrupt {
phandle: None,
interrupt_cells: None,
interrupts_extended,
dev,
})
}
/// Parse nodes for Ethernet devices.
@ -237,7 +207,12 @@ impl<M: IoMapper> DevicetreeDriverBuilder<M> {
_ => return Err(DeviceError::NotSupported),
});
Ok((dev, interrupts_extended))
Ok(DevWithInterrupt {
phandle: None,
interrupt_cells: None,
interrupts_extended,
dev,
})
}
/// Parse nodes for UART devices.
@ -265,6 +240,57 @@ impl<M: IoMapper> DevicetreeDriverBuilder<M> {
_ => return Err(DeviceError::NotSupported),
});
Ok((dev, interrupts_extended))
Ok(DevWithInterrupt {
phandle: None,
interrupt_cells: None,
interrupts_extended,
dev,
})
}
}
/// Register interrupts for `dev` according to its interrupt parent, which can
/// be found from the phandle-device mapping.
fn register_interrupt(
dev: &DevWithInterrupt,
dev_list: &[DevWithInterrupt],
intc_map: &BTreeMap<u32, usize>,
) -> DeviceResult {
let mut pos = 0;
while pos < dev.interrupts_extended.len() {
let parent = dev.interrupts_extended[pos];
// find the interrupt parent in `dev_list`
if let Some(intc) = intc_map.get(&parent).map(|&i| &dev_list[i]) {
let cells = intc.interrupt_cells.ok_or(DeviceError::InvalidParam)?;
if let Device::Irq(irq) = &intc.dev {
// get irq_num from the `interrupts_extended` property
let irq_num = dev.interrupts_extended[pos + 1] as usize;
if irq_num != 0xffff_ffff {
info!(
"device-tree: register interrupts for {:?}: {:?}, irq_num={}",
intc.dev, dev.dev, irq_num
);
irq.register_device(irq_num, dev.dev.inner())?;
// enable the interrupt after registration
irq.unmask(irq_num)?;
}
} else {
warn!(
"device-tree: node with phandle {:#x} is not an interrupt-controller",
parent
);
return Err(DeviceError::InvalidParam);
}
// process the next interrupt parent
pos += 1 + cells as usize;
} else {
warn!(
"device-tree: no such node with phandle {:#x} as the interrupt-parent",
parent
);
return Err(DeviceError::InvalidParam);
}
}
Ok(())
}

View File

@ -1,38 +0,0 @@
#![allow(unused)]
#[cfg(any(target_arch = "x86_64", target_arch = "riscv64"))]
pub mod pci;
pub fn phys_to_virt(paddr: PhysAddr) -> VirtAddr {
unsafe { drivers_phys_to_virt(paddr) }
}
pub fn virt_to_phys(vaddr: VirtAddr) -> PhysAddr {
unsafe { drivers_virt_to_phys(vaddr) }
}
extern "C" {
fn drivers_dma_alloc(pages: usize) -> PhysAddr;
fn drivers_dma_dealloc(paddr: PhysAddr, pages: usize) -> i32;
fn drivers_phys_to_virt(paddr: PhysAddr) -> VirtAddr;
fn drivers_virt_to_phys(vaddr: VirtAddr) -> PhysAddr;
}
pub const PAGE_SIZE: usize = 4096;
type VirtAddr = usize;
type PhysAddr = usize;
use core::ptr::{read_volatile, write_volatile};
#[inline(always)]
pub fn write<T>(addr: usize, content: T) {
let cell = (addr) as *mut T;
unsafe {
write_volatile(cell, content);
}
}
#[inline(always)]
pub fn read<T>(addr: usize) -> T {
let cell = (addr) as *const T;
unsafe { read_volatile(cell) }
}

View File

@ -1,327 +0,0 @@
use super::{phys_to_virt, PAGE_SIZE};
use crate::builder::IoMapper;
use crate::{Device, DeviceError, DeviceResult, VirtAddr};
use alloc::{collections::BTreeMap, format, sync::Arc, vec::Vec};
use pci::*;
use spin::Mutex;
const PCI_COMMAND: u16 = 0x04;
const BAR0: u16 = 0x10;
const PCI_CAP_PTR: u16 = 0x34;
const PCI_INTERRUPT_LINE: u16 = 0x3c;
const PCI_INTERRUPT_PIN: u16 = 0x3d;
const PCI_MSI_CTRL_CAP: u16 = 0x00;
const PCI_MSI_ADDR: u16 = 0x04;
const PCI_MSI_UPPER_ADDR: u16 = 0x08;
const PCI_MSI_DATA_32: u16 = 0x08;
const PCI_MSI_DATA_64: u16 = 0x0C;
const PCI_CAP_ID_MSI: u8 = 0x05;
struct PortOpsImpl;
#[cfg(target_arch = "x86_64")]
use x86_64::instructions::port::Port;
#[cfg(target_arch = "x86_64")]
impl PortOps for PortOpsImpl {
unsafe fn read8(&self, port: u16) -> u8 {
Port::new(port).read()
}
unsafe fn read16(&self, port: u16) -> u16 {
Port::new(port).read()
}
unsafe fn read32(&self, port: u32) -> u32 {
Port::new(port as u16).read()
}
unsafe fn write8(&self, port: u16, val: u8) {
Port::new(port).write(val);
}
unsafe fn write16(&self, port: u16, val: u16) {
Port::new(port).write(val);
}
unsafe fn write32(&self, port: u32, val: u32) {
Port::new(port as u16).write(val);
}
}
#[cfg(target_arch = "x86_64")]
const PCI_BASE: usize = 0; //Fix me
#[cfg(any(target_arch = "mips", target_arch = "riscv64"))]
use super::{read, write};
#[cfg(feature = "board_malta")]
const PCI_BASE: usize = 0xbbe00000;
#[cfg(target_arch = "riscv64")]
const PCI_BASE: usize = 0x30000000;
#[cfg(target_arch = "riscv64")]
const E1000_BASE: usize = 0x40000000;
// riscv64 Qemu
#[cfg(target_arch = "x86_64")]
const PCI_ACCESS: CSpaceAccessMethod = CSpaceAccessMethod::IO;
#[cfg(not(target_arch = "x86_64"))]
const PCI_ACCESS: CSpaceAccessMethod = CSpaceAccessMethod::MemoryMapped(PCI_BASE as *mut u8);
#[cfg(any(target_arch = "mips", target_arch = "riscv64"))]
impl PortOps for PortOpsImpl {
unsafe fn read8(&self, port: u16) -> u8 {
read(phys_to_virt(PCI_BASE) + port as usize)
}
unsafe fn read16(&self, port: u16) -> u16 {
read(phys_to_virt(PCI_BASE) + port as usize)
}
unsafe fn read32(&self, port: u32) -> u32 {
read(phys_to_virt(PCI_BASE) + port as usize)
}
unsafe fn write8(&self, port: u16, val: u8) {
write(phys_to_virt(PCI_BASE) + port as usize, val);
}
unsafe fn write16(&self, port: u16, val: u16) {
write(phys_to_virt(PCI_BASE) + port as usize, val);
}
unsafe fn write32(&self, port: u32, val: u32) {
write(phys_to_virt(PCI_BASE) + port as usize, val);
}
}
/// Enable the pci device and its interrupt
/// Return assigned MSI interrupt number when applicable
unsafe fn enable(loc: Location, paddr: u64) -> Option<usize> {
let ops = &PortOpsImpl;
//let am = CSpaceAccessMethod::IO;
let am = PCI_ACCESS;
if paddr != 0 {
// reveal PCI regs by setting paddr
let bar0_raw = am.read32(ops, loc, BAR0);
am.write32(ops, loc, BAR0, (paddr & !0xfff) as u32); //Only for 32-bit decoding
debug!(
"BAR0 set from {:#x} to {:#x}",
bar0_raw,
am.read32(ops, loc, BAR0)
);
}
// 23 and lower are used
static mut MSI_IRQ: u32 = 23;
let orig = am.read16(ops, loc, PCI_COMMAND);
// IO Space | MEM Space | Bus Mastering | Special Cycles | PCI Interrupt Disable
am.write32(ops, loc, PCI_COMMAND, (orig | 0x40f) as u32);
// find MSI cap
let mut msi_found = false;
let mut cap_ptr = am.read8(ops, loc, PCI_CAP_PTR) as u16;
let mut assigned_irq = None;
while cap_ptr > 0 {
let cap_id = am.read8(ops, loc, cap_ptr);
if cap_id == PCI_CAP_ID_MSI {
let orig_ctrl = am.read32(ops, loc, cap_ptr + PCI_MSI_CTRL_CAP);
// The manual Volume 3 Chapter 10.11 Message Signalled Interrupts
// 0 is (usually) the apic id of the bsp.
//am.write32(ops, loc, cap_ptr + PCI_MSI_ADDR, 0xfee00000 | (0 << 12));
am.write32(ops, loc, cap_ptr + PCI_MSI_ADDR, 0xfee00000);
MSI_IRQ += 1;
let irq = MSI_IRQ;
assigned_irq = Some(irq as usize);
// we offset all our irq numbers by 32
if (orig_ctrl >> 16) & (1 << 7) != 0 {
// 64bit
am.write32(ops, loc, cap_ptr + PCI_MSI_DATA_64, irq + 32);
} else {
// 32bit
am.write32(ops, loc, cap_ptr + PCI_MSI_DATA_32, irq + 32);
}
// enable MSI interrupt, assuming 64bit for now
am.write32(ops, loc, cap_ptr + PCI_MSI_CTRL_CAP, orig_ctrl | 0x10000);
debug!(
"MSI control {:#b}, enabling MSI interrupt {}",
orig_ctrl >> 16,
irq
);
msi_found = true;
}
debug!("PCI device has cap id {} at {:#X}", cap_id, cap_ptr);
cap_ptr = am.read8(ops, loc, cap_ptr + 1) as u16;
}
if !msi_found {
// Use PCI legacy interrupt instead
// IO Space | MEM Space | Bus Mastering | Special Cycles
am.write32(ops, loc, PCI_COMMAND, (orig | 0xf) as u32);
debug!("MSI not found, using PCI interrupt");
}
info!("pci device enable done");
assigned_irq
}
pub fn init_driver(dev: &PCIDevice, mapper: &Option<Arc<dyn IoMapper>>) -> DeviceResult<Device> {
let name = format!("enp{}s{}f{}", dev.loc.bus, dev.loc.device, dev.loc.function);
match (dev.id.vendor_id, dev.id.device_id) {
(0x8086, 0x100e) | (0x8086, 0x100f) | (0x8086, 0x10d3) => {
// 0x100e
// 82540EM Gigabit Ethernet Controller
// 0x100f
// 82545EM Gigabit Ethernet Controller (Copper)
// 0x10d3
// 82574L Gigabit Network Connection
// (e1000e 8086:10d3)
if let Some(BAR::Memory(addr, len, _, _)) = dev.bars[0] {
info!("Found e1000e dev {:?} BAR0 {:#x?}", dev, addr);
#[cfg(target_arch = "riscv64")]
let addr = if addr == 0 { E1000_BASE as u64 } else { addr };
if let Some(m) = mapper {
m.query_or_map(addr as usize, PAGE_SIZE * 8);
}
let irq = unsafe { enable(dev.loc, addr) };
let vaddr = phys_to_virt(addr as usize);
let dev = Device::Net(Arc::new(crate::net::e1000::init(
name,
irq.unwrap_or(0),
vaddr,
len as usize,
0,
)?));
return Ok(dev);
}
}
(0x8086, 0x10fb) => {
// 82599ES 10-Gigabit SFI/SFP+ Network Connection
if let Some(BAR::Memory(addr, len, _, _)) = dev.bars[0] {
let irq = unsafe { enable(dev.loc, 0) };
let vaddr = phys_to_virt(addr as usize);
info!("Found ixgbe dev {:#x}, irq: {:?}", vaddr, irq);
/*
let index = NET_DRIVERS.read().len();
PCI_DRIVERS.lock().insert(
dev.loc,
ixgbe::ixgbe_init(name, irq, vaddr, len as usize, index),
);
*/
return Err(DeviceError::NotSupported);
}
}
(0x8086, 0x1533) => {
if let Some(BAR::Memory(addr, len, _, _)) = dev.bars[0] {
info!("Intel Corporation I210 Gigabit Network Connection");
info!("DEV: {:?}, BAR0: {:#x}", dev, addr);
return Err(DeviceError::NotSupported);
}
}
(0x8086, 0x1539) => {
if let Some(BAR::Memory(addr, len, _, _)) = dev.bars[0] {
info!(
"Found Intel I211 ethernet controller dev {:?}, addr: {:x?}",
dev, addr
);
return Err(DeviceError::NotSupported);
}
}
_ => {}
}
if dev.id.class == 0x01 && dev.id.subclass == 0x06 {
// Mass storage class
// SATA subclass
if let Some(BAR::Memory(addr, len, _, _)) = dev.bars[5] {
info!("Found AHCI dev {:?} BAR5 {:x?}", dev, addr);
/*
let irq = unsafe { enable(dev.loc) };
assert!(len as usize <= PAGE_SIZE);
let vaddr = phys_to_virt(addr as usize);
if let Some(driver) = ahci::init(irq, vaddr, len as usize) {
PCI_DRIVERS.lock().insert(dev.loc, driver);
}
*/
return Err(DeviceError::NotSupported);
}
}
Err(DeviceError::NoResources)
}
pub fn detach_driver(loc: &Location) -> bool {
/*
match PCI_DRIVERS.lock().remove(loc) {
Some(driver) => {
DRIVERS
.write()
.retain(|dri| dri.get_id() != driver.get_id());
NET_DRIVERS
.write()
.retain(|dri| dri.get_id() != driver.get_id());
true
}
None => false,
}
*/
false
}
pub fn init(mapper: Option<Arc<dyn IoMapper>>) -> DeviceResult<Vec<Device>> {
let mapper_driver = if let Some(m) = mapper {
m.query_or_map(PCI_BASE, PAGE_SIZE * 256 * 32 * 8);
Some(m)
} else {
None
};
let mut dev_list = Vec::new();
let pci_iter = unsafe { scan_bus(&PortOpsImpl, PCI_ACCESS) };
info!("");
info!("--------- PCI bus:device:function ---------");
for dev in pci_iter {
info!(
"pci: {}:{}:{} {:04x}:{:04x} ({} {}) irq: {}:{:?}",
dev.loc.bus,
dev.loc.device,
dev.loc.function,
dev.id.vendor_id,
dev.id.device_id,
dev.id.class,
dev.id.subclass,
dev.pic_interrupt_line,
dev.interrupt_pin,
);
let res = init_driver(&dev, &mapper_driver);
match res {
Ok(d) => dev_list.push(d),
Err(e) => warn!(
"{:?}, failed to initialize PCI device: {:04x}:{:04x}",
e, dev.id.vendor_id, dev.id.device_id
),
}
}
info!("---------");
info!("");
Ok(dev_list)
}
pub fn find_device(vendor: u16, product: u16) -> Option<Location> {
let pci_iter = unsafe { scan_bus(&PortOpsImpl, PCI_ACCESS) };
for dev in pci_iter {
if dev.id.vendor_id == vendor && dev.id.device_id == product {
return Some(dev.loc);
}
}
None
}
pub fn get_bar0_mem(loc: Location) -> Option<(usize, usize)> {
unsafe { probe_function(&PortOpsImpl, loc, PCI_ACCESS) }
.and_then(|dev| dev.bars[0])
.map(|bar| match bar {
BAR::Memory(addr, len, _, _) => (addr as usize, len as usize),
_ => unimplemented!(),
})
}
// all devices stored inAllDeviceList

View File

@ -1,5 +1,3 @@
//! Only UEFI Display currently.
mod uefi;
pub use uefi::UefiDisplay;

View File

@ -1,5 +1,3 @@
//! Only Mouse currently.
mod mouse;
pub mod input_event_codes;

View File

@ -1,6 +1,6 @@
use alloc::{boxed::Box, sync::Arc};
use lock::Mutex;
use spin::Mutex;
use crate::prelude::{CapabilityType, InputEvent, InputEventType};
use crate::scheme::{impl_event_scheme, InputScheme};

View File

@ -1,10 +1,12 @@
use super::Io;
use core::mem::MaybeUninit;
use core::ops::{BitAnd, BitOr, Not};
// 主存映射 I/O。
/// Memory-mapped I/O.
use super::Io;
#[repr(transparent)]
pub struct Mmio<T>(T);
pub struct Mmio<T> {
value: MaybeUninit<T>,
}
impl<T> Mmio<T> {
/// # Safety
@ -23,7 +25,9 @@ impl<T> Mmio<T> {
}
pub fn add<'a>(&self, offset: usize) -> &'a mut Self {
unsafe { Self::from_base((&self.0 as *const T).add(offset) as _) }
unsafe {
Self::from_base(self.value.as_ptr() as usize + offset * core::mem::size_of::<T>())
}
}
}
@ -34,20 +38,10 @@ where
type Value = T;
fn read(&self) -> T {
#[allow(clippy::let_and_return)]
unsafe {
let val = core::ptr::read_volatile(&self.0 as *const _);
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
core::arch::asm!("fence i,r");
val
}
unsafe { core::ptr::read_volatile(self.value.as_ptr()) }
}
fn write(&mut self, value: T) {
unsafe {
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
core::arch::asm!("fence w,o");
core::ptr::write_volatile(&mut self.0 as *mut _, value)
};
unsafe { core::ptr::write_volatile(self.value.as_mut_ptr(), value) };
}
}

View File

@ -1,79 +1,55 @@
// 封装对外设地址空间的访问,包括内存映射 IO 和端口映射 IO。
//
// 要了解这两种访问外设的方式,查看[维基百科](https://en.wikipedia.org/wiki/Memory-mapped_I/O)。
//! Peripheral address space access, including memory-mapped IO and port-mapped IO.
//!
//! About these two methods of performing I/O, see [wikipedia](https://en.wikipedia.org/wiki/Memory-mapped_I/O).
use core::ops::{BitAnd, BitOr, Not};
mod mmio;
#[cfg(target_arch = "x86_64")]
mod pmio;
mod pio;
pub use mmio::Mmio;
#[cfg(target_arch = "x86_64")]
pub use pmio::Pmio;
pub use pio::Pio;
// 用于处理外设地址空间访问的接口。
/// An interface for dealing with device address space access.
pub trait Io {
// 可访问的对象的类型。
/// The type of object to access.
type Value: Copy
+ BitAnd<Output = Self::Value>
+ BitOr<Output = Self::Value>
+ Not<Output = Self::Value>;
// 从外设读取值。
/// Reads value from device.
fn read(&self) -> Self::Value;
// 向外设写入值。
/// Writes `value` to device.
fn write(&mut self, value: Self::Value);
}
// 外设地址空间的一个只读单元。
/// A readonly unit in device address space.
#[repr(transparent)]
pub struct ReadOnly<I>(I);
pub struct ReadOnly<I> {
inner: I,
}
impl<I> ReadOnly<I> {
// 构造外设地址空间的一个只读单元。
/// Constructs a readonly unit in device address space.
pub const fn new(inner: I) -> Self {
Self(inner)
pub const fn new(inner: I) -> ReadOnly<I> {
ReadOnly { inner }
}
}
impl<I: Io> ReadOnly<I> {
// 从外设读取值。
/// Reads value from device.
#[inline(always)]
pub fn read(&self) -> I::Value {
self.0.read()
self.inner.read()
}
}
// 外设地址空间的一个只写单元。
/// A write-only unit in device address space.
#[repr(transparent)]
pub struct WriteOnly<I>(I);
pub struct WriteOnly<I> {
inner: I,
}
impl<I> WriteOnly<I> {
// 构造外设地址空间的一个只写单元。
/// Constructs a write-only unit in device address space.
pub const fn new(inner: I) -> Self {
Self(inner)
pub const fn new(inner: I) -> WriteOnly<I> {
WriteOnly { inner }
}
}
impl<I: Io> WriteOnly<I> {
// 向外设写入值。
/// Writes `value` to device.
#[inline(always)]
pub fn write(&mut self, value: I::Value) {
self.0.write(value);
self.inner.write(value)
}
}

View File

@ -1,35 +1,30 @@
// 端口映射 I/O。
//! Port-mapped I/O.
use core::arch::asm;
use core::marker::PhantomData;
use super::Io;
use core::{arch::asm, marker::PhantomData};
// 端口映射 I/O。
/// Port-mapped I/O.
/// Generic PIO
#[derive(Copy, Clone)]
pub struct Pmio<T> {
pub struct Pio<T> {
port: u16,
_phantom: PhantomData<T>,
}
impl<T> Pmio<T> {
// 映射指定端口进行外设访问。
/// Maps a given port to assess device.
impl<T> Pio<T> {
/// Create a PIO from a given port
pub const fn new(port: u16) -> Self {
Self {
Pio::<T> {
port,
_phantom: PhantomData,
}
}
}
// 逐字节端口映射读写。
/// Read/Write for byte PMIO.
impl Io for Pmio<u8> {
/// Read/Write for byte PIO
impl Io for Pio<u8> {
type Value = u8;
// 读。
/// Read.
/// Read
#[inline(always)]
fn read(&self) -> u8 {
let value: u8;
@ -39,8 +34,7 @@ impl Io for Pmio<u8> {
value
}
// 写。
/// Write.
/// Write
#[inline(always)]
fn write(&mut self, value: u8) {
unsafe {
@ -49,13 +43,11 @@ impl Io for Pmio<u8> {
}
}
// 逐字端口映射读写。
/// Read/Write for word PMIO.
impl Io for Pmio<u16> {
/// Read/Write for word PIO
impl Io for Pio<u16> {
type Value = u16;
// 读。
/// Read.
/// Read
#[inline(always)]
fn read(&self) -> u16 {
let value: u16;
@ -65,8 +57,7 @@ impl Io for Pmio<u16> {
value
}
// 写。
/// Write.
/// Write
#[inline(always)]
fn write(&mut self, value: u16) {
unsafe {
@ -75,13 +66,11 @@ impl Io for Pmio<u16> {
}
}
// 逐双字端口映射读写。
/// Read/Write for double-word PMIO.
impl Io for Pmio<u32> {
/// Read/Write for doubleword PIO
impl Io for Pio<u32> {
type Value = u32;
// 读。
/// Read.
/// Read
#[inline(always)]
fn read(&self) -> u32 {
let value: u32;
@ -91,8 +80,7 @@ impl Io for Pmio<u32> {
value
}
// 写。
/// Write.
/// Write
#[inline(always)]
fn write(&mut self, value: u32) {
unsafe {

View File

@ -1,11 +1,8 @@
//! External interrupt request and handle.
cfg_if::cfg_if! {
if #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] {
mod riscv_intc;
mod riscv_plic;
/// Implementation of risc-v interrupt controller.
#[doc(cfg(any(target_arch = "riscv32", target_arch = "riscv64")))]
pub mod riscv {
pub use super::riscv_intc::{Intc, ScauseIntCode};
@ -13,7 +10,7 @@ cfg_if::cfg_if! {
}
} else if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
mod x86_apic;
/// Implementation of x86 Advanced Programmable Interrupt Controller.
#[doc(cfg(any(target_arch = "x86", target_arch = "x86_64")))]
pub mod x86 {
pub use super::x86_apic::Apic;

View File

@ -1,5 +1,5 @@
use lock::Mutex;
use riscv::register::sie;
use spin::Mutex;
use crate::prelude::IrqHandler;
use crate::scheme::{IrqScheme, Scheme};

View File

@ -1,7 +1,6 @@
use core::arch::asm;
use core::ops::Range;
use lock::Mutex;
use spin::Mutex;
use crate::io::{Io, Mmio};
use crate::prelude::IrqHandler;
@ -39,7 +38,8 @@ impl PlicUnlocked {
let hart_id = cpu_id() as usize;
let mmio = self
.enable_base
.add(PLIC_ENABLE_HART_OFFSET * hart_id + irq_num / 32);
.add(PLIC_ENABLE_HART_OFFSET * hart_id)
.add(irq_num / 32);
let mask = 1 << (irq_num % 32);
if enable {
@ -54,7 +54,8 @@ impl PlicUnlocked {
let hart_id = cpu_id() as usize;
let irq_num = self
.context_base
.add(PLIC_CONTEXT_CLAIM_HART_OFFSET * hart_id + PLIC_CONTEXT_CLAIM)
.add(PLIC_CONTEXT_CLAIM_HART_OFFSET * hart_id)
.add(PLIC_CONTEXT_CLAIM)
.read() as usize;
if irq_num == 0 {
None
@ -68,7 +69,8 @@ impl PlicUnlocked {
debug_assert!(IRQ_RANGE.contains(&irq_num));
let hart_id = cpu_id() as usize;
self.context_base
.add(PLIC_CONTEXT_CLAIM + PLIC_CONTEXT_CLAIM_HART_OFFSET * hart_id)
.add(PLIC_CONTEXT_CLAIM)
.add(PLIC_CONTEXT_CLAIM_HART_OFFSET * hart_id)
.write(irq_num as _);
}
@ -82,7 +84,8 @@ impl PlicUnlocked {
fn set_threshold(&mut self, threshold: u8) {
let hart_id = cpu_id() as usize;
self.context_base
.add(PLIC_PRIORITY_HART_OFFSET * hart_id + PLIC_CONTEXT_THRESHOLD)
.add(PLIC_PRIORITY_HART_OFFSET * hart_id)
.add(PLIC_CONTEXT_THRESHOLD)
.write(threshold as _);
}

View File

@ -3,7 +3,7 @@ use core::{fmt, ptr::NonNull};
use acpi::platform::interrupt::InterruptModel;
use acpi::{AcpiHandler, AcpiTables, PhysicalMapping};
use lock::Mutex;
use spin::Mutex;
use x2apic::ioapic::{IoApic as IoApicInner, IrqFlags, IrqMode};
use super::{IrqPolarity, IrqTriggerMode, Phys2VirtFn};
@ -66,23 +66,9 @@ impl IoApic {
let mut inner = unsafe { IoApicInner::new(base_vaddr as u64) };
let max_entry = unsafe { inner.max_table_entry() };
unsafe { assert_eq!(id, inner.id()) };
unsafe {
inner.init(super::X86_INT_BASE as u8);
}
// disable all interrupts
for i in 0..max_entry + 1 {
unsafe {
// disable all interrupts
inner.disable_irq(i);
// Clean the redirection table
let mut entry = inner.table_entry(i);
entry.set_vector(0);
entry.set_dest(0);
entry.set_mode(IrqMode::Fixed);
entry.set_flags(IrqFlags::MASKED);
inner.set_table_entry(i, entry);
}
unsafe { inner.disable_irq(i) }
}
Self {
id,

View File

@ -1,6 +1,4 @@
use x2apic::lapic::{
xapic_base, LocalApic as LocalApicInner, LocalApicBuilder, TimerDivide, TimerMode,
};
use x2apic::lapic::{xapic_base, LocalApic as LocalApicInner, LocalApicBuilder};
use super::{consts, Phys2VirtFn};
@ -49,24 +47,4 @@ impl LocalApic {
pub fn eoi(&mut self) {
unsafe { self.inner.end_of_interrupt() }
}
pub fn disable_timer(&mut self) {
unsafe { self.inner.disable_timer() }
}
pub fn enable_timer(&mut self) {
unsafe { self.inner.enable_timer() }
}
pub fn set_timer_mode(&mut self, mode: TimerMode) {
unsafe { self.inner.set_timer_mode(mode) }
}
pub fn set_timer_divide(&mut self, divide: TimerDivide) {
unsafe { self.inner.set_timer_divide(divide) }
}
pub fn set_timer_initial(&mut self, initial: u32) {
unsafe { self.inner.set_timer_initial(initial) }
}
}

View File

@ -2,21 +2,22 @@ mod consts;
mod ioapic;
mod lapic;
use core::ops::Range;
use spin::Mutex;
use self::consts::{X86_INT_BASE, X86_INT_LOCAL_APIC_BASE};
use self::ioapic::{IoApic, IoApicList};
use self::lapic::LocalApic;
use crate::prelude::{IrqHandler, IrqPolarity, IrqTriggerMode};
use crate::scheme::{IrqScheme, Scheme};
use crate::{utils::IrqManager, DeviceError, DeviceResult, PhysAddr, VirtAddr};
use core::ops::Range;
use lock::Mutex;
const IOAPIC_IRQ_RANGE: Range<usize> = X86_INT_BASE..X86_INT_LOCAL_APIC_BASE;
const LAPIC_IRQ_RANGE: Range<usize> = 0..16;
type Phys2VirtFn = fn(paddr: PhysAddr) -> VirtAddr;
/// Advanced Programmable Interrupt Controller
pub struct Apic {
ioapic_list: IoApicList,
manager_ioapic: Mutex<IrqManager<256>>,
@ -24,7 +25,6 @@ pub struct Apic {
}
impl Apic {
/// Construct a new `Apic`.
pub fn new(acpi_rsdp: usize, phys_to_virt: Phys2VirtFn) -> Self {
Self {
ioapic_list: IoApicList::new(acpi_rsdp, phys_to_virt),
@ -81,8 +81,9 @@ impl Scheme for Apic {
fn handle_irq(&self, vector: usize) {
Self::local_apic().eoi();
let res = if vector >= X86_INT_LOCAL_APIC_BASE {
let handler = self.manager_lapic.lock();
handler.handle(vector - X86_INT_LOCAL_APIC_BASE)
self.manager_lapic
.lock()
.handle(vector - X86_INT_LOCAL_APIC_BASE)
} else {
self.manager_ioapic.lock().handle(vector)
};
@ -168,9 +169,4 @@ impl IrqScheme for Apic {
Err(DeviceError::InvalidParam)
}
}
fn apic_timer_enable(&self) {
// SAFETY: this will called only once for every core
Apic::local_apic().enable_timer();
}
}

View File

@ -1,5 +1,3 @@
//! Device drivers of zCore.
#![cfg_attr(not(feature = "mock"), no_std)]
#![feature(doc_cfg)]
@ -20,7 +18,6 @@ pub mod mock;
pub mod virtio;
pub mod builder;
pub mod bus;
pub mod display;
pub mod input;
pub mod io;
@ -31,7 +28,6 @@ pub mod scheme;
pub mod uart;
pub mod utils;
/// The error type for external device.
#[derive(Debug)]
pub enum DeviceError {
/// The buffer is too small.
@ -52,28 +48,19 @@ pub enum DeviceError {
NotSupported,
}
/// A type alias for the result of a device operation.
pub type DeviceResult<T = ()> = core::result::Result<T, DeviceError>;
/// Static shell of shared dynamic device [`Scheme`](crate::scheme::Scheme) types.
#[derive(Clone)]
pub enum Device {
/// Block device
Block(Arc<dyn scheme::BlockScheme>),
/// Display device
Display(Arc<dyn scheme::DisplayScheme>),
/// Input device
Input(Arc<dyn scheme::InputScheme>),
/// Interrupt request and handle
Irq(Arc<dyn scheme::IrqScheme>),
/// Network device
Net(Arc<dyn scheme::NetScheme>),
/// Uart port
Uart(Arc<dyn scheme::UartScheme>),
}
impl Device {
/// Get a general [`Scheme`](scheme::Scheme) from the device.
pub fn inner(&self) -> Arc<dyn scheme::Scheme> {
match self {
Self::Block(d) => d.clone().upcast(),

View File

@ -1,5 +1,3 @@
//! Mock devices, including display, input, uart and graphic.
pub mod display;
pub mod input;
pub mod uart;

View File

@ -1,7 +1,7 @@
use std::collections::VecDeque;
use async_std::{io, io::prelude::*, task};
use lock::Mutex;
use spin::Mutex;
use crate::scheme::{impl_event_scheme, Scheme, UartScheme};
use crate::utils::EventListener;

View File

@ -1,218 +0,0 @@
//! Intel PRO/1000 Network Adapter i.e. e1000 network driver
//! Datasheet: https://www.intel.ca/content/dam/doc/datasheet/82574l-gbe-controller-datasheet.pdf
use alloc::collections::BTreeMap;
use alloc::string::String;
use alloc::sync::Arc;
use alloc::vec::Vec;
use smoltcp::iface::*;
use smoltcp::phy::{self, DeviceCapabilities};
use smoltcp::time::Instant;
use smoltcp::wire::*;
use smoltcp::Result;
use super::ProviderImpl;
use super::PAGE_SIZE;
use crate::net::get_sockets;
use crate::scheme::{NetScheme, Scheme};
use crate::{DeviceError, DeviceResult};
use isomorphic_drivers::net::ethernet::intel::e1000::E1000;
use isomorphic_drivers::net::ethernet::structs::EthernetAddress as DriverEthernetAddress;
use lock::Mutex;
#[derive(Clone)]
pub struct E1000Driver(Arc<Mutex<E1000<ProviderImpl>>>);
#[derive(Clone)]
pub struct E1000Interface {
iface: Arc<Mutex<Interface<'static, E1000Driver>>>,
driver: E1000Driver,
name: String,
irq: usize,
}
impl Scheme for E1000Interface {
fn name(&self) -> &str {
"e1000"
}
fn handle_irq(&self, irq: usize) {
if irq != self.irq {
// not ours, skip it
return;
}
let data = self.driver.0.lock().handle_interrupt();
if data {
//let timestamp = Instant::from_millis(crate::trap::uptime_msec() as i64);
// Fix me
let timestamp = Instant::from_millis(0);
let sockets = get_sockets();
let mut sockets = sockets.lock();
match self.iface.lock().poll(&mut sockets, timestamp) {
Ok(p) => {
//SOCKET_ACTIVITY.notify_all();
info!("e1000 try_handle_interrupt poll: {:?}", p);
}
Err(err) => {
warn!("poll got err {}", err);
}
}
}
}
}
impl NetScheme for E1000Interface {
fn get_mac(&self) -> EthernetAddress {
self.iface.lock().ethernet_addr()
}
fn get_ifname(&self) -> String {
self.name.clone()
}
// get ip addresses
fn get_ip_address(&self) -> Vec<IpCidr> {
Vec::from(self.iface.lock().ip_addrs())
}
fn poll(&self) -> DeviceResult {
//let timestamp = Instant::from_millis(crate::trap::uptime_msec() as i64);
let timestamp = Instant::from_millis(0);
let sockets = get_sockets();
let mut sockets = sockets.lock();
match self.iface.lock().poll(&mut sockets, timestamp) {
Ok(p) => {
//SOCKET_ACTIVITY.notify_all();
info!("e1000 NetScheme poll: {:?}", p);
Ok(())
}
Err(err) => {
warn!("poll got err {}", err);
Err(DeviceError::IoError)
}
}
}
fn recv(&self, buf: &mut [u8]) -> DeviceResult<usize> {
if let Some(vec_recv) = self.driver.0.lock().receive() {
buf.copy_from_slice(&vec_recv);
Ok(vec_recv.len())
} else {
Err(DeviceError::NotReady)
}
}
fn send(&self, data: &[u8]) -> DeviceResult<usize> {
if self.driver.0.lock().can_send() {
let mut driver = self.driver.0.lock();
driver.send(data);
Ok(data.len())
} else {
Err(DeviceError::NotReady)
}
}
}
pub struct E1000RxToken(Vec<u8>);
pub struct E1000TxToken(E1000Driver);
impl phy::Device<'_> for E1000Driver {
type RxToken = E1000RxToken;
type TxToken = E1000TxToken;
fn receive(&mut self) -> Option<(Self::RxToken, Self::TxToken)> {
self.0
.lock()
.receive()
.map(|vec| (E1000RxToken(vec), E1000TxToken(self.clone())))
}
fn transmit(&mut self) -> Option<Self::TxToken> {
if self.0.lock().can_send() {
Some(E1000TxToken(self.clone()))
} else {
None
}
}
fn capabilities(&self) -> DeviceCapabilities {
let mut caps = DeviceCapabilities::default();
caps.max_transmission_unit = 1536;
caps.max_burst_size = Some(64);
caps
}
}
impl phy::RxToken for E1000RxToken {
fn consume<R, F>(mut self, _timestamp: Instant, f: F) -> Result<R>
where
F: FnOnce(&mut [u8]) -> Result<R>,
{
f(&mut self.0)
}
}
impl phy::TxToken for E1000TxToken {
fn consume<R, F>(self, _timestamp: Instant, len: usize, f: F) -> Result<R>
where
F: FnOnce(&mut [u8]) -> Result<R>,
{
let mut buffer = [0u8; PAGE_SIZE];
let result = f(&mut buffer[..len]);
let mut driver = (self.0).0.lock();
driver.send(&buffer);
result
}
}
// JudgeDuck-OS/kern/e1000.c
pub fn init(
name: String,
irq: usize,
header: usize,
size: usize,
index: usize,
) -> DeviceResult<E1000Interface> {
info!("Probing e1000 {}", name);
// randomly generated
let mac: [u8; 6] = [0x54, 0x51, 0x9F, 0x71, 0xC0, index as u8];
let e1000 = E1000::new(header, size, DriverEthernetAddress::from_bytes(&mac));
let net_driver = E1000Driver(Arc::new(Mutex::new(e1000)));
let ethernet_addr = EthernetAddress::from_bytes(&mac);
let ip_addrs = [IpCidr::new(IpAddress::v4(10, 0, 2, (15 + index) as u8), 24)];
let default_v4_gw = Ipv4Address::new(10, 0, 2, 2); //Qemu user network gateway: 10.0.2.2
static mut ROUTES_STORAGE: [Option<(IpCidr, Route)>; 1] = [None; 1];
let mut routes = unsafe { Routes::new(&mut ROUTES_STORAGE[..]) };
routes.add_default_ipv4_route(default_v4_gw).unwrap();
let neighbor_cache = NeighborCache::new(BTreeMap::new());
let iface = InterfaceBuilder::new(net_driver.clone())
.ethernet_addr(ethernet_addr)
.neighbor_cache(neighbor_cache)
.ip_addrs(ip_addrs)
.routes(routes)
.finalize();
info!(
"e1000 interface {} up with addr 10.0.2.{}/24",
name,
15 + index
);
let e1000_iface = E1000Interface {
iface: Arc::new(Mutex::new(iface)),
driver: net_driver,
name,
irq,
};
Ok(e1000_iface)
}

View File

@ -5,7 +5,7 @@ use crate::net::get_sockets;
use alloc::sync::Arc;
use alloc::string::String;
use lock::Mutex;
use spin::Mutex;
use crate::scheme::{NetScheme, Scheme};
use crate::{DeviceError, DeviceResult};
@ -54,7 +54,7 @@ impl NetScheme for LoopbackInterface {
fn get_ifname(&self) -> String {
unimplemented!()
}
fn get_ip_address(&self) -> Vec<IpCidr> {
fn get_ip_addrrs(&self) -> Vec<IpCidr> {
unimplemented!()
}
}

View File

@ -1,6 +1,3 @@
//! LAN driver, only for Realtek currently.
pub mod e1000;
cfg_if::cfg_if! {
if #[cfg(target_arch = "riscv64")] {
mod realtek;
@ -10,7 +7,6 @@ pub use rtlx::*;
}
}
/*
/// External functions that drivers must use
pub trait Provider {
/// Page size (usually 4K)
@ -24,8 +20,6 @@ pub trait Provider {
/// Deallocate DMA
fn dealloc_dma(vaddr: usize, size: usize);
}
*/
pub use isomorphic_drivers::provider::Provider;
pub struct ProviderImpl;
@ -69,7 +63,7 @@ pub use loopback::LoopbackInterface;
use alloc::sync::Arc;
use alloc::vec;
use lock::Mutex;
use spin::Mutex;
use smoltcp::socket::SocketSet;

View File

@ -214,6 +214,7 @@ impl<P> RTL8211F<P>
where
P: Provider,
{
#[allow(clippy::clone_on_copy)]
pub fn new(mac_addr: &[u8; 6]) -> Self {
assert_eq!(size_of::<dma_desc>(), 16);
@ -234,7 +235,7 @@ where
mac[i] = u8::from_str_radix(s, 16).unwrap();
}
} else {
mac = *mac_addr;
mac = mac_addr.clone();
}
info!(
@ -1141,10 +1142,12 @@ where
status = tx_dma_irq_status::tx_hard_error as i32;
}
#[allow(clippy::collapsible_if)]
/* 正常的 TX/RX NORMAL interrupts */
// (intr_status & (TX_INT | RX_INT | RX_EARLY_INT | TX_UA_INT)) != 0
if (intr_status & (TX_INT | RX_INT)) != 0 {
status = tx_dma_irq_status::handle_tx_rx as i32;
if (intr_status & (TX_INT | RX_INT | RX_EARLY_INT | TX_UA_INT)) != 0 {
if (intr_status & (TX_INT | RX_INT)) != 0 {
status = tx_dma_irq_status::handle_tx_rx as i32;
}
}
/* Clear the interrupt by writing a logic 1 to the CSR5[15-0] */
write_volatile((self.base + GETH_INT_STA) as *mut u32, intr_status & 0x3FFF);
@ -1431,6 +1434,7 @@ where
match speed {
1000 => ctrl &= !0x0C,
/*100 | 10 |*/
_ => {
ctrl |= 0x08;
if (speed == 100) {

View File

@ -1,6 +1,6 @@
// c906
use core::arch::asm;
// c906
const FREQUENCY: u64 = 24_000_000; // C906: 24_000_000, Qemu: 10_000_000
const MMIO_MTIMECMP0: *mut u64 = 0x0200_4000usize as *mut u64;
const MMIO_MTIME: *const u64 = 0x0200_BFF8 as *const u64;

View File

@ -1,13 +1,13 @@
use alloc::collections::BTreeMap;
use alloc::string::String;
use alloc::sync::Arc;
// use alloc::vec;
use alloc::vec;
use alloc::vec::Vec;
use lock::Mutex;
use spin::Mutex;
use smoltcp::iface::*;
use smoltcp::phy::{self, Device, DeviceCapabilities, Medium};
// use smoltcp::socket::SocketSet;
use smoltcp::socket::SocketSet;
use smoltcp::time::Instant;
use smoltcp::wire::*;
use smoltcp::Result;
@ -18,7 +18,6 @@ use super::ProviderImpl;
use super::PAGE_SIZE;
//use kernel_hal::drivers::{Driver, DeviceType, NetDriver, DRIVERS, NET_DRIVERS, SOCKETS};
use crate::net::get_sockets;
use crate::scheme::{NetScheme, Scheme};
use crate::{DeviceError, DeviceResult};
@ -49,13 +48,13 @@ impl Scheme for RTLxInterface {
let handle_tx_rx = 3;
if status == handle_tx_rx {
let timestamp = Instant::from_millis(0);
let sockets = get_sockets();
let mut sockets = sockets.lock();
let mut sockets = SOCKETS.lock(); //引发死锁?
self.driver.0.lock().int_disable();
match self.iface.lock().poll(&mut sockets, timestamp) {
Ok(b) => {
debug!("nic poll, is changed ?: {}", b);
Ok(_) => {
//SOCKET_ACTIVITY.notify_all();
debug!("try_handle_interrupt SOCKET_ACTIVITY unimplemented");
}
Err(err) => {
error!("poll got err {}", err);
@ -76,17 +75,17 @@ impl NetScheme for RTLxInterface {
self.name.clone()
}
fn get_ip_address(&self) -> Vec<IpCidr> {
fn get_ip_addrrs(&self) -> Vec<IpCidr> {
Vec::from(self.iface.lock().ip_addrs())
}
fn poll(&self) -> DeviceResult {
let timestamp = Instant::from_millis(0);
let sockets = get_sockets();
let mut sockets = sockets.lock();
let mut sockets = SOCKETS.lock();
match self.iface.lock().poll(&mut sockets, timestamp) {
Ok(b) => {
debug!("nic poll, is changed ?: {}", b);
Ok(_) => {
//SOCKET_ACTIVITY.notify_all();
error!("poll, SOCKET_ACTIVITY unimplemented");
Ok(())
}
Err(err) => {
@ -193,20 +192,14 @@ pub fn rtlx_init<F: Fn(usize, usize) -> Option<usize>>(
let ethernet_addr = EthernetAddress::from_bytes(&mac);
let ip_addrs = [IpCidr::new(IpAddress::v4(192, 168, 0, 123), 24)];
let default_gateway = Ipv4Address::new(192, 168, 0, 1);
static mut ROUTES_STORAGE: [Option<(IpCidr, Route)>; 1] = [None; 1];
let mut routes = unsafe { Routes::new(&mut ROUTES_STORAGE[..]) };
routes.add_default_ipv4_route(default_gateway).unwrap();
let neighbor_cache = NeighborCache::new(BTreeMap::new());
let iface = InterfaceBuilder::new(net_driver.clone())
.ethernet_addr(ethernet_addr)
.neighbor_cache(neighbor_cache)
.ip_addrs(ip_addrs)
.routes(routes)
.finalize();
info!("rtl8211f interface up with addr 192.168.0.123/24");
info!("rtl8211f interface up with route 192.168.0.1/24");
let rtl8211f_iface = RTLxInterface {
iface: Arc::new(Mutex::new(iface)),
driver: net_driver,
@ -218,7 +211,7 @@ pub fn rtlx_init<F: Fn(usize, usize) -> Option<usize>>(
}
//TODO: Global SocketSet
// lazy_static::lazy_static! {
// pub static ref SOCKETS: Mutex<SocketSet<'static>> =
// Mutex::new(SocketSet::new(vec![]));
// }
lazy_static::lazy_static! {
pub static ref SOCKETS: Mutex<SocketSet<'static>> =
Mutex::new(SocketSet::new(vec![]));
}

View File

@ -1,11 +1,8 @@
//! Re-export most commonly used driver types.
pub use crate::scheme::display::{ColorFormat, DisplayInfo, FrameBuffer, Rectangle, RgbColor};
pub use crate::scheme::input::{CapabilityType, InputCapability, InputEvent, InputEventType};
pub use crate::scheme::irq::{IrqHandler, IrqPolarity, IrqTriggerMode};
pub use crate::{Device, DeviceError, DeviceResult};
/// Re-export types from [`input`](crate::input).
pub mod input {
pub use crate::input::{Mouse, MouseFlags, MouseState};
}

View File

@ -5,7 +5,6 @@ use core::ops::Range;
use super::Scheme;
use crate::DeviceResult;
/// A type alias for
pub type IrqHandler = Box<dyn Fn() + Send + Sync>;
#[derive(Debug)]
@ -76,9 +75,4 @@ pub trait IrqScheme: Scheme {
fn init_hart(&self) {
unimplemented!()
}
/// [for x86_64] enable apic timer
fn apic_timer_enable(&self) {
unimplemented!()
}
}

View File

@ -1,5 +1,5 @@
//! The [`Scheme`] describe some functions must be implemented for different type of devices,
//! there are many [`Scheme`] traits in this mod.
//! The [`Scheme`] describe some functions must be implemented for device, there are
//! many [`Scheme`] traits in this mod.
//!
//! If you need to develop a new device, just implement the corresponding trait.
//!
@ -26,20 +26,12 @@ pub use irq::IrqScheme;
pub use net::NetScheme;
pub use uart::UartScheme;
/// Common of all device drivers.
///
/// Every device must says its name and handles interrupts.
pub trait Scheme: SchemeUpcast + Send + Sync {
/// Returns name of the driver.
fn name(&self) -> &str;
/// Handles an interrupt.
fn handle_irq(&self, _irq_num: usize) {}
}
/// Used to convert a concrete type pointer to a general [`Scheme`] pointer.
pub trait SchemeUpcast {
/// Performs the conversion.
fn upcast<'a>(self: Arc<Self>) -> Arc<dyn Scheme + 'a>
where
Self: 'a;

View File

@ -9,6 +9,6 @@ pub trait NetScheme: Scheme {
fn send(&self, buf: &[u8]) -> DeviceResult<usize>;
fn get_mac(&self) -> EthernetAddress;
fn get_ifname(&self) -> String;
fn get_ip_address(&self) -> Vec<IpCidr>;
fn get_ip_addrrs(&self) -> Vec<IpCidr>;
fn poll(&self) -> DeviceResult;
}

View File

@ -1,6 +1,6 @@
use alloc::{boxed::Box, collections::VecDeque, string::String, sync::Arc};
use lock::Mutex;
use spin::Mutex;
use crate::scheme::{impl_event_scheme, Scheme, UartScheme};
use crate::utils::EventListener;

View File

@ -1,5 +1,3 @@
//! Uart device driver.
mod buffered;
mod uart_16550;
@ -7,4 +5,4 @@ pub use buffered::BufferedUart;
pub use uart_16550::Uart16550Mmio;
#[cfg(target_arch = "x86_64")]
pub use uart_16550::Uart16550Pmio;
pub use uart_16550::Uart16550Pio;

View File

@ -2,7 +2,7 @@ use core::convert::TryInto;
use core::ops::{BitAnd, BitOr, Not};
use bitflags::bitflags;
use lock::Mutex;
use spin::Mutex;
use crate::io::{Io, Mmio, ReadOnly};
use crate::scheme::{impl_event_scheme, Scheme, UartScheme};
@ -106,7 +106,6 @@ where
}
}
/// MMIO driver for UART 16550
pub struct Uart16550Mmio<V: 'static>
where
V: Copy + BitAnd<Output = V> + BitOr<Output = V> + Not<Output = V>,
@ -201,21 +200,20 @@ impl Uart16550Mmio<u32> {
}
#[cfg(target_arch = "x86_64")]
mod pmio {
mod pio {
use super::*;
use crate::io::Pmio;
use crate::io::Pio;
/// Pmio driver for UART 16550
pub struct Uart16550Pmio {
inner: Mutex<Uart16550Inner<Pmio<u8>>>,
pub struct Uart16550Pio {
inner: Mutex<Uart16550Inner<Pio<u8>>>,
listener: EventListener,
}
impl_event_scheme!(Uart16550Pmio);
impl_event_scheme!(Uart16550Pio);
impl Scheme for Uart16550Pmio {
impl Scheme for Uart16550Pio {
fn name(&self) -> &str {
"uart16550-Pmio"
"uart16550-pio"
}
fn handle_irq(&self, _irq_num: usize) {
@ -223,7 +221,7 @@ mod pmio {
}
}
impl UartScheme for Uart16550Pmio {
impl UartScheme for Uart16550Pio {
fn try_recv(&self) -> DeviceResult<Option<u8>> {
self.inner.lock().try_recv()
}
@ -237,17 +235,16 @@ mod pmio {
}
}
impl Uart16550Pmio {
/// Construct a `Uart16550Pmio` whose address starts at `base`.
impl Uart16550Pio {
pub fn new(base: u16) -> Self {
let mut uart = Uart16550Inner::<Pmio<u8>> {
data: Pmio::new(base),
int_en: Pmio::new(base + 1),
fifo_ctrl: Pmio::new(base + 2),
line_ctrl: Pmio::new(base + 3),
modem_ctrl: Pmio::new(base + 4),
line_sts: ReadOnly::new(Pmio::new(base + 5)),
modem_sts: ReadOnly::new(Pmio::new(base + 6)),
let mut uart = Uart16550Inner::<Pio<u8>> {
data: Pio::new(base),
int_en: Pio::new(base + 1),
fifo_ctrl: Pio::new(base + 2),
line_ctrl: Pio::new(base + 3),
modem_ctrl: Pio::new(base + 4),
line_sts: ReadOnly::new(Pio::new(base + 5)),
modem_sts: ReadOnly::new(Pio::new(base + 6)),
};
uart.init();
Self {
@ -259,4 +256,4 @@ mod pmio {
}
#[cfg(target_arch = "x86_64")]
pub use pmio::Uart16550Pmio;
pub use pio::Uart16550Pio;

View File

@ -1,10 +1,10 @@
//! Package of [`device_tree`].
use crate::{DeviceError, DeviceResult, PhysAddr, VirtAddr};
use alloc::vec::Vec;
use core::ops::Range;
use device_tree::{DeviceTree as DeviceTreeInner, PropError};
use crate::{DeviceError, DeviceResult, PhysAddr, VirtAddr};
pub use device_tree::{util::StringList, Node};
/// A unified representation of the `interrupts` and `interrupts_extended`

View File

@ -1,35 +1,24 @@
use alloc::{boxed::Box, vec::Vec};
use lock::Mutex;
use spin::Mutex;
/// A type alias for the closure to handle device event.
pub type EventHandler<T = ()> = Box<dyn Fn(&T) + Send + Sync>;
/// Device event listener.
///
/// It keeps a series of [`EventHandler`]s that handle events of one single type.
pub struct EventListener<T = ()> {
events: Mutex<Vec<(EventHandler<T>, bool)>>,
}
impl<T> EventListener<T> {
/// Construct a new, empty `EventListener`.
pub fn new() -> Self {
Self {
events: Mutex::new(Vec::new()),
}
}
/// Register a new `handler` into this `EventListener`.
///
/// If `once` is `true`, the `handler` will be removed once it handles an event.
pub fn subscribe(&self, handler: EventHandler<T>, once: bool) {
self.events.lock().push((handler, once));
}
/// Send an event to the `EventListener`.
///
/// All the handlers handle the event, and those marked `once` will be removed immediately.
pub fn trigger(&self, event: T) {
self.events.lock().retain(|(f, once)| {
f(&event);

View File

@ -1,5 +1,3 @@
//! Event handler and device tree.
#![allow(unused_imports)]
mod event_listener;

View File

@ -1,4 +1,4 @@
use lock::Mutex;
use spin::Mutex;
use virtio_drivers::{VirtIOBlk as InnerDriver, VirtIOHeader};
use crate::scheme::{BlockScheme, Scheme};

View File

@ -1,6 +1,6 @@
use core::fmt::{Result, Write};
use lock::Mutex;
use spin::Mutex;
use virtio_drivers::{VirtIOConsole as InnerDriver, VirtIOHeader};
use crate::prelude::DeviceResult;

View File

@ -1,4 +1,4 @@
use lock::Mutex;
use spin::Mutex;
use virtio_drivers::{VirtIOGpu as InnerDriver, VirtIOHeader};
use crate::prelude::{ColorFormat, DisplayInfo, FrameBuffer};

View File

@ -1,6 +1,6 @@
use core::convert::TryFrom;
use lock::Mutex;
use spin::Mutex;
use virtio_drivers::{InputConfigSelect, VirtIOHeader, VirtIOInput as InnerDriver};
use crate::prelude::{CapabilityType, InputCapability, InputEvent, InputEventType};

View File

@ -1,5 +1,3 @@
//! Packaging of [`virtio-drivers` library](https://github.com/rcore-os/virtio-drivers).
mod blk;
mod console;
mod gpu;

View File

@ -1,10 +1,7 @@
[package]
name = "kernel-hal"
version = "0.1.0"
authors = [
"Runji Wang <wangrunji0408@163.com>",
"Yuekai Jia <equation618@gmail.com>",
]
authors = ["Runji Wang <wangrunji0408@163.com>", "Yuekai Jia <equation618@gmail.com>"]
edition = "2018"
description = "Kernel HAL interface definations."
@ -13,40 +10,32 @@ description = "Kernel HAL interface definations."
[features]
default = ["libos"]
smp = []
libos = [
"nix",
"tempfile",
"async-std",
"bitmap-allocator",
"zcore-drivers/mock",
]
libos = ["nix", "tempfile", "async-std", "bitmap-allocator", "zcore-drivers/mock"]
graphic = ["zcore-drivers/graphic"]
loopback = []
[dependencies]
log = "0.4"
spin = "0.9"
cfg-if = "1.0"
bitflags = "1.3"
trapframe = "0.9.0"
trapframe = "0.9"
git-version = "0.3"
numeric-enum-macro = "0.2"
lazy_static = { version = "1.4", features = ["spin_no_std"] }
zcore-drivers = { path = "../drivers", features = ["virtio"] }
lock = { git = "https://github.com/DeathWish5/kernel-sync", rev = "01b2e70" }
smoltcp = { git = "https://github.com/smoltcp-rs/smoltcp", rev = "35e833e3", default-features = false, features = ["log", "alloc", "verbose", "proto-ipv4", "proto-ipv6", "proto-igmp", "medium-ip", "medium-ethernet", "socket-raw", "socket-udp", "socket-tcp", "socket-icmp", "async"] }
smoltcp = { git = "https://gitee.com/gcyyfun/smoltcp", rev="043eb60", default-features = false, features = ["alloc","log", "async", "medium-ethernet","proto-ipv4", "proto-igmp", "socket-icmp", "socket-udp", "socket-tcp", "socket-raw"] }
# LibOS mode
[target.'cfg(not(target_os = "none"))'.dependencies]
nix = { version = "0.23", optional = true }
tempfile = { version = "3", optional = true }
async-std = { version = "1.10", optional = true }
bitmap-allocator = { git = "https://github.com/rcore-os/bitmap-allocator.git", rev = "88e871a5", optional = true }
bitmap-allocator = { git = "https://github.com/rcore-os/bitmap-allocator", rev = "b3f9f51", optional = true }
# Bare-metal mode
[target.'cfg(target_os = "none")'.dependencies]
executor = { git = "https://github.com/DeathWish5/PreemptiveScheduler", rev = "3b04ba4" }
executor = { git = "https://github.com/rcore-os/executor.git", rev = "85b9335" }
naive-timer = "0.2.0"
# All mode on x86_64
@ -59,8 +48,7 @@ x86_64 = "0.14"
uefi = "0.11"
raw-cpuid = "9.0"
x86-smpboot = { git = "https://github.com/rcore-os/x86-smpboot", rev = "1069df3" }
x2apic = "0.4"
# Bare-metal mode on riscv64
[target.'cfg(all(target_os = "none", target_arch = "riscv64"))'.dependencies]
riscv = "0.8"
riscv = { git = "https://github.com/rust-embedded/riscv", rev = "cd31989", features = ["inline-asm"] }

View File

@ -1,4 +1,5 @@
//! CPU information.
use crate::utils::init_once::InitOnce;
pub(super) static CPU_FREQ_MHZ: InitOnce<u16> = InitOnce::new_with_default(10);

View File

@ -62,37 +62,6 @@ pub(super) fn init() -> DeviceResult {
}
}
#[cfg(not(feature = "loopback"))]
{
use alloc::sync::Arc;
use zcore_drivers::bus::pci;
let pci_devs = pci::init(Some(Arc::new(IoMapperImpl)))?;
for d in pci_devs.into_iter() {
drivers::add_device(d);
}
}
intc_init()?;
#[cfg(feature = "graphic")]
if let Some(display) = drivers::all_display().first() {
crate::console::init_graphic_console(display.clone());
if display.need_flush() {
// TODO: support nested interrupt to render in time
crate::thread::spawn(crate::common::future::DisplayFlushFuture::new(display, 30));
}
}
#[cfg(feature = "loopback")]
{
use crate::net;
net::init();
}
Ok(())
}
pub(super) fn intc_init() -> DeviceResult {
let irq = drivers::all_irq()
.find(format!("riscv-intc-cpu{}", crate::cpu::cpu_id()).as_str())
.expect("IRQ device 'riscv-intc' not initialized!");
@ -109,5 +78,14 @@ pub(super) fn intc_init() -> DeviceResult {
irq.unmask(ScauseIntCode::SupervisorSoft as _)?;
irq.unmask(ScauseIntCode::SupervisorTimer as _)?;
#[cfg(feature = "graphic")]
if let Some(display) = drivers::all_display().first() {
crate::console::init_graphic_console(display.clone());
if display.need_flush() {
// TODO: support nested interrupt to render in time
crate::thread::spawn(crate::common::future::DisplayFlushFuture::new(display, 30));
}
}
Ok(())
}

View File

@ -5,13 +5,11 @@ use riscv::{asm, register::sstatus};
hal_fn_impl! {
impl mod crate::hal_fn::interrupt {
fn wait_for_interrupt() {
let enable = sstatus::read().sie();
if !enable {
unsafe { sstatus::set_sie() };
}
unsafe { asm::wfi(); }
if !enable {
unsafe { sstatus::clear_sie() };
unsafe {
// enable interrupt and disable
sstatus::set_sie();
asm::wfi();
sstatus::clear_sie();
}
}
@ -19,17 +17,5 @@ hal_fn_impl! {
trace!("Handle irq cause: {}", cause);
crate::drivers::all_irq().first_unwrap().handle_irq(cause)
}
fn intr_on() {
unsafe { sstatus::set_sie() };
}
fn intr_off() {
unsafe { sstatus::clear_sie() };
}
fn intr_get() -> bool {
sstatus::read().sie()
}
}
}

View File

@ -23,12 +23,12 @@ pub fn free_pmem_regions() -> Vec<Range<PhysAddr>> {
}
if let Some(initrd) = initrd {
// no overlap at all
if initrd.end <= start || end <= initrd.start {
if initrd.end <= start || initrd.start >= end {
regions.push(start..end);
continue;
}
// no overlap on the left
if start < initrd.start {
if initrd.start > start {
regions.push(start..align_down(initrd.start));
}
// no overlap on the right

View File

@ -9,8 +9,9 @@ pub mod sbi;
pub mod timer;
pub mod vm;
use alloc::{string::String, vec::Vec};
use alloc::{boxed::Box, format, string::String, vec::Vec};
use core::ops::Range;
use zcore_drivers::irq::riscv::ScauseIntCode;
use zcore_drivers::utils::devicetree::Devicetree;
use crate::{mem::phys_to_virt, utils::init_once::InitOnce, PhysAddr};
@ -19,10 +20,6 @@ static CMDLINE: InitOnce<String> = InitOnce::new_with_default(String::new());
static INITRD_REGION: InitOnce<Option<Range<PhysAddr>>> = InitOnce::new_with_default(None);
static MEMORY_REGIONS: InitOnce<Vec<Range<PhysAddr>>> = InitOnce::new_with_default(Vec::new());
pub const fn timer_interrupt_vector() -> usize {
trap::SUPERVISOR_TIMER_INT_VEC
}
pub fn cmdline() -> String {
CMDLINE.clone()
}
@ -56,19 +53,33 @@ pub fn primary_init_early() {
pub fn primary_init() {
vm::init();
drivers::init().unwrap();
// We should set first time interrupt before run into first user program
// timer::init();
}
pub fn timer_init() {
timer::init();
}
pub fn secondary_init() {
vm::init();
drivers::intc_init().unwrap();
let intc = crate::drivers::all_irq()
.find(format!("riscv-intc-cpu{}", crate::cpu::cpu_id()).as_str())
.expect("IRQ device 'riscv-intc' not initialized!");
// register soft interrupts handler
intc.register_handler(
ScauseIntCode::SupervisorSoft as _,
Box::new(trap::super_soft),
)
.unwrap();
// register timer interrupts handler
intc.register_handler(
ScauseIntCode::SupervisorTimer as _,
Box::new(trap::super_timer),
)
.unwrap();
intc.unmask(ScauseIntCode::SupervisorSoft as _).unwrap();
intc.unmask(ScauseIntCode::SupervisorTimer as _).unwrap();
let plic = crate::drivers::all_irq()
.find("riscv-plic")
.expect("IRQ device 'riscv-plic' not initialized!");
plic.init_hart();
timer::init();
}

View File

@ -2,7 +2,6 @@ use riscv::register::scause;
use trapframe::TrapFrame;
use crate::context::TrapReason;
pub(super) const SUPERVISOR_TIMER_INT_VEC: usize = 5; // scause::Interrupt::SupervisorTimer
fn breakpoint(sepc: &mut usize) {
info!("Exception::Breakpoint: A breakpoint set @0x{:x} ", sepc);
@ -15,6 +14,7 @@ fn breakpoint(sepc: &mut usize) {
pub(super) fn super_timer() {
super::timer::timer_set_next();
crate::timer::timer_tick();
//发生外界中断时epc的指令还没有执行故无需修改epc到下一条
}
@ -25,22 +25,16 @@ pub(super) fn super_soft() {
#[no_mangle]
pub extern "C" fn trap_handler(tf: &mut TrapFrame) {
// log::warn!("in trap handler");
let scause = scause::read();
trace!("kernel trap happened: {:?}", TrapReason::from(scause));
trace!(
"sepc = 0x{:x} pgtoken = 0x{:x}",
tf.sepc,
crate::vm::current_vmtoken()
);
match TrapReason::from(scause) {
TrapReason::SoftwareBreakpoint => breakpoint(&mut tf.sepc),
TrapReason::PageFault(vaddr, flags) => crate::KHANDLER.handle_page_fault(vaddr, flags),
TrapReason::Interrupt(vector) => {
crate::interrupt::handle_irq(vector);
if vector == SUPERVISOR_TIMER_INT_VEC {
executor::handle_timeout();
}
TrapReason::PageFault(vaddr, flags) => {
// log::warn!("sepc={:x}", riscv::register::sepc::read());
// log::warn!("sstatus.spp={:?}", riscv::register::sstatus::read().spp());
crate::KHANDLER.handle_page_fault(vaddr, flags)
}
TrapReason::Interrupt(vector) => crate::interrupt::handle_irq(vector),
other => panic!("Undefined trap: {:x?} {:#x?}", other, tf),
}
}

View File

@ -3,8 +3,8 @@
use core::fmt::{Debug, Formatter, Result};
use core::slice;
use lock::Mutex;
use riscv::{asm, register::satp};
use spin::Mutex;
use crate::utils::page_table::{GenericPTE, PageTableImpl, PageTableLevel3};
use crate::{mem::phys_to_virt, MMUFlags, PhysAddr, VirtAddr, KCONFIG};

View File

@ -26,8 +26,8 @@ hal_fn_impl! {
fn reset() -> ! {
info!("shutdown...");
loop {
use zcore_drivers::io::{Io, Pmio};
Pmio::<u16>::new(0x604).write(0x2000);
use zcore_drivers::io::{Io, Pio};
Pio::<u16>::new(0x604).write(0x2000);
super::interrupt::wait_for_interrupt();
}
}

View File

@ -2,16 +2,14 @@ use alloc::{boxed::Box, sync::Arc};
use zcore_drivers::irq::x86::Apic;
use zcore_drivers::scheme::IrqScheme;
use zcore_drivers::uart::{BufferedUart, Uart16550Pmio};
use zcore_drivers::uart::{BufferedUart, Uart16550Pio};
use zcore_drivers::{Device, DeviceResult};
use super::trap;
use crate::drivers;
pub(super) fn init_early() -> DeviceResult {
let uart = Arc::new(Uart16550Pmio::new(0x3F8));
drivers::add_device(Device::Uart(BufferedUart::new(uart)));
let uart = Arc::new(Uart16550Pmio::new(0x2F8));
let uart = Arc::new(Uart16550Pio::new(0x3F8));
drivers::add_device(Device::Uart(BufferedUart::new(uart)));
Ok(())
}
@ -22,41 +20,14 @@ pub(super) fn init() -> DeviceResult {
super::special::pc_firmware_tables().0 as usize,
crate::mem::phys_to_virt,
));
let uarts = drivers::all_uart();
if let Some(u) = uarts.try_get(0) {
irq.register_device(trap::X86_ISA_IRQ_COM1, u.clone().upcast())?;
irq.unmask(trap::X86_ISA_IRQ_COM1)?;
if let Some(u) = uarts.try_get(1) {
irq.register_device(trap::X86_ISA_IRQ_COM2, u.clone().upcast())?;
irq.unmask(trap::X86_ISA_IRQ_COM2)?;
}
}
use x2apic::lapic::{TimerDivide, TimerMode};
irq.register_local_apic_handler(trap::X86_INT_APIC_TIMER, Box::new(super::trap::super_timer))?;
// SAFETY: this will be called once and only once for every core
Apic::local_apic().set_timer_mode(TimerMode::Periodic);
Apic::local_apic().set_timer_divide(TimerDivide::Div256); // indeed it is Div1, the name is confusing.
let cycles =
super::cpu::cpu_frequency() as u64 * 1_000_000 / super::super::timer::TICKS_PER_SEC;
Apic::local_apic().set_timer_initial(cycles as u32);
Apic::local_apic().disable_timer();
irq.register_device(
trap::X86_ISA_IRQ_COM1,
drivers::all_uart().first_unwrap().upcast(),
)?;
irq.unmask(trap::X86_ISA_IRQ_COM1)?;
irq.register_local_apic_handler(trap::X86_INT_APIC_TIMER, Box::new(crate::timer::timer_tick))?;
drivers::add_device(Device::Irq(irq));
#[cfg(not(feature = "loopback"))]
{
// PCI scan
use zcore_drivers::bus::pci;
let pci_devs = pci::init(None)?;
for d in pci_devs.into_iter() {
drivers::add_device(d);
}
}
#[cfg(feature = "graphic")]
{
use crate::KCONFIG;
@ -75,12 +46,6 @@ pub(super) fn init() -> DeviceResult {
crate::console::init_graphic_console(display);
}
#[cfg(feature = "loopback")]
{
use crate::net;
net::init();
}
info!("Drivers init end.");
Ok(())
}

View File

@ -5,34 +5,19 @@ use core::ops::Range;
use crate::drivers::all_irq;
use crate::drivers::prelude::{IrqHandler, IrqPolarity, IrqTriggerMode};
use crate::HalResult;
use x86_64::instructions::interrupts;
hal_fn_impl! {
impl mod crate::hal_fn::interrupt {
fn wait_for_interrupt() {
let enable = interrupts::are_enabled();
use x86_64::instructions::interrupts;
interrupts::enable_and_hlt();
if !enable {
interrupts::disable();
}
interrupts::disable();
}
fn is_valid_irq(gsi: usize) -> bool {
all_irq().first_unwrap().is_valid_irq(gsi)
}
fn intr_on() {
interrupts::enable();
}
fn intr_off() {
interrupts::disable();
}
fn intr_get() -> bool {
interrupts::are_enabled()
}
fn mask_irq(gsi: usize) -> HalResult {
Ok(all_irq().first_unwrap().mask(gsi)?)
}

View File

@ -16,10 +16,6 @@ hal_fn_impl_default!(crate::hal_fn::console);
use crate::{mem::phys_to_virt, KCONFIG};
use x86_64::registers::control::{Cr4, Cr4Flags};
pub const fn timer_interrupt_vector() -> usize {
trap::X86_INT_APIC_TIMER
}
pub fn cmdline() -> alloc::string::String {
KCONFIG.cmdline.into()
}
@ -56,10 +52,6 @@ pub fn primary_init() {
}
}
pub fn timer_init() {
timer::init();
}
pub fn secondary_init() {
zcore_drivers::irq::x86::Apic::init_local_apic_ap();
}

View File

@ -1,6 +1,6 @@
//! Functions only available on x86 platforms.
pub use zcore_drivers::io::{Io, Pmio};
pub use zcore_drivers::io::{Io, Pio};
/// Get physical address of `acpi_rsdp` and `smbios` on x86_64.
pub fn pc_firmware_tables() -> (u64, u64) {

View File

@ -4,8 +4,3 @@ pub fn timer_now() -> Duration {
let cycle = unsafe { core::arch::x86_64::_rdtsc() };
Duration::from_nanos(cycle * 1000 / super::cpu::cpu_frequency() as u64)
}
pub fn init() {
let irq = crate::drivers::all_irq().first_unwrap();
irq.apic_timer_enable();
}

View File

@ -24,10 +24,6 @@ fn breakpoint() {
panic!("\nEXCEPTION: Breakpoint");
}
pub(super) fn super_timer() {
crate::timer::timer_tick();
}
#[no_mangle]
pub extern "C" fn trap_handler(tf: &mut TrapFrame) {
trace!(
@ -35,16 +31,10 @@ pub extern "C" fn trap_handler(tf: &mut TrapFrame) {
tf.trap_num,
super::cpu::cpu_id()
);
match TrapReason::from(tf.trap_num, tf.error_code) {
TrapReason::HardwareBreakpoint | TrapReason::SoftwareBreakpoint => breakpoint(),
TrapReason::PageFault(vaddr, flags) => crate::KHANDLER.handle_page_fault(vaddr, flags),
TrapReason::Interrupt(vector) => {
crate::interrupt::handle_irq(vector);
if vector == X86_INT_APIC_TIMER {
executor::handle_timeout();
}
}
TrapReason::Interrupt(vector) => crate::interrupt::handle_irq(vector),
other => panic!("Unhandled trap {:x?} {:#x?}", other, tf),
}
}

View File

@ -1,5 +1,6 @@
//! Bootstrap and initialization.
use super::net;
use crate::{KernelConfig, KernelHandler, KCONFIG, KHANDLER};
hal_fn_impl! {
@ -23,6 +24,7 @@ hal_fn_impl! {
info!("Primary CPU {} init...", crate::cpu::cpu_id());
unsafe { trapframe::init() };
super::arch::primary_init();
net::init();
}
fn secondary_init() {

View File

@ -2,11 +2,11 @@ cfg_if! {
if #[cfg(target_arch = "x86_64")] {
#[path = "arch/x86_64/mod.rs"]
mod arch;
pub use self::arch::{special as x86_64, timer_interrupt_vector};
pub use self::arch::special as x86_64;
} else if #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] {
#[path = "arch/riscv/mod.rs"]
pub mod arch;
pub use self::arch::{sbi, timer_interrupt_vector};
pub use self::arch::sbi;
}
}

View File

@ -1,4 +1,3 @@
// May need move to drivers
use smoltcp::{
iface::{InterfaceBuilder, NeighborCache, Route, Routes},
phy::{Loopback, Medium},
@ -12,7 +11,7 @@ use alloc::vec::Vec;
use alloc::sync::Arc;
use alloc::string::String;
use lock::Mutex;
use spin::Mutex;
use crate::drivers::add_device;
use crate::drivers::all_net;

View File

@ -3,27 +3,18 @@
use alloc::boxed::Box;
use core::time::Duration;
use core::sync::atomic::{AtomicBool, Ordering};
use lock::Mutex;
use naive_timer::Timer;
use spin::Mutex;
#[allow(dead_code)]
pub(super) const TICKS_PER_SEC: u64 = 100;
lazy_static! {
static ref NAIVE_TIMER: Mutex<Timer> = Mutex::new(Timer::default());
static ref FIRST: AtomicBool = AtomicBool::new(false);
}
hal_fn_impl! {
impl mod crate::hal_fn::timer {
fn timer_enable() {
if !FIRST.load(Ordering::Relaxed) {
FIRST.store(true, Ordering::Relaxed);
super::arch::timer_init();
}
}
fn timer_now() -> Duration {
super::arch::timer::timer_now()
}

View File

@ -2,7 +2,7 @@
use crate::drivers;
use core::fmt::{Arguments, Result, Write};
use lock::Mutex;
use spin::Mutex;
struct SerialWriter;

View File

@ -27,7 +27,7 @@ pub enum UserContextField {
}
/// Reason of the trap.
#[derive(Debug, PartialEq, Eq)]
#[derive(Debug)]
pub enum TrapReason {
Syscall,
Interrupt(usize),
@ -39,9 +39,6 @@ pub enum TrapReason {
GernelFault(usize),
}
#[cfg(not(feature = "libos"))]
pub const TIMER_INTERRUPT_VEC: usize = crate::timer_interrupt_vector();
impl TrapReason {
/// Get [`TrapReason`] from `trap_num` and `error_code` in trap frame for x86.
#[cfg(target_arch = "x86_64")]
@ -116,7 +113,7 @@ impl TrapReason {
/// User context saved on trap.
#[repr(transparent)]
#[derive(Clone, Copy)]
#[derive(Clone)]
pub struct UserContext(UserContextInner);
impl UserContext {
@ -127,53 +124,35 @@ impl UserContext {
}
/// Initialize the context for entry into userspace.
/// Note: if the number of args < 3, please fill with zeros
/// Eg: ctx.setup_uspace(pc_, sp_, &[arg1, arg2, 0])
pub fn setup_uspace(&mut self, pc: usize, sp: usize, args: &[usize; 3]) {
pub fn setup_uspace(&mut self, pc: usize, sp: usize, arg1: usize, arg2: usize) {
cfg_if! {
if #[cfg(target_arch = "x86_64")] {
self.0.general.rip = pc;
self.0.general.rsp = sp;
self.0.general.rdi = args[0];
self.0.general.rsi = args[1];
self.0.general.rdx = args[2];
self.0.general.rdi = arg1;
self.0.general.rsi = arg2;
// IOPL = 3, IF = 1
// FIXME: set IOPL = 0 when IO port bitmap is supporte
self.0.general.rflags = 0x3000 | 0x200 | 0x2;
} else if #[cfg(target_arch = "aarch64")] {
self.0.elr = pc;
self.0.sp = sp;
self.0.general.x0 = args[0];
self.0.general.x1 = args[1];
self.0.general.x2 = args[2];
self.0.general.x0 = arg1;
self.0.general.x1 = arg2;
// Mask SError exceptions (currently unhandled).
// TODO
self.0.spsr = 1 << 8;
} else if #[cfg(target_arch = "riscv64")] {
self.0.sepc = pc;
self.0.general.sp = sp;
self.0.general.a0 = args[0];
self.0.general.a1 = args[1];
self.0.general.a2 = args[2];
self.0.general.a0 = arg1;
self.0.general.a1 = arg2;
// SUM = 1, FS = 0b11, SPIE = 1
self.0.sstatus = 1 << 18 | 0b11 << 13 | 1 << 5;
}
}
}
/// Setup return addr
pub fn set_ra(&mut self, _ra: usize) {
cfg_if! {
if #[cfg(target_arch = "riscv64")] {
self.0.general.ra = _ra;
} else if #[cfg(target_arch = "x86_64")] {
error!("Please set return addr via stack!");
} else {
unimplemented!("Unsupported arch!");
}
}
}
/// Switch to user mode.
pub fn enter_uspace(&mut self) {
cfg_if! {

View File

@ -1,42 +1,23 @@
// 来自用户空间的裸指针
//! Raw pointer from user land.
//! Read/write user space pointer.
use crate::VirtAddr;
use alloc::{string::String, vec::Vec};
use core::{
fmt::{Debug, Formatter},
marker::PhantomData,
ops::{Deref, DerefMut},
};
use alloc::string::String;
use alloc::vec::Vec;
use core::fmt::{Debug, Formatter};
use core::marker::PhantomData;
use core::ops::{Deref, DerefMut};
// 来自用户空间的裸指针
/// Raw pointer from user land.
#[repr(transparent)]
pub struct UserPtr<T, P: Policy>(*mut T, PhantomData<P>);
#[repr(C)]
pub struct UserPtr<T, P: Policy> {
ptr: *mut T,
mark: PhantomData<P>,
}
// 标识用户指针功能的基特征。
/// Base trait for Markers of user pointer policy.
pub trait Policy {}
// 标记一个用于输入的指针。
/// Marks a pointer used to read.
pub trait Read: Policy {}
// 标记一个用于输出的指针。
/// Marks a pointer used to write.
pub trait Write: Policy {}
// 输入指针的类型参数。
/// Type argument for user pointer used to read.
pub struct In;
// 输出指针的类型参数。
/// Type argument for user pointer used to write.
pub struct Out;
// 既用于输入有用于输出的指针的类型参数。
/// Type argument for user pointer used to both read and write.
pub struct InOut;
pub enum In {}
pub enum Out {}
pub enum InOut {}
impl Policy for In {}
impl Policy for Out {}
@ -50,8 +31,9 @@ pub type UserInPtr<T> = UserPtr<T, In>;
pub type UserOutPtr<T> = UserPtr<T, Out>;
pub type UserInOutPtr<T> = UserPtr<T, InOut>;
// 用户指针操作的异常类型。
/// The error type which is returned from user pointer operation.
type Result<T> = core::result::Result<T, Error>;
/// The error type which is returned from user pointer.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Error {
InvalidUtf8,
@ -61,13 +43,9 @@ pub enum Error {
InvalidVectorAddress,
}
// 本模块用到的只是用户指针操作结果的类型。
type Result<T> = core::result::Result<T, Error>;
impl<T, P: Policy> Debug for UserPtr<T, P> {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
// 打印用户指针就是打印裸指针
write!(f, "{:?}", self.0)
write!(f, "{:?}", self.ptr)
}
}
@ -76,210 +54,154 @@ unsafe impl<T, P: Policy> Send for UserPtr<T, P> {}
unsafe impl<T, P: Policy> Sync for UserPtr<T, P> {}
impl<T, P: Policy> From<usize> for UserPtr<T, P> {
fn from(ptr: usize) -> Self {
UserPtr(ptr as _, PhantomData)
fn from(x: usize) -> Self {
UserPtr {
ptr: x as _,
mark: PhantomData,
}
}
}
impl<T, P: Policy> UserPtr<T, P> {
// 检查 `size` 是否足够放下一个 `T` 的值,
// 并从 `addr` 构造一个用户指针。
/// Checks if `size` is enough to save a value of `T`,
/// then constructs a user pointer from its value `addr`.
pub fn from_addr_size(addr: usize, size: usize) -> Result<Self> {
if size >= core::mem::size_of::<T>() {
Ok(Self::from(addr))
} else {
Err(Error::BufferTooSmall)
if size < core::mem::size_of::<T>() {
return Err(Error::BufferTooSmall);
}
Ok(Self::from(addr))
}
// 如果指针为空,返回 `true`。
/// Returns `true` if the pointer is null.
pub fn is_null(&self) -> bool {
self.0.is_null()
self.ptr.is_null()
}
// 偏移指针。
// `count` 表示 `T` 的数量;
// 例如,`count` 为 3 表示将指针移动 `3 * size_of::<T>()` 个字节。
/// Calculates the offset from a pointer.
/// `count` is in units of `T`;
/// e.g., a `count` of 3 represents a pointer offset of `3 * size_of::<T>()` bytes.
pub fn add(&self, count: usize) -> Self {
Self(unsafe { self.0.add(count) }, PhantomData)
}
// 返回指针对应的虚地址。
/// Returns the virtual address represented by the pointer.
pub fn as_addr(&self) -> VirtAddr {
self.0 as _
}
// 检查用户指针是否合法。
//
// 如果指针非空且对齐则返回 `OK(())`。
/// Checks avaliability of the user pointer.
///
/// Returns [`Ok(())`] if it is neither null nor unaligned.
pub fn check(&self) -> Result<()> {
if !self.0.is_null() && (self.0 as usize) % core::mem::align_of::<T>() == 0 {
Ok(())
} else {
Err(Error::InvalidPointer)
UserPtr {
ptr: unsafe { self.ptr.add(count) },
mark: PhantomData,
}
}
pub fn as_ptr(&self) -> *mut T {
self.ptr
}
pub fn check(&self) -> Result<()> {
if self.ptr.is_null() {
return Err(Error::InvalidPointer);
}
if (self.ptr as usize) % core::mem::align_of::<T>() != 0 {
return Err(Error::InvalidPointer);
}
Ok(())
}
}
impl<T, P: Read> UserPtr<T, P> {
// 取出指针值的引用(不要用于小于 8 字节的类型)。
/// Converts to reference.
#[allow(clippy::should_implement_trait)]
pub fn as_ref(&self) -> &'static T {
unsafe { &*self.0 }
pub fn as_ref(&self) -> Result<&'static T> {
Ok(unsafe { &*self.ptr })
}
// 读取但不移动指针所指的值(通过逐字节拷贝,但不需要 `Copy` 特征)。
// 指针所指的值保持不变。
/// Reads the value from `self` without moving it.
/// This leaves the memory in self unchanged.
pub fn read(&self) -> Result<T> {
// TODO: check ptr and return err
self.check()?;
Ok(unsafe { self.0.read() })
Ok(unsafe { self.ptr.read() })
}
// 和读取一样,
// 但若指针为空,返回 `None`。
/// Same as [`read`](Self::read),
/// but returns [`None`] when pointer is null.
pub fn read_if_not_null(&self) -> Result<Option<T>> {
if !self.0.is_null() {
Ok(Some(self.read()?))
} else {
Ok(None)
if self.ptr.is_null() {
return Ok(None);
}
let value = self.read()?;
Ok(Some(value))
}
// 构造一个从指针指向开始,长度为 `len` 的切片。
/// Forms a slice from a user pointer and a `len`.
pub fn as_slice(&self, len: usize) -> Result<&'static [T]> {
if len == 0 {
Ok(&[])
} else {
self.check()?;
Ok(unsafe { core::slice::from_raw_parts(self.0, len) })
}
}
// 拷贝对象来构造一个 `Vec`。
//
// `len` 是成员的数量,而不是字节数。
/// Copies elements into a new [`Vec`].
///
/// The `len` argument is the number of **elements**, not the number of bytes.
pub fn read_array(&self, len: usize) -> Result<Vec<T>> {
if len == 0 {
Ok(Vec::default())
} else {
self.check()?;
let mut ret = Vec::<T>::with_capacity(len);
unsafe {
ret.set_len(len);
ret.as_mut_ptr().copy_from_nonoverlapping(self.0, len);
}
Ok(ret)
return Ok(Vec::default());
}
self.check()?;
let mut ret = Vec::<T>::with_capacity(len);
unsafe {
ret.set_len(len);
ret.as_mut_ptr().copy_from_nonoverlapping(self.ptr, len);
}
Ok(ret)
}
}
impl<P: Read> UserPtr<u8, P> {
// 构造一个从指针指向开始,长度为 `len` 的字符切片。
/// Forms an utf-8 string slice from a user pointer and a `len`.
pub fn as_str(&self, len: usize) -> Result<&'static str> {
core::str::from_utf8(self.as_slice(len)?).map_err(|_| Error::InvalidUtf8)
pub fn read_string(&self, len: usize) -> Result<String> {
self.check()?;
let src = unsafe { core::slice::from_raw_parts(self.ptr, len) };
let s = core::str::from_utf8(src).map_err(|_| Error::InvalidUtf8)?;
Ok(String::from(s))
}
// 从一个 C 风格的零结尾字符串构造一个字符切片。
/// Forms a zero-terminated string slice from a user pointer to a c style string.
pub fn as_c_str(&self) -> Result<&'static str> {
self.as_str(unsafe { (0usize..).find(|&i| *self.0.add(i) == 0).unwrap() })
pub fn read_cstring(&self) -> Result<String> {
self.check()?;
let len = unsafe { (0usize..).find(|&i| *self.ptr.add(i) == 0).unwrap() };
self.read_string(len)
}
}
impl<P: 'static + Read> UserPtr<UserPtr<u8, P>, P> {
// 拷贝一组 C 风格的零结尾字符串到 `String`
// 并收集到一个 `Vec` 中。
/// Copies a group of zero-terminated string into [`String`]s,
/// and collect them into a [`Vec`].
impl<P: Read> UserPtr<UserPtr<u8, P>, P> {
pub fn read_cstring_array(&self) -> Result<Vec<String>> {
self.check()?;
let mut result = Vec::new();
let mut pptr = self.0;
loop {
let sptr = unsafe { pptr.read() };
if sptr.is_null() {
break;
}
result.push(sptr.as_c_str()?.into());
pptr = unsafe { pptr.add(1) };
}
Ok(result)
let len = unsafe {
(0usize..)
.find(|&i| self.ptr.add(i).read().is_null())
.unwrap()
};
self.read_array(len)?
.into_iter()
.map(|ptr| ptr.read_cstring())
.collect()
}
}
impl<T, P: Write> UserPtr<T, P> {
// 用指定的值覆盖指针位置。
// 旧的值直接被覆盖,不会调用释放逻辑。
/// Overwrites a memory location with the given `value`
/// **without** reading or dropping the old value.
pub fn write(&mut self, value: T) -> Result<()> {
self.check()?;
unsafe { self.0.write(value) };
unsafe {
self.ptr.write(value);
}
Ok(())
}
// 类似于写,
// 但指针为空时返回 `Ok(())`。
/// Same as [`write`](Self::write),
/// but does nothing and returns [`Ok`] when pointer is null.
pub fn write_if_not_null(&mut self, value: T) -> Result<()> {
if !self.0.is_null() {
self.write(value)
} else {
Ok(())
if self.ptr.is_null() {
return Ok(());
}
self.write(value)
}
// 写入 `values.len() * size_of<T>` 字节到指针位置。
// 写入的区间与目标区间不可重叠。
/// Copies `values.len() * size_of<T>` bytes from `values` to `self`.
/// The source and destination may not overlap.
pub fn write_array(&mut self, values: &[T]) -> Result<()> {
if !values.is_empty() {
self.check()?;
unsafe {
self.0
.copy_from_nonoverlapping(values.as_ptr(), values.len())
};
if values.is_empty() {
return Ok(());
}
self.check()?;
unsafe {
self.ptr
.copy_from_nonoverlapping(values.as_ptr(), values.len());
}
Ok(())
}
}
impl<P: Write> UserPtr<u8, P> {
// 拷贝指定字符串到目标位置并写入一个 `\0` 来模拟 C 风格零结尾字符串。
/// Copies `s` to `self`, then write a `'\0'` for c style string.
pub fn write_cstring(&mut self, s: &str) -> Result<()> {
let bytes = s.as_bytes();
self.write_array(bytes)?;
unsafe { self.0.add(bytes.len()).write(0) };
unsafe {
self.ptr.add(bytes.len()).write(0);
}
Ok(())
}
}
#[derive(Debug)]
#[repr(C)]
pub struct IoVec<P: 'static + Policy> {
pub struct IoVec<P: Policy> {
/// Starting address
ptr: UserPtr<u8, P>,
/// Number of bytes to transfer
@ -291,13 +213,13 @@ pub type IoVecOut = IoVec<Out>;
/// A valid IoVecs request from user
#[derive(Debug)]
pub struct IoVecs<P: 'static + Policy> {
pub struct IoVecs<P: Policy> {
vec: Vec<IoVec<P>>,
}
impl<P: Policy> UserInPtr<IoVec<P>> {
pub fn read_iovecs(&self, count: usize) -> Result<IoVecs<P>> {
if self.0.is_null() {
if self.ptr.is_null() {
return Err(Error::InvalidPointer);
}
let vec = self.read_array(count)?;
@ -324,7 +246,7 @@ impl<P: Read> IoVecs<P> {
pub fn read_to_vec(&self) -> Result<Vec<u8>> {
let mut buf = Vec::new();
for vec in self.vec.iter() {
buf.extend_from_slice(vec.ptr.as_slice(vec.len)?);
buf.extend(vec.ptr.read_array(vec.len)?);
}
Ok(buf)
}
@ -377,14 +299,20 @@ impl<P: Policy> IoVec<P> {
}
pub fn as_slice(&self) -> Result<&[u8]> {
self.as_mut_slice().map(|s| &*s)
}
pub fn as_mut_slice(&self) -> Result<&mut [u8]> {
if !self.ptr.is_null() {
Ok(unsafe { core::slice::from_raw_parts_mut(self.ptr.0, self.len) })
} else {
Err(Error::InvalidVectorAddress)
if self.ptr.is_null() {
return Err(Error::InvalidVectorAddress);
}
let slice = unsafe { core::slice::from_raw_parts(self.ptr.as_ptr(), self.len) };
Ok(slice)
}
}
impl<P: Write> IoVec<P> {
pub fn as_mut_slice(&mut self) -> Result<&mut [u8]> {
if self.ptr.is_null() {
return Err(Error::InvalidVectorAddress);
}
let slice = unsafe { core::slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len) };
Ok(slice)
}
}

View File

@ -3,7 +3,7 @@
use alloc::{sync::Arc, vec::Vec};
use core::convert::From;
use lock::{RwLock, RwLockReadGuard};
use spin::{RwLock, RwLockReadGuard};
use zcore_drivers::scheme::{
BlockScheme, DisplayScheme, InputScheme, IrqScheme, NetScheme, Scheme, UartScheme,

View File

@ -97,15 +97,6 @@ hal_fn_def! {
/// Is a valid IRQ number.
pub fn is_valid_irq(vector: usize) -> bool;
/// Enable the interrupts
pub fn intr_on();
/// Disable the interrupts
pub fn intr_off();
/// Test weather interrupt is enabled
pub fn intr_get() -> bool;
/// Disable IRQ.
pub fn mask_irq(vector: usize) -> HalResult;
@ -157,9 +148,6 @@ hal_fn_def! {
/// Time and clock functions.
pub mod timer {
/// Set the first time interrupt
pub fn timer_enable();
/// Get current time.
/// TODO: use `Instant` as return type.
pub fn timer_now() -> Duration;

View File

@ -1,5 +1,6 @@
//! Bootstrap and initialization.
use super::net;
use crate::{KernelConfig, KernelHandler, KCONFIG, KHANDLER};
hal_fn_impl! {
@ -18,6 +19,7 @@ hal_fn_impl! {
super::macos::register_sigsegv_handler();
}
net::init();
}
}
}

View File

@ -45,10 +45,4 @@ pub(super) fn init() {
crate::console::init_graphic_console(display);
}
#[cfg(feature = "loopback")]
{
use crate::net;
net::init();
}
}

View File

@ -1,10 +0,0 @@
hal_fn_impl! {
impl mod crate::hal_fn::interrupt {
fn wait_for_interrupt() {}
fn intr_on() {}
fn intr_off() {}
fn intr_get() -> bool {
false
}
}
}

View File

@ -5,7 +5,6 @@ mod mock_mem;
pub mod boot;
pub mod config;
pub mod cpu;
pub mod interrupt;
pub mod mem;
pub mod net;
pub mod thread;
@ -17,9 +16,9 @@ pub mod vm;
#[doc(cfg(feature = "libos"))]
pub mod libos;
pub use super::hal_fn::rand;
pub use super::hal_fn::{interrupt, rand};
hal_fn_impl_default!(rand, super::hal_fn::console);
hal_fn_impl_default!(interrupt, rand, super::hal_fn::console);
#[cfg(target_os = "macos")]
mod macos;

View File

@ -1,4 +1,3 @@
// May need move to drivers
use smoltcp::{
iface::{InterfaceBuilder, NeighborCache, Route, Routes},
phy::{Loopback, Medium},

View File

@ -69,7 +69,7 @@ impl GenericPageTable for PageTable {
fn query(&self, vaddr: VirtAddr) -> PagingResult<(PhysAddr, MMUFlags, PageSize)> {
debug_assert!(is_aligned(vaddr));
if (PMEM_MAP_VADDR..PMEM_MAP_VADDR + PMEM_SIZE).contains(&vaddr) {
if PMEM_MAP_VADDR <= vaddr && vaddr < PMEM_MAP_VADDR + PMEM_SIZE {
Ok((
vaddr - PMEM_MAP_VADDR,
MMUFlags::READ | MMUFlags::WRITE,
@ -95,7 +95,7 @@ mod tests {
use super::*;
/// A valid virtual address base to mmap.
const VBASE: VirtAddr = 0x0002_0000_0000;
const VBASE: VirtAddr = 0x2_00000000;
#[test]
fn map_unmap() {

View File

@ -6,8 +6,6 @@ use core::{fmt::Debug, marker::PhantomData, slice};
use crate::common::vm::*;
use crate::{mem::PhysFrame, MMUFlags, PhysAddr, VirtAddr};
use lock::Mutex;
pub trait PageTableLevel: Sync + Send {
const LEVEL: usize;
}
@ -152,7 +150,7 @@ impl<L: PageTableLevel, PTE: GenericPTE> PageTableImpl<L, PTE> {
}
fn dump(&self, limit: usize, print_fn: impl Fn(core::fmt::Arguments)) {
static LOCK: Mutex<()> = Mutex::new(());
static LOCK: spin::Mutex<()> = spin::Mutex::new(());
let _lock = LOCK.lock();
print_fn(format_args!("Root: {:x?}\n", self.table_phys()));

@ -1 +0,0 @@
Subproject commit 1426bea9f3482dec1aa98c31dcc3733a750fb090

View File

@ -19,18 +19,11 @@ zircon-object = { path = "../zircon-object", features = ["elf"] }
kernel-hal = { path = "../kernel-hal", default-features = false }
downcast-rs = { version = "1.2", default-features = false }
lazy_static = { version = "1.4", features = ["spin_no_std"] }
rcore-fs = { git = "https://github.com/rcore-os/rcore-fs", rev = "1a3246b" }
rcore-fs-sfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "1a3246b" }
rcore-fs-ramfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "1a3246b" }
rcore-fs-mountfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "1a3246b" }
rcore-fs-devfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "1a3246b" }
rcore-fs = { git = "https://github.com/rcore-os/rcore-fs", rev = "7c232ec" }
rcore-fs-sfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "7c232ec" }
rcore-fs-ramfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "7c232ec" }
rcore-fs-mountfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "7c232ec" }
rcore-fs-devfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "7c232ec" }
cfg-if = "1.0"
zcore-drivers = { path = "../drivers", features = ["virtio"] }
lock = { git = "https://github.com/DeathWish5/kernel-sync", rev = "01b2e70" }
smoltcp = { git = "https://github.com/smoltcp-rs/smoltcp", rev = "35e833e3", default-features = false, features = ["log", "alloc", "verbose", "proto-ipv4", "proto-ipv6", "proto-igmp", "medium-ip", "medium-ethernet", "socket-raw", "socket-udp", "socket-tcp", "socket-icmp", "async"] }
# LibOS mode
[target.'cfg(not(target_os = "none"))'.dependencies]
# Bare-metal mode
[target.'cfg(target_os = "none")'.dependencies]
smoltcp = { git = "https://gitee.com/gcyyfun/smoltcp", rev="043eb60", default-features = false, features = ["alloc","log", "async", "medium-ethernet","proto-ipv4", "proto-igmp", "socket-icmp", "socket-udp", "socket-tcp", "socket-raw"] }
zcore-drivers = { path = "../drivers", features = ["virtio"] }

View File

@ -111,8 +111,6 @@ pub enum LxError {
EISCONN = 106,
/// Transport endpoint is not connected
ENOTCONN = 107,
/// Connection timeout
ETIMEDOUT = 110,
/// Connection refused
ECONNREFUSED = 111,
}
@ -186,7 +184,6 @@ impl From<ZxError> for LxError {
ZxError::SHOULD_WAIT => LxError::EAGAIN,
ZxError::PEER_CLOSED => LxError::EPIPE,
ZxError::BAD_HANDLE => LxError::EBADF,
ZxError::TIMED_OUT => LxError::ETIMEDOUT,
_ => unimplemented!("unknown error type: {:?}", e),
}
}

View File

@ -1,9 +1,7 @@
mod fbdev;
mod input;
mod random;
mod uartdev;
pub use fbdev::FbDev;
pub use input::{EventDev, MiceDev};
pub use random::RandomINode;
pub use uartdev::UartDev;

View File

@ -1,109 +0,0 @@
use alloc::sync::Arc;
use core::any::Any;
use rcore_fs::vfs::{make_rdev, FileType, FsError, INode, Metadata, PollStatus, Result, Timespec};
use rcore_fs_devfs::DevFS;
use zcore_drivers::{scheme::UartScheme, DeviceError};
/// Uart device.
pub struct UartDev {
index: usize,
port: Arc<dyn UartScheme>,
inode_id: usize,
}
impl UartDev {
pub fn new(index: usize, port: Arc<dyn UartScheme>) -> Self {
Self {
index,
port,
inode_id: DevFS::new_inode_id(),
}
}
}
impl INode for UartDev {
fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> {
info!(
"uart read_at: offset={:#x} buf_len={:#x}",
offset,
buf.len()
);
let mut len = 0;
for b in buf.iter_mut() {
match self.port.try_recv() {
Ok(Some(b_)) => {
*b = b_;
len += 1;
}
Ok(None) => break,
Err(e) => return Err(convert_error(e)),
}
}
Ok(len)
}
fn write_at(&self, offset: usize, buf: &[u8]) -> Result<usize> {
info!(
"uart write_at: offset={:#x} buf_len={:#x}",
offset,
buf.len()
);
for b in buf {
self.port.send(*b).map_err(convert_error)?;
}
Ok(buf.len())
}
fn poll(&self) -> Result<PollStatus> {
Ok(PollStatus {
// TOKNOW and TODO
read: true,
write: false,
error: false,
})
}
fn metadata(&self) -> Result<Metadata> {
Ok(Metadata {
dev: 1,
inode: self.inode_id,
size: 0,
blk_size: 0,
blocks: 0,
atime: Timespec { sec: 0, nsec: 0 },
mtime: Timespec { sec: 0, nsec: 0 },
ctime: Timespec { sec: 0, nsec: 0 },
type_: FileType::CharDevice,
mode: 0o600, // owner read & write
nlinks: 1,
uid: 0,
gid: 0,
rdev: make_rdev(4, self.index),
})
}
#[allow(unsafe_code)]
fn io_control(&self, _cmd: u32, _data: usize) -> Result<usize> {
warn!("uart ioctl unimplemented");
Ok(0)
}
fn as_any_ref(&self) -> &dyn Any {
self
}
}
fn convert_error(e: DeviceError) -> FsError {
match e {
DeviceError::NotSupported => FsError::NotSupported,
DeviceError::NotReady => FsError::Busy,
DeviceError::InvalidParam => FsError::InvalidParam,
DeviceError::BufferTooSmall
| DeviceError::DmaError
| DeviceError::IoError
| DeviceError::AlreadyExists
| DeviceError::NoResources => FsError::DeviceError,
}
}

View File

@ -1,7 +1,7 @@
//! Implement Device
use rcore_fs::dev::{Device, Result};
use lock::RwLock;
use spin::RwLock;
/// memory buffer for device
pub struct MemBuf(RwLock<&'static mut [u8]>);

View File

@ -17,18 +17,15 @@ use downcast_rs::impl_downcast;
use kernel_hal::drivers;
use rcore_fs::vfs::{FileSystem, FileType, INode, PollStatus, Result};
use rcore_fs_devfs::{
special::{NullINode, ZeroINode},
DevFS,
};
use rcore_fs_devfs::special::{NullINode, ZeroINode};
use rcore_fs_devfs::DevFS;
use rcore_fs_mountfs::MountFS;
use rcore_fs_ramfs::RamFS;
use zircon_object::{object::KernelObject, vm::VmObject};
use self::{devfs::RandomINode, pseudo::Pseudo};
use crate::error::{LxError, LxResult};
use crate::process::LinuxProcess;
use devfs::RandomINode;
use pseudo::Pseudo;
pub use file::{File, OpenFlags, SeekFrom};
pub use pipe::Pipe;
@ -129,11 +126,9 @@ pub fn create_root_fs(rootfs: Arc<dyn FileSystem>) -> Arc<dyn INode> {
devfs_root
.add("urandom", Arc::new(RandomINode::new(true)))
.expect("failed to mknod /dev/urandom");
devfs_root
.add("shm", Arc::new(RandomINode::new(true)))
.expect("failed to mknod /dev/shm");
if let Some(display) = drivers::all_display().first() {
use devfs::{EventDev, FbDev, MiceDev};
use self::devfs::{EventDev, FbDev, MiceDev};
// Add framebuffer device at `/dev/fb0`
if let Err(e) = devfs_root.add("fb0", Arc::new(FbDev::new(display.clone()))) {
@ -161,14 +156,6 @@ pub fn create_root_fs(rootfs: Arc<dyn FileSystem>) -> Arc<dyn INode> {
}
}
// Add uart devices at `/dev/ttyS{i}`
for (i, uart) in drivers::all_uart().as_vec().iter().enumerate() {
let fname = format!("ttyS{}", i);
if let Err(e) = devfs_root.add(&fname, Arc::new(devfs::UartDev::new(i, uart.clone()))) {
warn!("failed to mknod /dev/{}: {:?}", &fname, e);
}
}
// mount DevFS at /dev
let dev = root.find(true, "dev").unwrap_or_else(|_| {
root.create("dev", FileType::Dir, 0o666)

View File

@ -12,8 +12,8 @@ use core::pin::Pin;
use core::task::{Context, Poll};
use kernel_hal::console::{self, ConsoleWinSize};
use lazy_static::lazy_static;
use lock::Mutex;
use rcore_fs::vfs::*;
use spin::Mutex;
lazy_static! {
/// STDIN global reference

View File

@ -8,7 +8,6 @@ pub use self::shared_mem::*;
use alloc::collections::BTreeMap;
use alloc::sync::Arc;
use bitflags::*;
use spin::Mutex;
/// Semaphore table in a process
#[derive(Default)]
@ -131,7 +130,7 @@ impl Drop for SemProc {
impl ShmProc {
/// Insert the `SharedGuard` and return its ID
pub fn add(&mut self, shared_guard: Arc<Mutex<ShmGuard>>) -> ShmId {
pub fn add(&mut self, shared_guard: Arc<spin::Mutex<ShmGuard>>) -> ShmId {
let id = self.get_free_id();
let shm_identifier = ShmIdentifier {
addr: 0,

View File

@ -6,7 +6,8 @@ use crate::time::*;
use alloc::{collections::BTreeMap, sync::Arc, sync::Weak, vec::Vec};
use core::ops::Index;
use lazy_static::*;
use spin::{Mutex, RwLock};
use spin::Mutex;
use spin::RwLock;
/// semid data structure
///

View File

@ -4,11 +4,13 @@ use crate::error::LxError;
use crate::time::TimeSpec;
use alloc::{collections::BTreeMap, sync::Arc, sync::Weak};
use lazy_static::lazy_static;
use spin::{Mutex, RwLock};
use spin::Mutex;
use spin::RwLock;
use zircon_object::vm::*;
lazy_static! {
static ref KEY2SHM: RwLock<BTreeMap<u32, Weak<Mutex<ShmGuard>>>> = RwLock::new(BTreeMap::new());
static ref KEY2SHM: RwLock<BTreeMap<u32, Weak<spin::Mutex<ShmGuard>>>> =
RwLock::new(BTreeMap::new());
}
/// shmid data structure
@ -41,7 +43,7 @@ pub struct ShmIdentifier {
/// Shared memory address
pub addr: usize,
/// Shared memory buffer and data
pub guard: Arc<Mutex<ShmGuard>>,
pub guard: Arc<spin::Mutex<ShmGuard>>,
}
/// shared memory buffer and data
@ -64,7 +66,7 @@ impl ShmIdentifier {
memsize: usize,
flags: usize,
cpid: u32,
) -> Result<Arc<Mutex<ShmGuard>>, LxError> {
) -> Result<Arc<spin::Mutex<ShmGuard>>, LxError> {
let mut key2shm = KEY2SHM.write();
let flag = IpcGetFlag::from_bits_truncate(flags);
@ -78,7 +80,7 @@ impl ShmIdentifier {
return Ok(guard);
}
}
let shared_guard = Arc::new(Mutex::new(ShmGuard {
let shared_guard = Arc::new(spin::Mutex::new(ShmGuard {
shared_guard: VmObject::new_paged(pages(memsize)),
shmid_ds: Mutex::new(ShmidDs {
perm: IpcPerm {

View File

@ -3,7 +3,6 @@
/// missing documentation
pub mod socket_address;
use smoltcp::wire::IpEndpoint;
pub use socket_address::*;
/// missing documentation
@ -15,7 +14,6 @@ pub mod udp;
pub use udp::*;
use spin::Mutex;
/// missing documentation
// pub mod raw;
// pub use raw::*;
@ -113,8 +111,24 @@ impl Drop for GlobalSocketHandle {
}
}
// #[cfg(feature = "e1000")]
use kernel_hal::net::get_net_device;
#[cfg(feature = "loopback")]
use hashbrown::HashMap;
#[cfg(feature = "loopback")]
use kernel_hal::timer_now;
// #[cfg(feature = "loopback")]
// use net_stack::{NetStack, NET_STACK};
#[cfg(feature = "loopback")]
use smoltcp::time::Instant;
// /// miss doc
// #[cfg(feature = "loopback")]
// pub fn get_net_stack() -> HashMap<usize, Arc<dyn NetStack>> {
// NET_STACK.read().clone()
// }
/// miss doc
fn poll_ifaces() {
for iface in get_net_device().iter() {
@ -127,8 +141,67 @@ fn poll_ifaces() {
}
}
// use core::future::Future;
// use core::pin::Pin;
// use core::task::Context;
// use core::task::Poll;
// use smoltcp::socket::TcpSocket;
// ============= SocketHandle =============
// ============= Endpoint =============
use smoltcp::wire::IpEndpoint;
/// missing documentation
#[derive(Clone, Debug)]
pub enum Endpoint {
/// missing documentation
Ip(IpEndpoint),
/// missing documentation
LinkLevel(LinkLevelEndpoint),
/// missing documentation
Netlink(NetlinkEndpoint),
}
/// missing documentation
#[derive(Clone, Debug)]
pub struct LinkLevelEndpoint {
/// missing documentation
pub interface_index: usize,
}
impl LinkLevelEndpoint {
/// missing documentation
pub fn new(ifindex: usize) -> Self {
LinkLevelEndpoint {
interface_index: ifindex,
}
}
}
/// missing documentation
#[derive(Clone, Debug)]
pub struct NetlinkEndpoint {
/// missing documentation
pub port_id: u32,
/// missing documentation
pub multicast_groups_mask: u32,
}
impl NetlinkEndpoint {
/// missing documentation
pub fn new(port_id: u32, multicast_groups_mask: u32) -> Self {
NetlinkEndpoint {
port_id,
multicast_groups_mask,
}
}
}
// ============= Endpoint =============
// ============= Rand Port =============
/// !!!! need riscv rng

View File

@ -5,11 +5,12 @@ use core::mem::size_of;
// crate
use crate::error::LxError;
// use crate::net::Endpoint;
use crate::net::Endpoint;
// smoltcp
pub use smoltcp::wire::{IpAddress, Ipv4Address};
// #
use crate::net::*;
use kernel_hal::user::{UserInOutPtr, UserOutPtr};
// use numeric_enum_macro::numeric_enum;
@ -90,58 +91,6 @@ pub struct SockAddrPlaceholder {
pub data: [u8; 14],
}
// ============= Endpoint =============
use smoltcp::wire::IpEndpoint;
/// missing documentation
#[derive(Clone, Debug)]
pub enum Endpoint {
/// missing documentation
Ip(IpEndpoint),
/// missing documentation
LinkLevel(LinkLevelEndpoint),
/// missing documentation
Netlink(NetlinkEndpoint),
}
/// missing documentation
#[derive(Clone, Debug)]
pub struct LinkLevelEndpoint {
/// missing documentation
pub interface_index: usize,
}
impl LinkLevelEndpoint {
/// missing documentation
pub fn new(ifindex: usize) -> Self {
LinkLevelEndpoint {
interface_index: ifindex,
}
}
}
/// missing documentation
#[derive(Clone, Debug)]
pub struct NetlinkEndpoint {
/// missing documentation
pub port_id: u32,
/// missing documentation
pub multicast_groups_mask: u32,
}
impl NetlinkEndpoint {
/// missing documentation
pub fn new(port_id: u32, multicast_groups_mask: u32) -> Self {
NetlinkEndpoint {
port_id,
multicast_groups_mask,
}
}
}
// ============= Endpoint =============
impl From<Endpoint> for SockAddr {
fn from(endpoint: Endpoint) -> Self {
#[allow(warnings)]
@ -163,29 +112,32 @@ impl From<Endpoint> for SockAddr {
},
_ => unimplemented!("only ipv4"),
}
} else if let Endpoint::LinkLevel(link_level) = endpoint {
SockAddr {
addr_ll: SockAddrLl {
sll_family: AddressFamily::Packet.into(),
sll_protocol: 0,
sll_ifindex: link_level.interface_index as u32,
sll_hatype: 0,
sll_pkttype: 0,
sll_halen: 0,
sll_addr: [0; 8],
},
}
} else if let Endpoint::Netlink(netlink) = endpoint {
SockAddr {
addr_nl: SockAddrNl {
nl_family: AddressFamily::Netlink.into(),
nl_pad: 0,
nl_pid: netlink.port_id,
nl_groups: netlink.multicast_groups_mask,
},
}
// unix socket 暂时 未开启
// } else if let Endpoint::LinkLevel(link_level) = endpoint {
// SockAddr {
// addr_ll: SockAddrLl {
// sll_family: AddressFamily::Packet.into(),
// sll_protocol: 0,
// sll_ifindex: link_level.interface_index as u32,
// sll_hatype: 0,
// sll_pkttype: 0,
// sll_halen: 0,
// sll_addr: [0; 8],
// },
// }
// } else if let Endpoint::Netlink(netlink) = endpoint {
// SockAddr {
// addr_nl: SockAddrNl {
// nl_family: AddressFamily::Netlink.into(),
// nl_pad: 0,
// nl_pid: netlink.port_id,
// nl_groups: netlink.multicast_groups_mask,
// },
// }
} else {
unimplemented!("not match");
unimplemented!("only ip");
}
}
}

View File

@ -70,7 +70,7 @@ impl TcpSocketState {
/// missing documentation
pub async fn read(&self, data: &mut [u8]) -> (LxResult<usize>, Endpoint) {
info!("tcp read");
warn!("tcp read");
loop {
poll_ifaces();
let net_sockets = get_sockets();
@ -96,9 +96,60 @@ impl TcpSocketState {
}
}
/// missing documentation
#[cfg(feature = "e1000")]
pub async fn read(&self, data: &mut [u8]) -> (LxResult<usize>, Endpoint) {
warn!("tcp read");
use core::task::Poll;
futures::future::poll_fn(|cx| {
self.with(|s| {
if s.can_recv() {
warn!("can recv ok");
if let Ok(size) = s.recv_slice(data) {
warn!("--------------Ok size {}", size);
if size > 0 {
let endpoint = s.remote_endpoint();
Poll::Ready((Ok(size), Endpoint::Ip(endpoint)))
} else {
warn!("wait size > 0");
s.register_recv_waker(cx.waker());
s.register_send_waker(cx.waker());
Poll::Pending
}
} else {
warn!("recv_slice not Oksize");
Poll::Ready((
Err(LxError::ENOTCONN),
Endpoint::Ip(IpEndpoint::UNSPECIFIED),
))
}
} else {
error!("can not recv");
s.register_recv_waker(cx.waker());
s.register_send_waker(cx.waker());
Poll::Pending
}
})
})
.await
// let net_sockets = get_net_sockets();
// let mut sockets = net_sockets.lock();
// let mut socket = sockets.get::<TcpSocket>(self.handle.0);
// // if socket.may_recv() {
// if let Ok(size) = socket.recv_slice(data) {
// let endpoint = socket.remote_endpoint();
// return (Ok(size), Endpoint::Ip(endpoint));
// } else {
// return (
// Err(LxError::ENOTCONN),
// Endpoint::Ip(IpEndpoint::UNSPECIFIED),
// );
// }
}
/// missing documentation
pub fn write(&self, data: &[u8], _sendto_endpoint: Option<Endpoint>) -> SysResult {
info!("tcp write");
warn!("tcp write");
let net_sockets = get_sockets();
let mut sockets = net_sockets.lock();
let mut socket = sockets.get::<TcpSocket>(self.handle.0);
@ -190,6 +241,194 @@ impl TcpSocketState {
Err(LxError::EINVAL)
}
}
/// missing documentation
#[cfg(feature = "e1000")]
pub async fn connect(&self, endpoint: Endpoint) -> SysResult {
warn!("tcp connect");
// if let Endpoint::Ip(ip) = endpoint {
// let local_port = get_ephemeral_port();
// self.with(|ss| ss.connect(ip, local_port).map_err(|_| LxError::ENOBUFS))?;
// // use crate::net::IFaceFuture;
// // IFaceFuture { flag: false }.await;
// // warn!("no");
// // use smoltcp::socket::TcpState;
// // let ret = self.with(|ss| match ss.state() {
// // TcpState::SynSent => {
// // // still connecting
// // warn!("SynSent");
// // Ok(0)
// // }
// // TcpState::Established => Ok(0),
// // _ => Err(LxError::ECONNREFUSED),
// // });
// // Ok(0)
// // socket
// // .connect(ip, local_port)
// // .map_err(|_| LxError::ENOBUFS)?;
// // use crate::net::ConnectFuture;
// // use smoltcp::socket::SocketRef;
// // let c = ConnectFuture {
// // socket: SocketRef::into_inner(socket),
// // }
// // .await;
// // drop(c);
// // use core::future::Future;
// // use core::pin::Pin;
// // use core::task::Context;
// use crate::net::IFaceFuture;
// IFaceFuture.await;
// // warn!("no");
// // IFaceFuture.await;
// // warn!("no");
// // IFaceFuture.await;
// // warn!("no");
// // IFaceFuture.await;
// // warn!("no");
// use core::task::Poll;
// use smoltcp::socket::TcpState;
// let ret = futures::future::poll_fn(|cx| {
// self.with(|s| {
// // s.connect(ip, local_port).map_err(|_| LxError::ENOBUFS)?;
// match s.state() {
// TcpState::Closed | TcpState::TimeWait => {
// warn!("Closed|TimeWait");
// Poll::Ready(Err(LxError::ECONNREFUSED))
// }
// TcpState::Listen => {
// warn!("Listen");
// Poll::Ready(Err(LxError::ECONNREFUSED))
// }
// TcpState::SynSent => {
// warn!("SynSent");
// s.register_recv_waker(cx.waker());
// s.register_send_waker(cx.waker());
// // drop(s);
// // #[cfg(feature = "e1000")]
// // poll_ifaces_e1000();
// // IFaceFuture.await
// Poll::Pending
// }
// TcpState::SynReceived => {
// warn!("SynReceived");
// s.register_recv_waker(cx.waker());
// s.register_send_waker(cx.waker());
// Poll::Pending
// }
// TcpState::Established => {
// warn!("Established");
// // s.register_recv_waker(cx.waker());
// // s.register_send_waker(cx.waker());
// Poll::Ready(Ok(0))
// // Poll::Pending
// }
// // TcpState::TimeWait => {
// // warn!("TimeWait");
// // // s.register_recv_waker(cx.waker());
// // // s.register_send_waker(cx.waker());
// // Poll::Ready(Ok(0))
// // // Poll::Pending
// // }
// TcpState::FinWait1 => {
// warn!("------------------------------------FinWait1");
// // s.register_recv_waker(cx.waker());
// // s.register_send_waker(cx.waker());
// Poll::Ready(Ok(0))
// // Poll::Pending
// }
// TcpState::FinWait2 => {
// warn!("----------------------------------------FinWait2");
// // s.register_recv_waker(cx.waker());
// // s.register_send_waker(cx.waker());
// Poll::Ready(Ok(0))
// // Poll::Pending
// }
// TcpState::Closing => {
// warn!("-------------------------------------------Closing");
// // s.register_recv_waker(cx.waker());
// // s.register_send_waker(cx.waker());
// Poll::Ready(Ok(0))
// // Poll::Pending
// }
// TcpState::LastAck => {
// warn!("-------------------------------------------LastAck");
// // s.register_recv_waker(cx.waker());
// // s.register_send_waker(cx.waker());
// Poll::Ready(Ok(0))
// // Poll::Pending
// }
// _ => {
// warn!("_");
// Poll::Ready(Err(LxError::ECONNREFUSED))
// }
// }
// })
// })
// .await;
// // #[cfg(feature = "e1000")]
// // poll_ifaces_e1000();
// IFaceFuture.await;
// warn!("ret {:?}", ret);
// ret
// // Ok(0)
// } else {
// return Err(LxError::EINVAL);
// }
let net_sockets = get_net_sockets();
let mut sockets = net_sockets.lock();
let mut socket = sockets.get::<TcpSocket>(self.handle.0);
#[allow(warnings)]
if let Endpoint::Ip(ip) = endpoint {
let local_port = get_ephemeral_port();
socket
.connect(ip, local_port)
.map_err(|_| LxError::ENOBUFS)?;
// avoid deadlock
drop(socket);
drop(sockets);
#[cfg(feature = "e1000")]
poll_ifaces_e1000();
#[cfg(feature = "loopback")]
poll_ifaces_loopback();
// wait for connection result
loop {
warn!("loop");
let net_sockets = get_net_sockets();
let mut sockets = net_sockets.lock();
let socket = sockets.get::<TcpSocket>(self.handle.0);
use smoltcp::socket::TcpState;
match socket.state() {
TcpState::SynSent => {
// still connecting
warn!("SynSent");
drop(socket);
drop(sockets);
#[cfg(feature = "e1000")]
poll_ifaces_e1000();
#[cfg(feature = "loopback")]
poll_ifaces_loopback();
}
TcpState::Established => {
warn!("estab");
break Ok(0);
}
_ => {
break Err(LxError::ECONNREFUSED);
}
}
}
} else {
drop(socket);
drop(sockets);
return Err(LxError::EINVAL);
}
}
/// missing documentation
fn bind(&mut self, endpoint: Endpoint) -> SysResult {
@ -272,6 +511,54 @@ impl TcpSocketState {
drop(sockets);
}
}
#[cfg(feature = "e1000")]
async fn accept(&mut self) -> Result<(Arc<Mutex<dyn Socket>>, Endpoint), LxError> {
let endpoint = self.local_endpoint.ok_or(LxError::EINVAL)?;
// let net_sockets = get_net_sockets();
// let mut sockets = net_sockets.lock();
// let socket = sockets.get::<TcpSocket>(self.handle.0);
// if socket.is_active() {
// use crate::net::AcceptFuture;
// AcceptFuture {
// socket: &mut socket,
// }
// .await;
use core::task::Poll;
futures::future::poll_fn(|cx| {
self.with(|s| {
if s.is_active() {
Poll::Ready(())
} else {
s.register_recv_waker(cx.waker());
s.register_send_waker(cx.waker());
Poll::Pending
}
})
})
.await;
let remote_endpoint = self.with(|s| s.remote_endpoint());
// drop(socket);
let new_socket = {
let rx_buffer = TcpSocketBuffer::new(vec![0; TCP_RECVBUF]);
let tx_buffer = TcpSocketBuffer::new(vec![0; TCP_SENDBUF]);
let mut socket = TcpSocket::new(rx_buffer, tx_buffer);
socket.listen(endpoint).unwrap();
let net_sockets = get_net_sockets();
let mut sockets = net_sockets.lock();
let new_handle = GlobalSocketHandle(sockets.add(socket));
let old_handle = ::core::mem::replace(&mut self.handle, new_handle);
Arc::new(Mutex::new(TcpSocketState {
// base: KObjectBase::new(),
handle: old_handle,
local_endpoint: self.local_endpoint,
is_listening: false,
}))
};
return Ok((new_socket, Endpoint::Ip(remote_endpoint)));
}
/// missing documentation
fn endpoint(&self) -> Option<Endpoint> {

View File

@ -31,6 +31,7 @@ use alloc::sync::Arc;
use alloc::vec;
// smoltcp
use smoltcp::socket::UdpPacketMetadata;
use smoltcp::socket::UdpSocket;
use smoltcp::socket::UdpSocketBuffer;
@ -120,6 +121,34 @@ impl UdpSocketState {
drop(sockets);
}
}
/// missing documentation
#[cfg(feature = "e1000")]
pub async fn read(&self, data: &mut [u8]) -> (SysResult, Endpoint) {
use core::task::Poll;
futures::future::poll_fn(|cx| {
self.with(|s| {
if s.can_recv() {
if let Ok((size, remote_endpoint)) = s.recv_slice(data) {
let endpoint = remote_endpoint;
warn!("udp read => size : {} , enpoint : {} ", size, endpoint);
Poll::Ready((Ok(size), Endpoint::Ip(endpoint)))
} else {
warn!("recv faill message");
Poll::Ready((
Err(LxError::ENOTCONN),
Endpoint::Ip(IpEndpoint::UNSPECIFIED),
))
}
} else {
warn!("udp can not recv ,because rx buffer is null");
s.register_recv_waker(cx.waker());
s.register_send_waker(cx.waker());
Poll::Pending
}
})
})
.await
}
/// missing documentation
pub fn write(&self, data: &[u8], sendto_endpoint: Option<Endpoint>) -> SysResult {

Some files were not shown because too many files have changed in this diff Show More