Compare commits

..

No commits in common. "master" and "master" have entirely different histories.

293 changed files with 4159 additions and 13568 deletions

View File

@ -1,22 +1,16 @@
[alias]
xtask = "run --package xtask --release --"
git-proxy = "xtask git-proxy"
zircon-init = "xtask zircon-init"
setup = "xtask setup"
update-all = "xtask update-all"
check-style = "xtask check-style"
rootfs = "xtask rootfs"
musl-libs = "xtask musl-libs"
opencv = "xtask opencv"
ffmpeg = "xtask ffmpeg"
libc-test = "xtask libc-test"
other-test = "xtask other-test"
image = "xtask image"
linux-libos = "xtask linux-libos"
asm = "xtask asm"
bin = "xtask bin"
qemu = "xtask qemu"
gdb = "xtask gdb"

1
.gitattributes vendored Normal file
View File

@ -0,0 +1 @@
prebuilt/**/* filter=lfs diff=lfs merge=lfs -text

5
.github/scripts/install-deps.sh vendored Executable file
View File

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

View File

@ -3,5 +3,5 @@
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,aarch64-softmmu
make -j > /dev/null 2>&1
./configure --target-list=x86_64-softmmu,riscv64-softmmu
make -j$nproc > /dev/null 2>&1

View File

@ -7,11 +7,11 @@ on:
- cron: '0 22 * * *' # every day at 22:00 UTC
env:
rust_toolchain: nightly-2022-08-05
rust_toolchain: nightly-2022-01-20
jobs:
workspace:
runs-on: ubuntu-latest
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3
@ -40,23 +40,54 @@ jobs:
command: clippy
args: --all-features
- name: Pull prebuilt images
if: github.event_name == 'schedule'
run: make zircon-init
- name: Build docs
if: github.event_name == 'schedule'
uses: actions-rs/cargo@v1
with:
command: doc
args: --no-deps --all-features --workspace
args: --all-features --no-deps
build-aarch64:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: ${{ env.rust_toolchain }}
override: true
target: aarch64-unknown-linux-gnu
- uses: actions-rs/cargo@v1
with:
command: build
use-cross: true
args: --target aarch64-unknown-linux-gnu --workspace --exclude linux-syscall --exclude zcore-loader --exclude zcore
build-user:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3
- 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 }}
target: x86_64-fuchsia
- name: Build Zircon user programs
run: cd zircon-user && make build MODE=release
test-libos:
runs-on: ubuntu-latest
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
mode: [linux, zircon]
os: [ubuntu-latest, macos-latest]
steps:
- uses: actions/checkout@v3
@ -66,10 +97,6 @@ jobs:
toolchain: ${{ env.rust_toolchain }}
components: rust-src, llvm-tools-preview, clippy
- name: Pull prebuilt images
if: matrix.mode == 'zircon'
run: make zircon-init
- name: Build
uses: actions-rs/cargo@v1
with:
@ -83,11 +110,12 @@ jobs:
args: --package zcore --features "${{ matrix.mode }} libos"
test-bare-metal:
runs-on: ubuntu-latest
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
arch: [x86_64, riscv64, aarch64]
arch: [x86_64, riscv64]
os: [ubuntu-latest, macos-latest]
steps:
- uses: actions/checkout@v3
with:
@ -104,44 +132,18 @@ jobs:
crate: cargo-binutils
version: latest
- name: Install qemu-utils
run: sudo apt update && sudo apt install qemu-utils
- name: Pull prebuilt images
if: matrix.arch == 'x86_64'
run: make zircon-init
- name: Build ${{ matrix.arch }} bare-metal zircon
if: matrix.arch == 'x86_64'
run: cd zCore && make build ARCH=${{ matrix.arch }} ZBI=core-tests
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 }} ZBI=core-tests
run: cd zCore && make clippy ARCH=${{ matrix.arch }}
- name: Build ${{ matrix.arch }} bare-metal linux
if: matrix.arch != 'x86_64'
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
- name: Xtask Build bare-metal linux
run: cargo bin -m virt-${{ matrix.arch }}
build-user:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install prebuilt images
run: make zircon-init
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: nightly-2022-01-20
target: x86_64-fuchsia
- name: Build Zircon user programs
run: cd zircon-user && make build MODE=release

View File

@ -1,29 +1,26 @@
name: Deploy docs
name: Deploy docs
on:
push:
pull_request:
env:
rust_toolchain: nightly-2022-08-05
rust_toolchain: nightly-2022-01-20
jobs:
doc:
runs-on: ubuntu-latest
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: ${{ env.rust_toolchain }}
- name: Pull prebuilt images
run: make zircon-init
- name: Build docs
run: |
cargo doc --no-deps --all-features --workspace
cargo doc --no-deps --all-features
.github/scripts/add-doc-index.sh
- name: Deploy to Github Pages

View File

@ -7,13 +7,13 @@ on:
- cron: '0 22 * * *' # every day at 22:00 UTC
env:
rust_toolchain: nightly-2022-08-05
rust_toolchain: nightly-2022-01-20
qemu_version: 7.0.0
jobs:
unit-test:
name: Unit Test
runs-on: ubuntu-latest
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3
@ -21,7 +21,7 @@ jobs:
with:
profile: minimal
toolchain: ${{ env.rust_toolchain }}
components: rust-src, llvm-tools-preview
components: rust-src, llvm-tools-preview, rustfmt, clippy
- name: Run unit test
uses: actions-rs/cargo@v1
@ -49,9 +49,26 @@ jobs:
# github-token: ${{ secrets.GITHUB_TOKEN }}
# path-to-lcov: ${{ steps.coverage.outputs.report }}
bench-test:
name: Bench 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 bench test
uses: actions-rs/cargo@v1
with:
command: bench
zircon-core-test-libos:
name: Zircon Core Test Libos
runs-on: ubuntu-latest
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3
with:
@ -61,13 +78,16 @@ jobs:
with:
profile: minimal
toolchain: ${{ env.rust_toolchain }}
components: rust-src, llvm-tools-preview
components: rust-src, llvm-tools-preview, rustfmt, clippy
- name: Pull prebuilt images
run: make zircon-init
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: pip3 install -r tests/requirements.txt
run: .github/scripts/install-deps.sh
- name: Run fast tests
if: github.event_name != 'schedule'
@ -77,56 +97,9 @@ jobs:
if: github.event_name == 'schedule'
run: cd tests && python3 zircon_core_test.py --libos
zircon-core-test:
name: Zircon Core Test Baremetal
runs-on: ubuntu-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
- name: Pull prebuilt images
run: make zircon-init
- name: Cache QEMU
id: cache-qemu
uses: actions/cache@v3
with:
path: qemu-${{ env.qemu_version }}
key: qemu-${{ env.qemu_version }}
- name: Install ninja-build
run: sudo apt-get update && sudo apt-get install -y ninja-build
- name: Download and Compile QEMU
if: steps.cache-qemu.outputs.cache-hit != 'true'
run: .github/scripts/make-qemu.sh ${{ env.qemu_version }}
- name: Install QEMU
run: |
cd qemu-${{ env.qemu_version }} && sudo make install
qemu-system-x86_64 --version
- name: Install python 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 --fast
- name: Run full tests
if: github.event_name == 'schedule'
run: cd tests && python3 zircon_core_test.py
linux-libc-test-libos:
name: Linux Libc Test Libos
runs-on: ubuntu-latest
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3
with:
@ -136,13 +109,13 @@ jobs:
with:
profile: minimal
toolchain: ${{ env.rust_toolchain }}
components: rust-src, llvm-tools-preview
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: cargo xtask libos-libc-test
- name: Install python dependencies
run: pip3 install -r tests/requirements.txt
run: make libc-test
- name: Run fast tests
if: github.event_name != 'schedule'
@ -152,13 +125,9 @@ jobs:
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-latest
strategy:
fail-fast: false
matrix:
arch: [x86_64, riscv64, aarch64]
zircon-core-test-baremetal:
name: Zircon Core Test Baremetal
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3
with:
@ -168,29 +137,58 @@ jobs:
with:
profile: minimal
toolchain: ${{ env.rust_toolchain }}
components: rust-src, llvm-tools-preview
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
- name: Install dependencies
run: .github/scripts/install-deps.sh ninja-build
- name: Cache QEMU
id: cache-qemu
uses: actions/cache@v3
with:
path: qemu-${{ env.qemu_version }}
key: qemu-${{ env.qemu_version }}
- name: Install ninja-build
run: sudo apt-get update && sudo apt-get install -y ninja-build
key: qemu-${{ env.qemu_version }}-x86_64-riscv64
- name: Download and Compile QEMU
if: steps.cache-qemu.outputs.cache-hit != 'true'
run: .github/scripts/make-qemu.sh ${{ env.qemu_version }}
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
qemu-system-x86_64 --version
- name: Prepare rootfs
run: cargo libc-test --arch ${{ matrix.arch }} && cargo image --arch ${{ matrix.arch }}
- 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-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
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
@ -198,8 +196,27 @@ jobs:
crate: cargo-binutils
version: latest
- name: Install python dependencies
run: pip3 install -r tests/requirements.txt
- 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 libc-test ARCH=${{ matrix.arch }} && make image ARCH=${{ matrix.arch }}
- name: Run fast tests
if: github.event_name != 'schedule'
@ -211,11 +228,11 @@ jobs:
linux-other-test-baremetal:
name: Linux Other Test Baremetal
runs-on: ubuntu-latest
runs-on: ubuntu-20.04
strategy:
fail-fast: false
matrix:
arch: [x86_64, riscv64, aarch64]
arch: [x86_64, riscv64]
steps:
- uses: actions/checkout@v3
with:
@ -225,29 +242,7 @@ jobs:
with:
profile: minimal
toolchain: ${{ env.rust_toolchain }}
components: rust-src, llvm-tools-preview
- name: Cache QEMU
id: cache-qemu
uses: actions/cache@v3
with:
path: qemu-${{ env.qemu_version }}
key: qemu-${{ env.qemu_version }}
- name: Install ninja-build
run: sudo apt-get update && sudo apt-get install -y ninja-build
- name: Download and Compile QEMU
if: steps.cache-qemu.outputs.cache-hit != 'true'
run: .github/scripts/make-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: cargo other-test --arch ${{ matrix.arch }} && cargo image --arch ${{ matrix.arch }}
components: rust-src, llvm-tools-preview, rustfmt, clippy
- if: matrix.arch == 'riscv64'
uses: actions-rs/install@v0.1
@ -255,8 +250,27 @@ jobs:
crate: cargo-binutils
version: latest
- name: Install python dependencies
run: pip3 install -r tests/requirements.txt
- 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'

14
.gitignore vendored
View File

@ -1,14 +1,18 @@
**/.*/*
!.github/*
!.cargo/*
**/.*
!.github/
!.cargo/
!.vscode/settings.json
**/target
**/*.rs.bk
*.img
*.bin
*.log
Cargo.lock
/ignored
/rootfs
# for aarch64 only
/zCore/disk
zCore/src/platform/riscv/kernel-vars.ld
.DS_Store
__pycache__

10
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,10 @@
{
// 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
}

2671
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -8,7 +8,6 @@ members = [
"linux-syscall",
"loader",
"zCore",
"z-config",
"xtask",
]
default-members = ["xtask"]
@ -16,4 +15,3 @@ exclude = ["zircon-user", "rboot"]
[profile.release]
lto = true
debug = true

View File

@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
SOFTWARE.

View File

@ -1,20 +1,16 @@
# Makefile for top level of zCore
ARCH ?= x86_64
XTASK ?= 1
STRIP := $(ARCH)-linux-musl-strip
export PATH=$(shell printenv PATH):$(CURDIR)/ignored/target/$(ARCH)/$(ARCH)-linux-musl-cross/bin/
.PHONY: help zircon-init update rootfs libc-test other-test image check doc clean
.PHONY: help setup update rootfs libc-test other-test image check doc clean
# print top level help
help:
cargo xtask
cargo xtask help
# download zircon binaries
zircon-init:
cargo zircon-init
# setup git lfs and git submodules
setup:
cargo setup
# update toolchain and dependencies
update:
@ -22,19 +18,11 @@ update:
# put rootfs for linux mode
rootfs:
ifeq ($(XTASK), 1)
cargo rootfs --arch $(ARCH)
else ifeq ($(ARCH), riscv64)
@rm -rf rootfs/riscv && mkdir -p rootfs/riscv/bin
@wget https://github.com/rcore-os/busybox-prebuilts/raw/master/busybox-1.30.1-riscv64/busybox -O rootfs/riscv/bin/busybox
@ln -s busybox rootfs/riscv/bin/ls
endif
# put libc tests into rootfs
libc-test:
cargo libc-test --arch $(ARCH)
find rootfs/$(ARCH)/libc-test -type f \
-name "*so" -o -name "*exe" -exec $(STRIP) {} \;
# put other tests into rootfs
other-test:
@ -42,13 +30,7 @@ other-test:
# build image from rootfs
image:
ifeq ($(XTASK), 1)
cargo image --arch $(ARCH)
else ifeq ($(ARCH), riscv64)
@echo building riscv.img
@rcore-fs-fuse zCore/riscv64.img rootfs/riscv zip
@qemu-img resize -f raw zCore/riscv64.img +5M
endif
# check code style
check:
@ -61,21 +43,11 @@ doc:
# clean targets
clean:
cargo clean
rm -f *.asm
rm -rf rootfs
rm -rf zCore/disk
find zCore -maxdepth 1 -name "*.img" -delete
find zCore -maxdepth 1 -name "*.bin" -delete
# delete targets, including those that are large and compile slowly
cleanup: clean
rm -rf ignored/target
find zCore -maxdepth 1 -name "*.img" -delete
# delete everything, including origin files that are downloaded directly
clean-everything: clean
rm -rf ignored
# 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.
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.

View File

@ -1,278 +0,0 @@
# zCore
[![CI](https://github.com/rcore-os/zCore/workflows/CI/badge.svg?branch=master)](https://github.com/rcore-os/zCore/actions)
[![Docs](https://img.shields.io/badge/docs-alpha-blue)](https://rcore-os.github.io/zCore/)
[![Coverage Status](https://coveralls.io/repos/github/rcore-os/zCore/badge.svg?branch=master)](https://coveralls.io/github/rcore-os/zCore?branch=master)
Reimplement [Zircon][zircon] microkernel in safe Rust as a userspace program!
## Dev Status
🚧 Working In Progress
- 2020.04.16: Zircon console is working on zCore! 🎉
## Quick start for RISCV64
```sh
make riscv-image
cd zCore
make run ARCH=riscv64 LINUX=1
```
## Getting started
Environments
- [Rust toolchain](http://rustup.rs)
- [QEMU](https://www.qemu.org)
### Developing environment info
- current rustc -- rustc 1.60.0-nightly (5e57faa78 2022-01-19)
- current rust-toolchain -- nightly-2022-01-20
- current qemu -- 5.2.0 -> 6.2.0
Clone repo and pull prebuilt fuchsia images:
```sh
git clone https://github.com/rcore-os/zCore --recursive
cd zCore
make setup
```
For users in China, there's a mirror you can try:
```sh
git clone https://github.com.cnpmjs.org/rcore-os/zCore --recursive
```
Use docker container as standand develop environment, please refer to [tootls/docker](https://github.com/rcore-os/zCore/tree/master/tools/docker).
### Run zcore in libos mode
#### Run zcore in linux-libos mode
- step 1: Prepare Alpine Linux rootfs:
```sh
make rootfs
```
- step 2: Compile & Run native Linux program (Busybox) in libos mode:
```sh
cargo run --release --features "linux libos" -- /bin/busybox [args]
```
You can also add the feature `graphic` to show the graphical output (with [sdl2](https://www.libsdl.org) installed).
To debug, set the `LOG` environment variable to one of `error`, `warn`, `info`, `debug`, `trace`.
#### Run native Zircon program (shell) in zircon-libos mode:
- step 1: Compile and Run Zircon shell
```sh
cargo run --release --features "zircon libos" -- prebuilt/zircon/x64/bringup.zbi
```
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:
```sh
make rootfs
```
- step 2: Create Linux rootfs image:
Note: Before below step, you can add some special apps in zCore/rootfs
```sh
make image
```
- 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]
```
#### Run Zircon shell 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:
```sh
# See template in zircon-user
cd zircon-user && make zbi MODE=release
# Run your programs in zCore
cd zCore && make run MODE=release USER=1 [LOG=warn] [GRAPHIC=on] [ACCEL=1]
```
## Testing
### LibOS Mode Testing
#### Zircon related
Run Zircon official core-tests:
```sh
pip3 install pexpect
cd scripts && python3 unix-core-testone.py 'Channel.*'
```
Run all (non-panicked) core-tests for CI:
```sh
pip3 install pexpect
cd scripts && python3 unix-core-tests.py
# Check `zircon/test-result.txt` for results.
```
#### Linux related
Run Linux musl libc-tests for CI:
```sh
make rootfs && make libc-test
cd scripts && python3 libos-libc-tests.py
# Check `linux/test-result.txt` for results.
```
### Bare-metal Mode Testing
#### Zircon related
Run Zircon official core-tests on bare-metal:
```sh
cd zCore && make test MODE=release [ACCEL=1] TEST_FILTER='Channel.*'
```
Run all (non-panicked) core-tests for CI:
```sh
pip3 install pexpect
cd scripts && python3 core-tests.py
# Check `zircon/test-result.txt` for results.
```
#### x86-64 Linux related
Run Linux musl libc-tests for CI:
```sh
## Prepare rootfs with libc-test apps
make baremetal-test-img
## Build zCore kernel
cd zCore && make build MODE=release LINUX=1 ARCH=x86_64
## Testing
cd scripts && python3 baremetal-libc-test.py
##
```
You can use [`scripts/baremetal-libc-test-ones.py`](./scripts/baremetal-libc-test-ones.py) & [`scripts/linux/baremetal-test-ones.txt`](./scripts/linux/baremetal-test-ones.txt) to test specified apps.
[`scripts/linux/baremetal-test-fail.txt`](./scripts/linux/baremetal-test-fail.txt) includes all failed x86-64 apps (We need YOUR HELP to fix bugs!)
#### riscv-64 Linux related
Run Linux musl libc-tests for CI:
```sh
## Prepare rootfs with libc-test & oscomp apps
make riscv-image
## Build zCore kernel & Testing
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
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>
### 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
cd zCore #zCore ROOT DIR
make rootfs
cp ../rcore-user/app/snake rootfs/bin #copy snake ELF file to rootfs/bin
make image # build rootfs image
cd zCore #zCore kernel dir
make run MODE=release LINUX=1 GRAPHIC=on
```
Then you can play the game.
Operation
- Keyboard
- `W`/`A`/`S`/`D`: Move
- `R`: Restart
- `ESC`: End
- Mouse
- `Left`: Speed up
- `Right`: Slow down
- `Middle`: Pause/Resume
## Doc
```
make doc
```
### RISC-V 64 porting info
- [porting riscv64 doc](./docs/porting-rv64.md)
## Components
### Overview
![](./docs/structure.svg)
[zircon]: https://fuchsia.googlesource.com/fuchsia/+/master/zircon/README.md
[kernel-objects]: https://github.com/PanQL/zircon/blob/master/docs/objects.md
[syscalls]: https://github.com/PanQL/zircon/blob/master/docs/syscalls.md
### Hardware Abstraction Layer
| | Bare Metal | Linux / macOS |
| :------------------------ | ---------- | ----------------- |
| Virtual Memory Management | Page Table | Mmap |
| Thread Management | `executor` | `async-std::task` |
| Exception Handling | Interrupt | Signal |
### Small Goal & Little Plans
- <https://github.com/rcore-os/zCore/wiki/Plans>

418
README.md
View File

@ -1,270 +1,282 @@
# zCore
[![CI](https://github.com/rcore-os/zCore/actions/workflows/build.yml/badge.svg?branch=master)](https://github.com/rcore-os/zCore/actions)
[![Docs](https://img.shields.io/badge/docs-pages-green)](https://rcore-os.github.io/zCore/)
[![CI](https://github.com/rcore-os/zCore/workflows/CI/badge.svg?branch=master)](https://github.com/rcore-os/zCore/actions)
[![Docs](https://img.shields.io/badge/docs-alpha-blue)](https://rcore-os.github.io/zCore/)
[![Coverage Status](https://coveralls.io/repos/github/rcore-os/zCore/badge.svg?branch=master)](https://coveralls.io/github/rcore-os/zCore?branch=master)
[![issue](https://img.shields.io/github/issues/rcore-os/zCore)](https://github.com/rcore-os/zCore/issues)
[![forks](https://img.shields.io/github/forks/rcore-os/zCore)](https://github.com/rcore-os/zCore/fork)
![stars](https://img.shields.io/github/stars/rcore-os/zCore)
![license](https://img.shields.io/github/license/rcore-os/zCore)
基于 zircon 并提供 Linux 兼容性的操作系统内核。
Reimplement [Zircon][zircon] microkernel in safe Rust as a userspace program!
## 原版README
## Manual
Reimplement `Zircon` microkernel in safe Rust as a userspace program!
[This](docs/Manual.md) is a new simple chinese manual.
- zCore设计架构概述
- 支持bare-metal模式的Zircon & Linux
- 支持libos模式的Zircon & Linux
- 支持的图形应用程序等更多指导请查看[原版README文档](README-arch.md)。
## Dev Status
## 启动内核
🚧 Working In Progress
```bash
cargo qemu --arch riscv64
```
- 2020.04.16: Zircon console is working on zCore! 🎉
这个命令会使用 qemu-system-riscv64 启动 zCore。
## Quick start for RISCV64
默认的文件系统中将包含 busybox 应用程序和 musl-libc 链接器。它们是用自动下载的 musl-libc RISC-V 交叉编译工具链编译的。
## 目录
- [启动内核](#启动内核)
- [项目构建](#项目构建)
- [构建命令](#构建命令)
- [命令参考](#命令参考)
- [平台支持](#平台支持)
- [Qemu/virt](#qemuvirt)
- [全志/哪吒](#全志哪吒)
- [赛昉/星光](#赛昉星光)
- [晶视/cr1825](#晶视cr1825)
## 项目构建
项目构建采用 [xtask 模式](https://github.com/matklad/cargo-xtask),常用操作被封装成 cargo 命令。
另外,还通过 [Makefile](Makefile) 提供 make 调用,以兼容一些旧脚本。
目前已测试的开发环境包括 Ubuntu20.04、Ubuntu22.04 和 Debian11Ubuntu22.04 不能正确编译 x86_64 的 libc 测试。若不需要烧写到物理硬件,使用 WSL2 或其他虚拟机的操作与真机并无不同之处。
### 构建命令
命令的基本格式为 `cargo <command> [--args [value]]`,这实际上是 `cargo run --package xtask --release -- <command> [--args [value]]` 的简写。`command` 被传递给 xtask 应用程序,解析并执行。
许多命令的效果受到仓库环境的影响,也会影响仓库的环境。为了使用方便,如果一个命令依赖于另一个命令的效果,它们被设计为递归的。命令的递归关系图如下,对于它们的详细解释在下一节:
---
> **NOTICE** 建议使用等宽字体
---
```text
┌────────────┐ ┌─────────────┐ ┌─────────────┐
| update-all | | check-style | | zircon-init |
└────────────┘ └─────────────┘ └─────────────┘
┌─────┐ ┌──────┐ ┌─────┐ ┌─────────────┐ ┌─────────────────┐
| asm | | qemu |─→| bin | | linux-libos | | libos-libc-test |
└─────┘ └──────┘ └─────┘ └─────────────┘ └─────────────────┘
| └───┐┌─────┘ ┌───────────┐
↓ ↓↓ ┌──| libc-test |
┌───────┐ ┌────────┐←─┘ └───────────┘
| image |───────→| rootfs |←─┐ ┌────────────┐
└───────┘ └────────┘ └─| other-test |
┌────────┐ ↑ └────────────┘
| opencv |────→┌───────────┐
└────────┘ ┌─→| musl-libc |
┌────────┐ | └───────────┘
| ffmpeg |──┘
└────────┘
-------------------------------------------------------------------
图例A 递归执行 BA 依赖 B 的结果,执行 A 时自动先执行 B
┌───┐ ┌───┐
| A |─→| B |
└───┘ └───┘
```sh
make riscv-image
cd zCore
make run ARCH=riscv64 LINUX=1
```
### 命令参考
## Getting started
如果下面的命令描述与行为不符,或怀疑此文档更新不及时,亦可直接查看[内联文档](xtask/src/main.rs#L48)。
如果发现 `error: no such subcommand: ...`,查看[命令简写](.cargo/config.toml)为哪些命令设置了别名。
Environments
---
- [Rust toolchain](http://rustup.rs)
- [QEMU](https://www.qemu.org)
- [Git LFS](https://git-lfs.github.com)
> **NOTICE** 内联文档也是中英双语
### Developing environment info
---
- current rustc -- rustc 1.60.0-nightly (5e57faa78 2022-01-19)
- current rust-toolchain -- nightly-2022-01-20
- current qemu -- 5.2.0 -> 6.2.0
#### **update-all**
Clone repo and pull prebuilt fuchsia images:
更新工具链、依赖和 git 子模块。
如果没有递归克隆子模块,可以使用这个命令克隆。
```bash
cargo update-all
```sh
git clone https://github.com/rcore-os/zCore --recursive
cd zCore
git lfs install
git lfs pull
```
#### **check-style**
For users in China, there's a mirror you can try:
静态检查。设置多种编译选项,检查代码能否编译。
```bash
cargo check-style
```sh
git clone https://github.com.cnpmjs.org/rcore-os/zCore --recursive
```
#### **zircon-init**
### Run zcore in libos mode
下载 zircon 模式所需的二进制文件。
#### Run zcore in linux-libos mode
```bash
cargo zircon-init
- step 1: Prepare Alpine Linux rootfs:
```sh
make rootfs
```
- step 2: Compile & Run native Linux program (Busybox) in libos mode:
```sh
cargo run --release --features "linux libos" -- /bin/busybox [args]
```
You can also add the feature `graphic` to show the graphical output (with [sdl2](https://www.libsdl.org) installed).
To debug, set the `LOG` environment variable to one of `error`, `warn`, `info`, `debug`, `trace`.
#### Run native Zircon program (shell) in zircon-libos mode:
- step 1: Compile and Run Zircon shell
```sh
cargo run --release --features "zircon libos" -- prebuilt/zircon/x64/bringup.zbi
```
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:
```sh
make rootfs
```
- step 2: Create Linux rootfs image:
Note: Before below step, you can add some special apps in zCore/rootfs
```sh
make image
```
- 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]
```
#### Run Zircon shell 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:
```sh
# See template in zircon-user
cd zircon-user && make zbi MODE=release
# Run your programs in zCore
cd zCore && make run MODE=release USER=1 [LOG=warn] [GRAPHIC=on] [ACCEL=1]
```
## Testing
### LibOS Mode Testing
#### Zircon related
Run Zircon official core-tests:
```sh
pip3 install pexpect
cd scripts && python3 unix-core-testone.py 'Channel.*'
```
#### **asm**
Run all (non-panicked) core-tests for CI:
反汇并保存编指定架构的内核。默认保存到 `target/zcore.asm`
```bash
cargo asm -m virt-riscv64 -o z.asm
```sh
pip3 install pexpect
cd scripts && python3 unix-core-tests.py
# Check `zircon/test-result.txt` for results.
```
#### **bin**
#### Linux related
生成内核 raw 镜像到指定位置。默认输出到 `target/{arch}/release/zcore.bin`
Run Linux musl libc-tests for CI:
```bash
cargo bin -m virt-riscv64 -o z.bin
```sh
make rootfs && make libc-test
cd scripts && python3 libos-libc-tests.py
# Check `linux/test-result.txt` for results.
```
#### **qemu**
### Bare-metal Mode Testing
在 Qemu 中启动 zCore。这需要 Qemu 已经安装好了。
#### Zircon related
```bash
cargo qemu --arch riscv64 --smp 4
Run Zircon official core-tests on bare-metal:
```sh
cd zCore && make test MODE=release [ACCEL=1] TEST_FILTER='Channel.*'
```
支持将 qemu 连接到 gdb
Run all (non-panicked) core-tests for CI:
```bash
cargo qemu --arch riscv64 --smp 4 --gdb 1234
```sh
pip3 install pexpect
cd scripts && python3 core-tests.py
# Check `zircon/test-result.txt` for results.
```
#### **rootfs**
#### x86-64 Linux related
重建 Linux rootfs。直接执行这个命令会清空已有的为此架构构造的 rootfs 目录,重建最小的 rootfs。
Run Linux musl libc-tests for CI:
```bash
cargo rootfs --arch riscv64
```sh
## Prepare rootfs with libc-test apps
make baremetal-test-img
## Build zCore kernel
cd zCore && make build MODE=release LINUX=1 ARCH=x86_64
## Testing
cd scripts && python3 baremetal-libc-test.py
##
```
#### **musl-libs**
You can use [`scripts/baremetal-libc-test-ones.py`](./scripts/baremetal-libc-test-ones.py) & [`scripts/linux/baremetal-test-ones.txt`](./scripts/linux/baremetal-test-ones.txt) to test specified apps.
将 musl 动态库拷贝到 rootfs 目录对应位置。
[`scripts/linux/baremetal-test-fail.txt`](./scripts/linux/baremetal-test-fail.txt) includes all failed x86-64 apps (We need YOUR HELP to fix bugs!)
```bash
cargo musl-libs --arch riscv64
#### riscv-64 Linux related
Run Linux musl libc-tests for CI:
```sh
## Prepare rootfs with libc-test & oscomp apps
make riscv-image
## Build zCore kernel & Testing
cd scripts && python3 baremetal-test-riscv64.py
##
```
#### **ffmpeg**
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.
将 ffmpeg 动态库拷贝到 rootfs 目录对应位置。
[`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!)
```bash
cargo ffmpeg --arch riscv64
## Graph/Game
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
cd zCore #zCore ROOT DIR
make rootfs
cp ../rcore-user/app/snake rootfs/bin #copy snake ELF file to rootfs/bin
make image # build rootfs image
cd zCore #zCore kernel dir
make run MODE=release LINUX=1 GRAPHIC=on
```
#### **opencv**
Then you can play the game.
Operation
将 opencv 动态库拷贝到 rootfs 目录对应位置。如果 ffmpeg 已经放好了opencv 将会编译出包含 ffmepg 支持的版本。
- Keyboard
- `W`/`A`/`S`/`D`: Move
- `R`: Restart
- `ESC`: End
- Mouse
- `Left`: Speed up
- `Right`: Slow down
- `Middle`: Pause/Resume
```bash
cargo opencv --arch riscv64
## Doc
```
make doc
```
#### **libc-test**
### RISC-V 64 porting info
将 libc 测试集拷贝到 rootfs 目录对应位置。
- [porting riscv64 doc](./docs/porting-rv64.md)
```bash
cargo libc-test --arch riscv64
```
## Components
#### **other-test**
### Overview
将其他测试集拷贝到 rootfs 目录对应位置。
![](./docs/structure.svg)
```bash
cargo other-test --arch riscv64
```
[zircon]: https://fuchsia.googlesource.com/fuchsia/+/master/zircon/README.md
[kernel-objects]: https://github.com/PanQL/zircon/blob/master/docs/objects.md
[syscalls]: https://github.com/PanQL/zircon/blob/master/docs/syscalls.md
#### **image**
### Hardware Abstraction Layer
从 rootfs 目录构建 Linux rootfs 镜像文件。
| | Bare Metal | Linux / macOS |
| :------------------------ | ---------- | ----------------- |
| Virtual Memory Management | Page Table | Mmap |
| Thread Management | `executor` | `async-std::task` |
| Exception Handling | Interrupt | Signal |
```bash
cargo image --arch riscv64
```
### Small Goal & Little Plans
#### **linux-libos**
在 linux libos 模式下启动 zCore 并执行位于指定路径的应用程序。
> **NOTICE** libos 模式只能执行单个应用程序,完成就会退出。
```bash
cargo linux-libos --args "/bin/busybox"
```
可以直接给应用程序传参数:
```bash
cargo linux-libos --args "/bin/busybox ls"
```
## 平台支持
### Qemu/virt
直接使用命令启动,参见[启动内核](#启动内核)和 [`qemu` 命令](#qemu)。
### 全志/哪吒
使用以下命令构造系统镜像:
```bash
cargo bin -m nezha -o z.bin
```
然后使用 [rustsbi-d1](https://github.com/rustsbi/rustsbi-d1) 将镜像部署到 Flash 或 DRAM。
另: 可以查看[README for D1 文档](docs/README-D1.md)获知更多D1开发板有关的操作指导。
### 赛昉/星光
使用以下命令构造系统镜像:
```bash
cargo bin -m visionfive -o z.bin
```
然后根据[此文档](docs/README-visionfive.md)的详细说明通过 u-boot 网络启动系统。
### 晶视/cr1825
使用以下命令构造系统镜像:
```bash
cargo bin -m cr1825 -o z.bin
```
然后通过 u-boot 网络启动系统。
## 其他
- [An English README](docs/README_EN.md)
- [开发者注意事项(草案)](docs/for-developers.md)
- [构建系统更新日志](xtask/CHANGELOG.md)
- <https://github.com/rcore-os/zCore/wiki/Plans>

View File

@ -1,31 +0,0 @@
[qemu.virt-riscv64]
arch = "riscv64"
[qemu.virt-aarch64]
arch = "aarch64"
[qemu.virt-x86_64]
arch = "x86_64"
[allwinner.nezha]
arch = "riscv64"
link-user-img = "zCore/riscv64.img"
pci-support = false
features = ["allwinner-drivers"]
[cvitek.cr1825]
arch = "riscv64"
link-user-img = "zCore/riscv64.img"
pci-support = false
features = ["thead-maee"]
[starfive.visionfive]
arch = "riscv64"
link-user-img = "zCore/riscv64.img"
pci-support = false
[sifive.fu740]
arch = "riscv64"
link-user-img = "zCore/riscv64.img"
pci-support = true
features = ["fu740-drivers"]

86
docs/Manual.md Normal file
View File

@ -0,0 +1,86 @@
# 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

@ -1,277 +0,0 @@
# zCore on riscv64
## T-HEAD C910 Light val board 操作说明
### 编译zCore内核镜像
编译zCore内核:
```
cd zCore/zCore
make build LINUX=1 MODE=release ARCH=riscv64 PLATFORM=c910light
```
制作u-boot系统镜像:
```
mkimage -A riscv -O linux -C none -T kernel -a 0x200000 -e 0x200000 -n "zCore for c910" -d ../target/riscv64/release/zcore.bin uImageC910
```
### 编译opensbi镜像
```
git clone https://github.com/elliott10/opensbi.git -b thead_light-c910
cd opensbi
make PLATFORM=generic CROSS_COMPILE=/path/to/toolchain/bin/riscv64-unknown-linux-gnu-
# 生成所需的fw_dynamic.bin
```
原编译工具链基于官方仓库https://gitee.com/thead-yocto/xuantie-yocto.git 编译生成出来的。理论上可以使用其他工具链替代之
### 基于u-boot运行
在搭建好tftp服务的服务器目录中放入编译好的opensbi镜像`fw_dynamic.bin`和系统镜像`uImageC910`。<br>
进入配置好网络的C910 Light板子的u-boot命令行上运行
```
ext4load mmc 0:2 $aon_ram_addr light_aon_fpga.bin; ext4load mmc 0:2 $dtb_addr ${fdt_file};
tftp $opensbi_addr fw_dynamic.bin;
tftp $kernel_addr uImageC910;
bootslave; run finduuid; run set_bootargs; bootm $kernel_addr - $dtb_addr;
```
## T-HEAD C910 Light val board 移植说明
### 1. 系统初步分析并制作系统镜像
<img src="img/c910-light.jpeg" alt="c910-light" style="zoom:25%;" />
C910 Light开发板如上图在取得C910 Light开发板后先按照官方的用户手册了解基本的硬件组件以及电源和串口等接口的接线。<br>
用户手册https://gitee.com/thead-yocto/documents/blob/master/en/user_guide/T-Head%20Yeying1520%20Yocto%20User%20Guide.pdf <br>
电源接上以及串口连接到host机后可以看到有四个串口`/dev/ttyUSBX`调试用串口是host机连上该串口并在启动u-boot时按任意键可进入命令行模式<br>
u-boot命令行模式上可以连接通有线网络并通过tftp协议加载待启动的操作系统镜像。<br>
```
# minicom -b 115200 -D /dev/ttyUSB2
U-Boot 2020.01-ge0ddd4721a (Dec 14 2021 - 22:26:59 +0800)
CPU: rv64imafdcvsu
Model: T-HEAD c910 light
DRAM: 1 GiB
C910 CPU FREQ: 1500MHz
AHB2_CPUSYS_HCLK FREQ: 250MHz
AHB3_CPUSYS_PCLK FREQ: 125MHz
PERISYS_AHB_HCLK FREQ: 250MHz
PERISYS_APB_PCLK FREQ: 62MHz
GMAC PLL POSTDIV FREQ: 1000MHZ
DPU0 PLL POSTDIV FREQ: 1188MHZ
DPU1 PLL POSTDIV FREQ: 1188MHZ
MMC: sdhci@ffe7080000: 0, sd@ffe7090000: 1
Loading Environment from MMC... OK
In: serial@ffe7014000
Out: serial@ffe7014000
Err: serial@ffe7014000
Net: eth0: ethernet@ffe7070000
Hit any key to stop autoboot: 0
C910 Light#
# setenv ipaddr <IP>
# setenv serverip <Server IP>
```
在这里一开始尝试fu740板子的zCore系统镜像制作以及tftp启动模式, 在u-boot命令行中配置开发板IP地址和服务器IP地址通过tftp协议加载系统镜像最后通过bootm运行镜像; <br>
其他正常但这样在引导zCore系统镜像时会出现报错显示无法识别该系统镜像.
```
Filename 'uImageC910'.
Load address: 0x200000
Loading: #################################################################
#############################################
5.1 MiB/s
done
Bytes transferred = 1609651 (188fb3 hex)
Wrong Image Format for bootm command
ERROR: can't get kernel image!
```
这个问题分析后发现由于u-boot的版本不同导致对系统镜像格式的识别不一致。<br>
在fu740板子上的zCore系统镜像是基于`.its`脚本的新`FIT image`;<br>
而C910 Light的板子上的u-boot则只支持`old legacy image`,需要这样制作:
```
mkimage -A riscv -O linux -C none -T kernel -a 0x200000 -e 0x200000 -n "zCore for c910" -d ../target/riscv64/release/zcore.bin uImageC910
```
### 2. zCore系统引导构建
根据板子已有的Linux系统镜像可获知加载地址是`Load Address: 0x200000`, 执行入口地址是`Entry Point: 0x200000`.
由`0x200000`入口地址修改zCore的linker.ld链接脚本文件的`BASE_ADDRESS`变量为相应的值编译出zCore系统镜像在u-boot中使用`tftp`命令网络加载镜像,`bootm`命令尝试引导镜像,发现在跳转内核后无任何反应。
这里分析可能有两种可能第一可能zCore默认串口输出调用的opensbi print不正确第二则可能在开始构建虚拟内存并跳转时出错。于是这里先让zCore引导启动时用物理内存的方式把`zCore/src/platform/riscv/`目录中的引导有关的偏移地址变量暂修改成以`0x200000`为入口地址的相应的值即可便没有了问题二剩下了问题一关于opensbi的输出问题。
为了验证opensbi的输出是否正常先尝试最精简的zCore镜像在启动到rust代码的最早阶段调用opensbi的`SBI_CONSOLE_PUTCHAR`输出功能。问题依旧无任何反应,这里陷入了问题僵局;
C910 Light开发板是一块四方形大板配置接口很丰富包括了调试CPU的JTAG口。根据平头哥的官方调试文档连接部署好调试环境 https://occ.t-head.cn/document?temp=linux&slug=t-head-debug-server-user-manual
<img src="img/c910-jtag.jpg" alt="jtag" style="zoom:25%;" />
通过gdb连接JTAG DEBUG Server后便可以单步调试C910 CPU的指令执行了不过偶尔也会有无法下断点的问题需要先把zCore系统镜像加载到内存之后再下函数断点。
在JTAG的单步调试过程中发现在执行指令`ecall SBI_CONSOLE_PUTCHAR`之后没有任何反应理论上应该会有字符从串口输出。这里考虑没有有效的opensbi要么串口驱动有问题。
解决print问题解决串口输出比较直接于是参照u-boot的串口代码把串口输出的基本功能使能代码如下
```
// T-HEAD C910 light
pub fn uart_put(c: u8) {
let ptr = BADDR as *mut u32;
unsafe {
//LSR bit:THRE
while ptr.add(5).read_volatile() & (1 << 5) == 0 {}
//此时transmitter empty, THR有效位是8
ptr.add(0).write_volatile(c as u32);
}
}
pub fn uart_get() -> Option<u8> {
let ptr = BADDR as *mut u32;
unsafe {
//查看LSR的DR位为1则有数据
if ptr.add(5).read_volatile() & 0b1 == 0 {
None
} else {
Some((ptr.add(0).read_volatile() & 0xff) as u8)
}
}
}
```
于是zCore便可以运行输出了。
这里出现device tree解析DTB失败的问题经研究尝试发现是由于DTB加载到内存的空间被zCore内核覆盖了把DTB地址往高地址再移一段偏移便可以正常解析到DTB。
![c910 uart](img/c910-run-uart.png)
后面与平头哥的技术支持人员沟通获得了C910 light板子的文档和代码据此获知更多有效信息可以自定义编译u-boot、Linux内核、以及文件系统等板子必要组件
通过结合分析C910 light板子的文档和源代码理清楚了C910 light板子的启动链:
```
U-Boot 运行于M态
|
V
OpenSBI 由U-Boot来加载会从M态跳转至S态
|
V
Linux 由U-Boot来加载并运行于S态
```
所有若直接使用U-Boot单独加载一个zCore Kernel是没有OpenSBI可print的效果便是无任何输出这里定位了问题便着手修复。
试验使用u-boot单独运行opensbi发现并没有常见的“OPENSBI”大LOGO输出于是尝试修复opensbi的串口串口驱动缺少了对C910 light板子型号`snps,dw-apb-uart`的解析,于是走的通用串口型号`ns16550`打上patchhttps://github.com/elliott10/opensbi/commit/404951dd5b047873fa023545eafeb1fa2a9c5838
编译运行OpenSBI的输出work
### 3. zCore虚拟内存页表问题
zCore继续往下运行便会遇到新的问题停在切换页表`switch table`之后。
这是个很奇怪的问题正常流程这里会映射好zCore kernel的所有sections以及其他的内存地址空间到一个新创建的页表中映射的参数和过程都是复用的其他板子类型如qemu或D1等的。理论上这里没理由出现BUG停在的地点如下
```
[ 48.117274 INFO 0 0:0 kernel_hal::imp::arch::vm] initialized kernel page table @ 0x5c18000
[ 48.128044 DEBUG 0 0:0 kernel_hal::imp::arch::vm] cpu 0 switch table 2ec000 -> 5c18000
```
这个奇怪的问题再次上JTAG调试器跟踪CPU运行到这里后单步指令的行为。
在`switch table`切换页表前下断点,单步跟踪,发现在`csrw satp`之后程序便跑飞了触发异常。于是怀疑satp使用的页表有问题。
Linux代码是zCore开发中非常好的参照这里开始对照Linux的切换页表写satp的过程找到一些参考
<img src="img/c910-linux-pg.png" alt="c910 pagetable" style="zoom:75%;" />
Linux源码中的riscv架构下在构建虚拟内存页表项时
为内核镜像内存地址空间`PAGE_KERNEL`添加相比普通页表的额外的flags属性`CACHE`,`SHARE`,`BUF`
为设备地址空间`PAGE_IOREMAP`添加额外的属性:`SHARE`,`SO`;
这些页表项的额外的flags属性位可以通过查询C910芯片手册获知其定义信息C910额外页面属性位于`63:59`位,包括了`SO`, `CACHE`, `BUF`, `SHARE`, `SEC`
更加其他CPU芯片手册可指导这些平头哥CPU的拓展属性不单在C910中存在在C906 CPU中通用存在。
![c910 pte flags](img/c910-pte-flags.png)
zCore中先尝试把内核的`CACHE`,`SHARE`,`BUF`这些位在构建内核页表时置位上,启动发现问题依旧,依然停在切换页表`switch table`之后,原因不详???
既然基于RISCV标准进行自定义拓展的位理论上应该是可以关闭的吧于是继续在芯片手册中查找果然在拓展状态寄存器`MXSTATUS`中找到了相应的设置位`MAEE`
![c910 mxstatus](img/c910-mxstatus.png)
C910 CPU的MAEE拓展位可以设置是否打开拓展的MMU地址属性即是否使能`SO`, `CACHE`, `BUF`, `SHARE`, `SEC`
设置`MAEE = 0`时, 不拓展MMU地址属性`SO`, `CACHE`, `BUF`, `SHARE`, `SEC`
设置`MAEE = 1`时, 使能拓展MMU中PTE的地址属性`SO`, `CACHE`, `BUF`, `SHARE`, `SEC`并可以在页表项PTE中设置对应位
![c910 mxstatus](img/c910-maee.jpeg)
于是直接关闭虚拟内存的页表项拓展属性,设置`MAEE = 0`,果然之前停在页表切换处`switch table`的问题通过了。zCore可以继续往下执行开始解析设备树的各node节点后面接着会遇到设备地址过高导致在处理解析到的node节点地址时出错...
### 4. 页表项PTE的拓展属性设置MAEE于CR1825板子的尝试
之前一次与DF交流CR1825目前遇到的BUG情况时一开始有提议说可能内核的`.BSS`段可能未清除干净。
因为在去年刚把增加了riscv支持的zCore移植到D1时也出现过spin原子指令死锁的问题这个问题当时请教的JYK童鞋后给思路原来`.bss`段没clear干净导致未初始化时的原子变量存在了随机值持续死锁。
<img src="img/c906-clear-bss.jpeg" alt="c906 clear bsss" style="zoom:50%;" />
不过,这个清除`.bss`段应该是随后就加上了。虽然后来引导启动部分有重构过DF也确认确有执行`.bss`段清除。
我在调试C910的期间在芯片手册中了解页表属性及其相关的其他寄存器位的同时也对比C906手册发现基本两CPU在属性设置方面没有大的区别。
在修复好C910 light板子的停在页表切换处`switch table`的问题后与DF交流并取得cr1825的opensbi, u-boot, Linux等的源代码主要对比与C910 light板子的启动代码的区别。
发现带C906 CPU的cr1825与C910 CPU的light板子的启动代码很相似包括虚拟内存的构建过程同样也对内核虚拟内存的页表项配置了拓展位`cache`, `share`, `buf`而原生zCore从未对这些位进行配置。
于是猜想也许页表项PTE的拓展位设置问题与当前cr1825遇到的原子锁问题有很大的关联原子操作即是需要对虚拟内存中的某个值进行判断改写。
为了验证该猜想制作了一个cr1825的启动引导镜像`fip.bin`, 方式是直接关闭虚拟内存的页表项拓展属性,设置`MAEE = 0`代码修改如https://github.com/elliott10/opensbi/commit/404951dd5b047873fa023545eafeb1fa2a9c5838
请DF帮忙远程验证幸运地原子锁的问题也通过了的确与平头哥的拓展页表项有关
<img src="img/c906-amo-1.jpg" alt="c906 amo 1" style="zoom:50%;" />
<img src="img/c906-amo-2.jpg" alt="c906 amo 1" style="zoom:50%;" />
之后在群里与YDR等人继续交流关于平头哥拓展位的原理问题并获得平头哥技术人员的确认: "PTE中cacheable代表该page可以被906 cache缓存如果为0则不会进入缓存。PTE中bufferable位控制总线传输时的bufferable信号是否拉起在行为上cpu并不关心"“amo指令需要cache支持也就是不能在非cache的区域使用amo指令”。
cr1825锁卡住的问题通了后后面进展较顺利了。
在打开`maee`的情况下,这里可能需要注意内核镜像和设备地址空间所设置的`PTE`额外属性值不同。
根据Linux源码在构建虚拟内存页表项时
为内核镜像内存地址空间`PAGE_KERNEL`添加相比普通页表的额外的flags属性`CACHE`,`SHARE`,`BUF`
为设备地址空间`PAGE_IOREMAP`添加额外的属性:`SHARE`,`SO`;
### 5. 设备地址过高的问题
前面讲到zCore构建好虚拟内存之后解析设备树的各node节点时后面接着会遇到设备地址过高的问题导致在处理解析到的node节点地址时出错。
例如从设备树中,取得的串口基地址是`0xffe7014000`该地址比一般的设备地址大例如相比Qemu的串口基地址`0x10000000`。C910 light板子的多种设备基地址都类似的这么大。在物理地址空间中这些大的设备地址不会出问题但在zCore构建好内核虚拟内存后当统一加上一个`offset`如`0xffffffe000200000`便溢出了SV39模式的虚拟内存地址空间。
对于地址溢出时,对该问题做一个简单的判断处理,把溢出的保留位重新置为`1`即可:
```
paddr | (0x1ffffff << 39)
```
### 5. C910 light板子运行
zCore顺利运行进busybox shell
![c910 zcore](img/c910-zcore-run.png)

View File

@ -1,7 +1,6 @@
# zCore on riscv64
# zCore for riscv64
## D1开发板
### 编译 zCore 系统镜像
## 编译 zCore 系统镜像
先在源码根目录下编译 riscv64 的文件系统。
@ -13,7 +12,7 @@ cd zCore
make build LINUX=1 ARCH=riscv64 PLATFORM=d1 MODE=release
```
### riscv64 开发板的烧写
## riscv64 开发板的烧写
以全志 D1 c906 开发板为例。
@ -30,10 +29,10 @@ make
安装好工具 `xfel`,开发板进入 FEL 模式,可在开发板的 Linux 系统中执行 `reboot efex` 命令进入 FEL 模式。然后运行:
```sh
make run LINUX=1 ARCH=riscv64 PLATFORM=d1 MODE=release
make run_d1 LINUX=1 ARCH=riscv64 PLATFORM=d1 MODE=release
```
### (可选)手动烧写运行:
### 手动烧写运行:
1. 下载 D1 开发板的 [OpenSBI](https://github.com/elliott10/opensbi) 源码,并编译出镜像 build/platform/thead/c910/firmware/fw_payload.elf
@ -43,7 +42,7 @@ make run LINUX=1 ARCH=riscv64 PLATFORM=d1 MODE=release
make PLATFORM=thead/c910 CROSS_COMPILE=/path/to/toolchain/bin/riscv64-unknown-linux-gnu- SUNXI_CHIP=sun20iw1p1 PLATFORM_RISCV_ISA=rv64gcxthead
```
或使用预编译的镜像 [prebuilt/firmware/riscv/d1_fw_payload.elf](../prebuilt/firmware/riscv/d1_fw_payload.elf).
或使用预编译的镜像 [prebuilt/firmware/d1/fw_payload.elf](../prebuilt/firmware/d1/fw_payload.elf)。
2. 生成包含了 OpenSBI, dtb, zCore 的待烧写固件:
@ -55,12 +54,12 @@ make run LINUX=1 ARCH=riscv64 PLATFORM=d1 MODE=release
3. 启动全志 D1 c906 开发板,并进入 FEL 模式。然后通过烧写工具 `xfel` 把 zCore 系统镜像载入到 DDR 中:
```
sudo xfel ddr d1
sudo xfel ddr ddr3
sudo xfel write 0x40000000 zcore_d1.bin
sudo xfel exec 0x40000000
```
### 引导运行
## 引导运行
zCore 成功引导后, OpenSBI 会将 dtb 加载到高地址 `0x5ff00000`,运行如下所示:

View File

@ -1,40 +0,0 @@
# zCore on riscv64 for fu740
### 编译zCore for fu740系统镜像
先在源码根目录下编译 riscv64 的文件系统。
然后进入子目录 zCore 编译内核,会生成系统镜像`zcore-fu740.itb`
系统镜像会包含fu740板子的设备树, dtb设备树可以从fu740自带的Linux中的`/boot`目录中获取;
也可以从sifive官方镜像中获取https://github.com/sifive/freedom-u-sdk/releases/download/2022.04.00/demo-coreip-cli-unmatched-2022.04.00.rootfs.wic.xz
```sh
make riscv-image
cd zCore
make build MODE=release LINUX=1 ARCH=riscv64 PLATFORM=fu740
```
### 基于U-Boot启动系统镜像
首先搭建一台tftp服务器, 例如在Linux服务器中安装`tftpd-hpa`, 一般tftp服务的目录会在`/srv/tftp/`;
然后把编译出的zCore for fu740系统镜像`zcore-fu740.itb`拷贝到tftp服务目录
开发板fu740开机并进入U-Boot命令行
```
# 配置开发板IP地址和服务器IP地址
setenv ipaddr <IP>
setenv serverip <Server IP>
# 通过tftp协议加载系统镜像
tftp 0xa0000000 zcore-fu740.itb
# 运行
bootm 0xa0000000
```
### fu740资料汇集
Unmatched fu740 板子资料整理, 请见:
https://github.com/oscomp/DocUnmatchedU740/blob/main/unmatched.md

View File

@ -1,287 +0,0 @@
# 在 visionfive 上运行zCore
## 一. visionfive 开发板烧写
> **NOTICE** 本文描述的上位机操作在 Ubuntu20.04 上测试可用
### 1. 在工控机上部署必要服务
```bash
# 部署 dhcpd
# 1. 安装 dhcp3-server
sudo apt install isc-dhcp-server
# 2. 设置 dhcp 服务接口,这个接口为实际的物理网卡接口
vim /etc/default/isc-dhcp-server
------------------------------------------------
INTERFACESv4="enp2s0" # 设置 dhcpv4 端口为 enp2s0
INTERFACESv6=""
------------------------------------------------
# 3. 给这个接口配置 IP 地址,并 up 接口
vim /etc/netplan/01-network-manager-all.yaml
-----------------------------------------------------------
# Let NetworkManager manage all devices on this system
network:
version: 2
renderer: NetworkManager
ethernets:
eno1:
addresses: []
dhcp4: true
optional: true
enp2s0:
addresses: [192.168.10.10/24]
gateway4: 192.168.10.1
nameservers:
addresses: [114.114.114.114,8.8.8.8]
dhcp4: no
------------------------------------------------------------
sudo netplan appply
# 4. 设置 dhcp 相关配置
vim /etc/dhcp/dhcpd.conf
----------------------------------------------------
subnet 192.168.10.0 netmask 255.255.255.0 {
range 192.168.10.120 192.168.10.128;
option routers 192.168.10.10;
option subnet-mask 255.255.255.0;
option broadcast-address 192.168.10.255;
option domain-name-servers 192.168.10.10;
}
-----------------------------------------------------
# 5. 启动 dhcpd 服务
systemctl restart isc-dhcp-server
# 6. 检查 dhcpd 服务状态
systemctl status isc-dhcp-server
# 部署 tftpd
# 1. 安装 tftpd-hpa
sudo apt install tftpd-hpa
# 2. 修改配置
--------------------------------------------------------------
TFTP_USERNAME="tftp"
TFTP_DIRECTORY="/root/work/tftpboot" # 此项为 tftp 文件下载路径
TFTP_ADDRESS=":69"
TFTP_OPTIONS="--secure"
--------------------------------------------------------------
# 3. 启动 tftpd 服务
systemctl restart tftpd-hpa
# 4. 检查 tftpd 服务状态
systemctl status tftpd-hpa
```
### 2. 连接工控机和 visionfive 开发板
![avatar](visionfive.jpg)
```bash
# 圆头黑色线为工控机电源线
# 黄色网线是用来板子 dhcp 获取地址的
# 蓝色网线是工控机用来连接公网下载资源的,这里可以忽略
# 白色 USB 接口是给板子供电的5v/3A
# 黑色 USB 接口是串口控制台
```
在工控机上打开串口助手minicom开发板上电后过几秒钟会自动进入 u-boot 命令行模式
```bash
Welcome to minicom 2.7.1
OPTIONS: I18n
Compiled on Dec 23 2019, 02:06:26.
Port /dev/ttyUSB0, 12:54:20
Press CTRL-A Z for help on special keys
VisionFive #
VisionFive #
VisionFive #
# 此时可以使用 `help` 查看有哪些可用命令
# 使用 `printenv` 查看配置了哪些环境变量
# 1. 输入 `dhcp` 命令,让开发板获取 IP 地址
# 注意此时可能会自动下载服务器中的镜像, 请通过Ctrl+C打断
dhcp
# 2. 设置 tftp 客户端地址(本机)
setenv ipaddr 192.168.10.121 # 设置 dhcp 获取的那个地址
# 3. 设置 tftp 服务端地址(工控机)
setenv serverip 192.168.10.10 # 需要与自己 IP 在同一网段
# 4. 测试一下网络是否通畅
ping 192.168.10.10 # 试一下ping主机可选
# 5. 保存上述配置
saveenv # 保存配置到 flash之后就不再需要配置
```
### 3. 制作 itb 格式镜像
```bash
# 1. 从 visionfive 官方库下载 `starfive_fb.h` `starfive_vic7100_clk.dtsi` `starfive_vic7100_evb.dts`
# 2. 使用以下命令编译 dtb
cpp -nostdinc -I include -undef -x assembler-with-cpp starfive_vic7100_evb.dts starfive.dts.0
dtc -o starfive.dtb starfive.dts.0 # 预编译的starfive.dtb已放在prebuilt目录
# 3. 压缩内核镜像到 `z.bin.gz`
gzip -9 -cvf z.bin > z.bin.gz
# 4. 制作 itb 文件
mkimage -f zcore-starfive.its z.itb # zcore-starfive.its即prebuilt目录下的starfive_fdt.its故也可使用mkimage -f prebuilt/firmware/riscv/starfive_fdt.its z.itb达到相同的效果
下面是 zcore-starfive.its 内容
--------------------------------------------------------------------
/*
* U-Boot uImage source file for "zCore-visionfive"
*/
/dts-v1/;
/ {
description = "U-Boot uImage source file for zCore-visionfive";
#address-cells = <1>;
images {
kernel {
description = "Linux kernel for zCore-visionfive";
data = /incbin/("./z.bin.gz");
type = "kernel";
arch = "riscv";
os = "linux";
compression = "gzip";
load = <0x80200000>;
entry = <0x80200000>;
};
fdt {
description = "Flattened Device Tree blob for zCore-visionfive";
data = /incbin/("./starfive.dtb");
type = "flat_dt";
arch = "riscv";
compression = "none";
};
};
configurations {
default = "conf";
conf {
description = "Boot Linux kernel with FDT blob";
kernel = "kernel";
fdt = "fdt";
};
};
};
--------------------------------------------------------------------
# 5. 将 `z.itb` 放入 tftp 服务器指定的下载路径
cp z.itb /path/to/tftpboot
```
### 4. 上传 itb 文件到开发板内存,并从指定位置启动
```bash
VisionFive #tftpboot 0xc0000000 z.itb
Speed: 1000, full duplex
Using dwmac.10020000 device
TFTP from server 192.168.10.10; our IP address is 192.168.10.121
Filename 'z.itb'.
Load address: 0xc0000000
Loading: ################################################## 1.5 MiB
11.4 MiB/s
done
Bytes transferred = 1584003 (182b83 hex)
VisionFive #bootm 0xc0000000
## Loading kernel from FIT Image at c0000000 ...
Using 'conf' configuration
Trying 'kernel' kernel subimage
Description: Linux kernel for zCore-FU740
Type: Kernel Image
Compression: gzip compressed
Data Start: 0xc00000e8
Data Size: 1564993 Bytes = 1.5 MiB
Architecture: RISC-V
OS: Linux
Load Address: 0x80200000
Entry Point: 0x80200000
Verifying Hash Integrity ... OK
## Loading fdt from FIT Image at c0000000 ...
Using 'conf' configuration
Trying 'fdt' fdt subimage
Description: Flattened Device Tree blob for zCoreFU740
Type: Flat Device Tree
Compression: uncompressed
Data Start: 0xc017e2ec
Data Size: 17270 Bytes = 16.9 KiB
Architecture: RISC-V
Verifying Hash Integrity ... OK
Booting using the fdt blob at 0xc017e2ec
Uncompressing Kernel Image
Loading Device Tree to 00000000ff6e1000, end 00000000ff6e8375 ... OK
Starting kernel ...
boot page table launched, sstatus = 0x8000000200046000
kernel (physical): 0000000080200000..0000000085ce70b8
kernel (remapped): ffffffc080200000..ffffffc085ce70b8
device tree: 00000000ff6e1000..00000000ff6e6000
hart0 is booting...
hart1 is the primary hart.
[ 28.007868 WARN 1 0:0 zcore_drivers::builder::devicetree] device-tree: failed to parsing node "gpio@11910000": InvalidParam
[ 28.022102 ERROR 1 0:0 zcore_drivers::irq::riscv_intc] invalid SCAUSE value 0xb!
[ 28.032369 ERROR 1 0:0 zcore_drivers::irq::riscv_intc] invalid SCAUSE value 0xb!
[ 28.074321 WARN 1 0:0 linux_syscall] brk: unimplemented
[ 28.082355 WARN 1 0:0 linux_syscall] brk: unimplemented
[ 28.090609 WARN 1 0:0 linux_syscall::vm] mprotect: unimplemented
[ 28.100315 WARN 1 0:0 linux_syscall::vm] mprotect: unimplemented
[ 28.109179 WARN 1 0:0 linux_syscall] getuid: unimplemented
[ 28.117922 WARN 1 0:0 linux_syscall] getpgid: unimplemented
[ 28.126330 WARN 1 0:0 linux_syscall] setpgid: unimplemented
[ 28.134857 WARN 1 0:0 linux_object::fs::stdio] stdout TCGETS | TIOCSPGRP, pretend to be tty.
[ 28.146419 WARN 1 0:0 linux_object::fs::stdio] stdin TCGETS | TIOCSPGRP, pretend to be tty.
[ 28.157926 WARN 1 0:0 linux_syscall] geteuid: unimplemented
[ 28.166389 WARN 1 0:0 linux_syscall] geteuid: unimplemented
/ #
```
## 二. visionfive 移植问题处理
### 1. 烧录问题
我们使用 `tftpboot 0xc0000000 z.itb` 命令烧录,这个 `0xc0000000` 地址要留足内核解压后的空间。
### 2. 内存映射问题
星光开发板的 u-boot 需要给内核和设备树设置加载位置, 然后通过 `a1` 寄存器将设备树的位置通知内核,实际上设备树被放置到超过 1 GiB 的位置上,而 zCore 只支持 1 GiB所以报非法内存问题。我们需要修改内存映射布局修改参考这 2 个commit
[commit1](https://github.com/rcore-os/zCore/commit/227956d5df401c8f8f2fa746f8aa911d3530637f)
[commit2](https://github.com/rcore-os/zCore/commit/16772b9363d02945863008c6a4639ad1cb37eed4)
### 3. 中断处理中有 bug需要使用当前核去处理对应中断修复见
[commit](https://github.com/rcore-os/zCore/commit/55b3145442f0f70c01527c20e87988d26c01a39b)
### 4. 串口驱动
星光开发板支持 `16550` 驱动,只需做相应的代码适配即可,修改见
[commit](https://github.com/rcore-os/zCore/commit/55b3145442f0f70c01527c20e87988d26c01a39b)
### 5. 未注册中断处理
我们发现星光开发板从 `1` 号核心启动后会报一个 `131` 的中断,这个中断在设备树中是没有的,所以也没有在内核中注册,所以会报错,我们在中断处理的时候,将它的优先级降低做屏蔽处理了,见:
[commit](https://github.com/rcore-os/zCore/commit/55b3145442f0f70c01527c20e87988d26c01a39b)

View File

@ -1,257 +0,0 @@
# zCore
[![CI](https://github.com/rcore-os/zCore/actions/workflows/build.yml/badge.svg?branch=master)](https://github.com/rcore-os/zCore/actions)
[![Docs](https://img.shields.io/badge/docs-pages-green)](https://rcore-os.github.io/zCore/)
[![Coverage Status](https://coveralls.io/repos/github/rcore-os/zCore/badge.svg?branch=master)](https://coveralls.io/github/rcore-os/zCore?branch=master)
[![issue](https://img.shields.io/github/issues/rcore-os/zCore)](https://github.com/rcore-os/zCore/issues)
[![forks](https://img.shields.io/github/forks/rcore-os/zCore)](https://github.com/rcore-os/zCore/fork)
![stars](https://img.shields.io/github/stars/rcore-os/zCore)
![license](https://img.shields.io/github/license/rcore-os/zCore)
An OS kernel based on zircon, provides Linux compatible mode.
- [中文自述文档](../README.md)
- [legacy README](README_LEGACY.md)
> you may want to check the legacy for setting up docker, running graphical applications, etc. But many of these scripts are deprecated
## Launch zCore
```bash
cargo qemu --arch riscv64
```
This command will launch zCore using qemu-system-riscv64。
The default file system will contain a busybox application and a musl-libc linker. They are compiled by automatic downloaded musl-libc RISC-V cross-compilation tool chain.
## Table of contents
- [Launch zCore](#launch-zcore)
- [Build the project](#build-the-project)
- [Commands](#commands)
- [Commands reference](#commands-reference)
- [Platform support](#platform-support)
- [Qemu/virt](#qemuvirt)
- [Allwinner/nezha](#allwinnernezha)
- [starfivetech/visionfive](#starfivetechvisionfive)
- [cvitek/cr1825](#cvitekcr1825)
## Build the project
The project will be built with [xtask](https://github.com/matklad/cargo-xtask). The common operations are provided as cargo commands.
An extra [Makefile](../Makefile) provides make calls for compatibility with some legacy scripts.
Currently tested development environments include Ubuntu 20.04, Ubuntu 22.04 and Debian 11.
The libc tests for x86_64 cannot compile on Ubuntu22.04.
If you do not need to flash to physical hardware, using WSL2 or other virtual machines does not operate any differently from the real machine.
### Commands
The basic format of the command is `cargo <command> [--rags [value]]`, which is actually `cargo run --package xtask --release -- <command> [--args [value]]`. `command` is passed to the xtask application to parse and execute.
The effects of many commands are affected by the repo environment and will also affect the repo environment. For convenience, if one command depends on the result of another command, they are designed to recursion. The recursive relationship diagram of the commands is as follows. The detailed explanation of them is in the next section:
---
> **NOTICE** It is recommended to use equivalent fonts
---
```text
┌────────────┐ ┌─────────────┐ ┌─────────────┐
| update-all | | check-style | | zircon-init |
└────────────┘ └─────────────┘ └─────────────┘
┌─────┐ ┌──────┐ ┌─────┐ ┌─────────────┐ ┌─────────────────┐
| asm | | qemu |─→| bin | | linux-libos | | libos-libc-test |
└─────┘ └──────┘ └─────┘ └─────────────┘ └─────────────────┘
| └───┐┌─────┘ ┌───────────┐
↓ ↓↓ ┌──| libc-test |
┌───────┐ ┌────────┐←─┘ └───────────┘
| image |───────→| rootfs |←─┐ ┌────────────┐
└───────┘ └────────┘ └─| other-test |
┌────────┐ ↑ └────────────┘
| opencv |────→┌───────────┐
└────────┘ ┌─→| musl-libc |
┌────────┐ | └───────────┘
| ffmpeg |──┘
└────────┘
-------------------------------------------------------------------
Example`A` recursively executing `B` (`A` depends on the results of `B`, and `B` is executed before `A` automatically)
┌───┐ ┌───┐
| A |─→| B |
└───┘ └───┘
```
### Commands reference
If the following command description does not match its behavior, or if you suspect that this documentation is not up to date, you can check the [inline documentation](../xtask/src/main.rs#L48) as well.
If you find `error: no such subcommand: ...`, check [command alias](../.cargo/config.toml) to see which commands have aliases set for them.
---
> **NOTICE** inline documentation is also bilingual
---
#### **update-all**
Updates toolchain、dependencies and submodules.
```bash
cargo update-all
```
#### **check-style**
Checks code without running. Try to compile the project with various different features.
```bash
cargo check-style
```
#### **zircon-init**
Download zircon binaries.
```bash
cargo zircon-init
```
#### **asm**
Dumps the asm of kernel for specific architecture.
The default output is `target/zcore.asm`.
```bash
cargo asm -m virt-riscv64 -o z.asm
```
#### **bin**
Strips kernel binary for specific architecture.
The default output is `target/{arch}/release/zcore.bin`.
```bash
cargo bin -m virt-riscv64 -o z.bin
```
#### **qemu**
Runs zCore in qemu.
```bash
cargo qemu --arch riscv64 --smp 4
```
Connects qemu to gdb
```bash
cargo qemu --arch riscv64 --smp 4 --gdb 1234
```
#### **rootfs**
Rebuilds the linux rootfs.
This command will remove the existing rootfs directory for this architecture,
and rebuild a minimum rootfs.
```bash
cargo rootfs --arch riscv64
```
#### **musl-libs**
Copies musl so files to rootfs directory.
```bash
cargo musl-libs --arch riscv64
```
#### **ffmpeg**
Copies ffmpeg so files to rootfs directory.
```bash
cargo ffmpeg --arch riscv64
```
#### **opencv**
Copies opencv so files to rootfs directory.
If ffmpeg is already there, this opencv will build with ffmpeg support.
```bash
cargo opencv --arch riscv64
```
#### **libc-test**
Copies libc test files to rootfs directory.
```bash
cargo libc-test --arch riscv64
```
#### **other-test**
Copies other test files to rootfs directory.
```bash
cargo other-test --arch riscv64
```
#### **image**
Builds the linux rootfs image file.
```bash
cargo image --arch riscv64
```
#### **linux-libos**
Runs zCore in linux libos mode and runs an executable at the specified path.
> **NOTICE** zCore can only run a single executable in libos mode, and it will exit after finishing.
```bash
cargo linux-libos --args /bin/busybox
```
## Platform support
### Qemu/virt
Launch with command directly, see [launch zCore](#launch-zcore).
### Allwinner/nezha
Build kernel binary with the following command:
```bash
cargo bin -m nezha -o z.bin
```
Then deploy the binary to Flash or DRAM with [rustsbi-d1](https://github.com/rustsbi/rustsbi-d1).
### Starfivetech/visionfive
Build kernel binary with the following command:
```bash
cargo bin -m visionfive -o z.bin
```
Then, see [this document](docs/README-visionfive.md) for detailed description, launching the system through u-boot network.
### cvitek/cr1825
Build kernel binary with the following command:
```bash
cargo bin -m cr1825 -o z.bin
```
Then launch the system through u-boot network.

View File

@ -1,145 +0,0 @@
# 开发者注意事项(草案)
本文用于同步开发 zCore 的一些策略选择并提醒开发者某些需要注意的信息。
> 本文暂时是一份草案,欢迎在相关微信群或 github [讨论区](https://github.com/rcore-os/zCore/discussions/356)发表对形式和内容的意见
## 目录
- [工具链支持策略](#工具链支持策略)
>
> - 确定跟踪工具链的时间点
> - 汇总使用到的不稳定特性,以及使用的原因
>
- [代码质量保障](#代码质量保障)
> 介绍如何使用 `#[deny(...)]``#[allow(...)]`
- [依赖管理策略](#依赖管理策略)
> 介绍何时应以何种方式引入依赖项
- [features and cfg](#features-and-cfg)
> 介绍如何使用编译条件
## 工具链支持策略
由于[下文](#使用的不稳定特性)详述的具体原因,本项目依赖一些不稳定特性,只能使用 nightly 工具链编译。仓库将测试可用的工具链记录在 cargo 可识别的[工具链配置文件](../rust-toolchain.toml),使用 cargo 构建项目时会自动安装可靠的工具链。
仓库使用的工具链虽然是 nightly 的,但将伴随 stable 工具链的版本更新而更新。每当 stable 工具链更新,就将默认工具链更新到最接近最新 stable 的版本,周期约为 6 周。参考[版本信息网站](https://forge.rust-lang.org/)记录的最新稳定版分叉发生时间,使用对应的 nightly 即可。
下一次更新的版本为 1.642022-08-05进行更新的日期为 2022 年 9 月 22 日。
> 本文档记录的预期更新时间将随着每次工具链更新而更新。
### 使用的不稳定特性
#### [`doc_cfg`](https://doc.rust-lang.org/unstable-book/language-features/doc-cfg.html)
用到的模块:`zcore-drivers`、`kernel-hal`、`zcore-loader`
用于在文档上标记对象可使用的平台信息。
标注有助于提升文档质量,但不影响使用,必要时可去除。
#### [`naked_functions`](https://doc.rust-lang.org/unstable-book/language-features/naked-functions.html), [`asm_sym`](https://doc.rust-lang.org/unstable-book/language-features/asm-sym.html), [`asm_const`](https://doc.rust-lang.org/unstable-book/language-features/asm-const.html)
用到的模块:`zcore`
这三项用于支撑一个 rust 裸函数。裸函数不会自动插入栈操作,因此可用于设置栈之前的阶段。配合用于向内联汇编导入 rust 常量的 `asm_const` 和向内联汇编导入 rust 符号的 `asm_sym`,可以将整个启动阶段尽量置于 rust 的保护之下(避免硬编码常量或导出全局符号)。
可以移除,但不建议。
#### [`default_alloc_error_handler`](https://doc.rust-lang.org/unstable-book/language-features/default-alloc-error-handler.html)
用到的模块:`zcore`
要求 `alloc` 提供一个默认的分配失败回调。
只要同时使用 `no_std``alloc` 就必然需要分配失败回调,可选默认的或通过另一个不稳定特性 [`alloc-error-handler`](https://doc.rust-lang.org/unstable-book/language-features/alloc-error-handler.html) 提供一个自定义的。
## 代码质量保障
代码质量主要依赖 **clippy** 来保障。因此,需要创造利于 clippy 运行的环境,这包括三个部分:
1. rust-analyzer 绑定
如果使用 vs code 开发rust-analyzer 支持 checkOnSave 功能,即保存时自动检查(得益于现代编译器的效率,这是可能的)。如果配合自动保存功能,可实现随时检查,只要将检查方式默认为 clippy即可随时 clippy。
当然 clippy 运行比较慢,如果电脑性能不适应,只好关掉。
2. `#![deny(warnings)]`
这个选项将当前模块当然也包括子模块产生的警告视为错误这会禁止产生警告的代码完成编译有助于及早解决问题。clippy 也将产生警告,这些警告也被视作错误。
目前所有模块都添加了这个选项有些还禁止了别的东西unsafe_code 及 missing_docs 等,这不在我们的讨论范围内),且处在可通过编译的状态。开发时为了方便当然可以注释掉它们,但如果发布 PR务必恢复这些选项。
3. github actions
使用 clippy 检查代码已经写入 github 工作流,每次提交都会自动执行。这可以向其他开发者证明你的代码质量受到保障。可以在本地使用 `cargo check-style` 命令检查代码的合规性,其流程和使用 clippy 的方式与 github 工作流保持一致。
## 依赖管理策略
依赖从特殊到一般,分为以下 4 种形式:
1. [git 子模块](#git-子模块)
2. [个人仓库中基于 cargo 的项目](#个人仓库中基于-cargo-的项目)
3. [组织仓库中基于 cargo 的项目](#组织仓库中基于-cargo-的项目)
4. [发布到 crates.io 上的 crate](#发布到-cratesio-上的-crate)
### git 子模块
最特殊的依赖方式,对于那些不使用 cargo由于不是 rust 编写)的项目不得不如此。
目前使用此方式依赖的项目包括:
- libc-test
musl libc 的测例。使用 c 语言实现。
- tests
测试框架。主要使用 python。
- rboot
uefi 引导程序,使用 rust 实现。作为子模块是一个遗留问题,未来会解决。
### 个人仓库中基于 cargo 的项目
比较特殊的依赖方式,当且仅当一个项目具有下列情况之一:
- 属于实验性质,不稳定甚至可能放弃;
- 稳定,但不适合发布到 crates.io也没有组织愿意收录
- 从组织项目分叉,已提交 PR 但尚未采纳;
- 从组织项目分叉,且出于充分的理由决定永久分叉,成为一个独立的项目;
可以直接从个人项目中直接依赖。
如有可能,上述情况应当积极解决。
必须锁定提交哈希。
### 组织仓库中基于 cargo 的项目
正常的依赖方式,但若有可能,尽量发布到 crates.io。
必须锁定提交哈希。
### 发布到 crates.io 上的 crate
正常的依赖方式,可以随意使用。
尽量跟踪最新版本。对于无法跟踪的依赖,应记录理由。
## features and cfg
zCore 支持多种平台的不同硬件,难以避免使用编译选项。但是不当使用编译选项,可能导致混乱,或者干扰测试的覆盖性。因此,建议遵从如下标准设置 `#[cfg(...)]`
1. 仅与由平台决定的,设置 target_arch
2. 受到其他因素影响的,考虑通过设备树等方式动态决定;
3. 无法动态决定的,可以设置 feature但应在所在项目的入口lib.rs 或 main.rs注明设置 feature 的原因;
4. 平台相关的 feature应增加如下的约束而不是使用 `all(target_arch = ..., feature = ...)`
```rust
#[cfg(all(feature = "sbi", not(target_arch = "riscv64")))]
compile_error!("`sbi` is only available on RISC-V platforms");
```
> 现有代码不完全满足以上标准,将逐步改正

Binary file not shown.

Before

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 578 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 166 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 MiB

View File

@ -11,16 +11,10 @@ description = "Device drivers of zCore"
graphic = ["rcore-console"]
mock = ["async-std", "sdl2"]
virtio = ["virtio-drivers"]
loopback = []
no-pci = []
# special drivers for hardwares
allwinner = ["d1-pac"]
fu740 = []
[dependencies]
log = "0.4"
spin = "0.9"
cfg-if = "1.0"
bitflags = "1.3"
lazy_static = "1.4"
@ -30,37 +24,23 @@ bitmap-allocator = { git = "https://github.com/rcore-os/bitmap-allocator", rev =
pci = { git = "https://github.com/elliott10/pci-rs", rev = "8f33774b" }
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 = "8486b8" }
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",
] }
d1-pac = { version = "0.0.27", optional = true }
volatile = "0.3"
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"] }
# 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"
x2apic = "0.4"
x86_64 = "0.14"
[target.'cfg(any(target_arch = "riscv32", target_arch = "riscv64"))'.dependencies]
riscv = "0.9"
riscv = "0.8"

View File

@ -17,14 +17,15 @@
//!
//! Specification: <https://github.com/devicetree-org/devicetree-specification/releases/download/v0.3/devicetree-specification-v0.3.pdf>.
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, PhysAddr, VirtAddr,
Device, DeviceError, DeviceResult, VirtAddr,
};
use alloc::{collections::BTreeMap, sync::Arc, vec::Vec};
const MODULE: &str = "device-tree";
@ -62,48 +63,6 @@ impl<M: IoMapper> DevicetreeDriverBuilder<M> {
let mut intc_map = BTreeMap::new(); // phandle -> intc
let mut dev_list = Vec::new(); // devices
// 为 d1 启动 uart5
// 硬编码只是一个临时的方案
#[cfg(feature = "allwinner")]
{
use d1_pac::{ccu::RegisterBlock as Ccu, gpio::RegisterBlock as Gpio, CCU, GPIO};
let gpio = unsafe { &*(self.mmap(GPIO::PTR as _, 0x1000)? as *const Gpio) };
let ccu = unsafe { &*(self.mmap(CCU::PTR as _, 0x800)? as *const Ccu) };
#[rustfmt::skip]
gpio.pb_cfg0.modify(|r, w| unsafe {
w.bits(r.bits())
.pb0_select().uart2_tx()
.pb1_select().uart2_rx()
.pb4_select().uart5_tx()
.pb5_select().uart5_rx()
});
#[rustfmt::skip]
gpio.pb_cfg1.modify(|r, w| unsafe {
w.bits(r.bits())
.pb8_select().uart0_tx()
.pb9_select().uart0_rx()
});
#[rustfmt::skip]
gpio.pd_cfg1.modify(|r, w| unsafe {
w.bits(r.bits())
.pd10_select().uart3_tx()
.pd11_select().uart3_rx()
});
#[rustfmt::skip]
ccu.uart_bgr.write(|w| w
.uart0_rst() .deassert()
.uart0_gating().pass()
.uart2_rst() .deassert()
.uart2_gating().pass()
.uart3_rst() .deassert()
.uart3_gating().pass()
.uart5_rst() .deassert()
.uart5_gating().pass()
);
}
// 解析设备树
self.dt.walk(&mut |node, comp, props| {
debug!(
@ -127,11 +86,10 @@ impl<M: IoMapper> DevicetreeDriverBuilder<M> {
match comp {
#[cfg(feature = "virtio")]
c if c.contains("virtio,mmio") => self.parse_virtio(node, props),
#[cfg(not(feature = "loopback"))]
c if c.contains("allwinner,sunxi-gmac") => {
self.parse_ethernet(node, comp, props)
}
c if c.contains("ns16550a") || c.iter().any(|str| str.ends_with("uart")) => {
c if c.contains("ns16550a") || c.contains("allwinner,sun20i-uart") => {
self.parse_uart(node, comp, props)
}
_ => Err(DeviceError::NotSupported),
@ -175,12 +133,6 @@ impl<M: IoMapper> DevicetreeDriverBuilder<M> {
// 丢弃中断信息
Ok(dev_list.into_iter().map(|(dev, _)| dev).collect())
}
fn mmap(&self, phys_addr: PhysAddr, len: usize) -> DeviceResult<VirtAddr> {
self.io_mapper
.query_or_map(phys_addr, len)
.ok_or(DeviceError::NoResources)
}
}
#[allow(dead_code)]
@ -202,16 +154,17 @@ impl<M: IoMapper> DevicetreeDriverBuilder<M> {
.prop_u32("#interrupt-cells")
.map_err(|_| DeviceError::InvalidParam)?;
let interrupts_extended = parse_interrupts(node, props)?;
let base_vaddr =
parse_reg(node, props).and_then(|(paddr, size)| self.mmap(paddr as _, size as _));
let base_vaddr = parse_reg(node, props).and_then(|(paddr, size)| {
self.io_mapper
.query_or_map(paddr as usize, size as usize)
.ok_or(DeviceError::NoResources)
});
use crate::irq::*;
let dev = Device::Irq(match comp {
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
c if c.contains("riscv,cpu-intc") => Arc::new(riscv::Intc::new()),
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
c if c.contains("riscv,plic0") => Arc::new(riscv::Plic::new(base_vaddr?)),
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
c if c.contains("sifive,fu540-c000-plic") => Arc::new(riscv::Plic::new(base_vaddr?)),
_ => return Err(DeviceError::NotSupported),
});
@ -231,8 +184,11 @@ impl<M: IoMapper> DevicetreeDriverBuilder<M> {
use virtio_drivers::{DeviceType, VirtIOHeader};
let interrupts_extended = parse_interrupts(node, props)?;
let base_vaddr =
parse_reg(node, props).and_then(|(paddr, size)| self.mmap(paddr as _, size as _))?;
let base_vaddr = parse_reg(node, props).and_then(|(paddr, size)| {
self.io_mapper
.query_or_map(paddr as usize, size as usize)
.ok_or(DeviceError::NoResources)
})?;
let header = unsafe { &mut *(base_vaddr as *mut VirtIOHeader) };
if !header.verify() {
return Err(DeviceError::NotSupported);
@ -262,8 +218,11 @@ impl<M: IoMapper> DevicetreeDriverBuilder<M> {
props: &InheritProps,
) -> DeviceResult<DevWithInterrupt> {
let interrupts_extended = parse_interrupts(node, props)?;
let base_vaddr =
parse_reg(node, props).and_then(|(paddr, size)| self.mmap(paddr as _, size as _));
let base_vaddr = parse_reg(node, props).and_then(|(paddr, size)| {
self.io_mapper
.query_or_map(paddr as usize, size as usize)
.ok_or(DeviceError::NoResources)
});
info!("Ethernet gmac init ...");
let irq_num = interrupts_extended[1];
@ -289,22 +248,19 @@ impl<M: IoMapper> DevicetreeDriverBuilder<M> {
props: &InheritProps,
) -> DeviceResult<DevWithInterrupt> {
let interrupts_extended = parse_interrupts(node, props)?;
let base_vaddr =
parse_reg(node, props).and_then(|(paddr, size)| self.mmap(paddr as _, size as _))?;
let base_vaddr = parse_reg(node, props).and_then(|(paddr, size)| {
self.io_mapper
.query_or_map(paddr as usize, size as usize)
.ok_or(DeviceError::NoResources)
});
use crate::uart::*;
let dev = Device::Uart(match comp {
c if c.contains("ns16550a") => {
Arc::new(unsafe { Uart16550Mmio::<u8>::new(base_vaddr) })
Arc::new(unsafe { Uart16550Mmio::<u8>::new(base_vaddr?) })
}
c if c.contains("snps,dw-apb-uart") => {
Arc::new(unsafe { Uart16550Mmio::<u32>::new(base_vaddr) })
}
#[cfg(feature = "allwinner")]
c if c.contains("allwinner,sun20i-uart") => Arc::new(UartAllwinner::new(base_vaddr)),
#[cfg(feature = "fu740")]
c if c.contains("sifive,fu740-c000-uart") => {
Arc::new(unsafe { UartU740Mmio::<u32>::new(base_vaddr) })
c if c.contains("allwinner,sun20i-uart") => {
Arc::new(unsafe { Uart16550Mmio::<u32>::new(base_vaddr?) })
}
_ => return Err(DeviceError::NotSupported),
});

View File

@ -1,3 +1,5 @@
#![allow(unused)]
#[cfg(any(target_arch = "x86_64", target_arch = "riscv64"))]
pub mod pci;
@ -9,7 +11,6 @@ pub fn virt_to_phys(vaddr: VirtAddr) -> PhysAddr {
unsafe { drivers_virt_to_phys(vaddr) }
}
#[allow(unused)]
extern "C" {
fn drivers_dma_alloc(pages: usize) -> PhysAddr;
fn drivers_dma_dealloc(paddr: PhysAddr, pages: usize) -> i32;

View File

@ -1,23 +1,22 @@
use super::{phys_to_virt, PAGE_SIZE};
use crate::builder::IoMapper;
use crate::{Device, DeviceError, DeviceResult};
use alloc::{format, sync::Arc, vec::Vec};
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_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_UPPER_ADDR: u16 = 0x08;
const PCI_MSI_DATA_32: u16 = 0x08;
const PCI_MSI_DATA_64: u16 = 0x0C;
// const PCI_COMMAND_INTX_DISABLE:u16 = 0x400;
const PCI_CAP_ID_MSI: u8 = 0x05;
struct PortOpsImpl;
@ -100,7 +99,7 @@ unsafe fn enable(loc: Location, paddr: u64) -> Option<usize> {
// 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
warn!(
debug!(
"BAR0 set from {:#x} to {:#x}",
bar0_raw,
am.read32(ops, loc, BAR0)
@ -110,9 +109,9 @@ unsafe fn enable(loc: Location, paddr: u64) -> Option<usize> {
// 23 and lower are used
static mut MSI_IRQ: u32 = 23;
let _orig = am.read16(ops, loc, PCI_COMMAND);
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);
am.write32(ops, loc, PCI_COMMAND, (orig | 0x40f) as u32);
// find MSI cap
let mut msi_found = false;
@ -152,13 +151,13 @@ unsafe fn enable(loc: Location, paddr: u64) -> Option<usize> {
}
if !msi_found {
// am.write16(ops, loc, PCI_COMMAND, (0x2) as u16);
am.write16(ops, loc, PCI_COMMAND, 0x6);
am.write32(ops, loc, _PCI_INTERRUPT_LINE, 33);
// 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");
}
warn!("pci device enable done");
info!("pci device enable done");
assigned_irq
}
@ -167,7 +166,15 @@ pub fn init_driver(dev: &PCIDevice, mapper: &Option<Arc<dyn IoMapper>>) -> Devic
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 };
@ -186,28 +193,9 @@ pub fn init_driver(dev: &PCIDevice, mapper: &Option<Arc<dyn IoMapper>>) -> Devic
return Ok(dev);
}
}
(0x1b36, 0x10) => {
if let Some(BAR::Memory(addr, _len, _, _)) = dev.bars[0] {
#[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 blk = Arc::new(crate::nvme::NvmeInterface::new(vaddr, irq.unwrap_or(33))?);
let dev = Device::Block(blk);
return Ok(dev);
}
}
(0x8086, 0x10fb) => {
// 82599ES 10-Gigabit SFI/SFP+ Network Connection
if let Some(BAR::Memory(addr, _len, _, _)) = dev.bars[0] {
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);
@ -222,14 +210,14 @@ pub fn init_driver(dev: &PCIDevice, mapper: &Option<Arc<dyn IoMapper>>) -> Devic
}
}
(0x8086, 0x1533) => {
if let Some(BAR::Memory(addr, _len, _, _)) = dev.bars[0] {
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] {
if let Some(BAR::Memory(addr, len, _, _)) = dev.bars[0] {
info!(
"Found Intel I211 ethernet controller dev {:?}, addr: {:x?}",
dev, addr
@ -242,7 +230,7 @@ pub fn init_driver(dev: &PCIDevice, mapper: &Option<Arc<dyn IoMapper>>) -> Devic
if dev.id.class == 0x01 && dev.id.subclass == 0x06 {
// Mass storage class
// SATA subclass
if let Some(BAR::Memory(addr, _len, _, _)) = dev.bars[5] {
if let Some(BAR::Memory(addr, len, _, _)) = dev.bars[5] {
info!("Found AHCI dev {:?} BAR5 {:x?}", dev, addr);
/*
let irq = unsafe { enable(dev.loc) };
@ -259,7 +247,7 @@ pub fn init_driver(dev: &PCIDevice, mapper: &Option<Arc<dyn IoMapper>>) -> Devic
Err(DeviceError::NoResources)
}
pub fn detach_driver(_loc: &Location) -> bool {
pub fn detach_driver(loc: &Location) -> bool {
/*
match PCI_DRIVERS.lock().remove(loc) {
Some(driver) => {

View File

@ -2,6 +2,9 @@
//!
//! Reference: <https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/input-event-codes.h>
#![allow(dead_code)]
#![allow(unused_parens)]
/// Device properties and quirks
pub mod input_prop {
/// needs a pointer
@ -20,7 +23,7 @@ pub mod input_prop {
pub const INPUT_PROP_ACCELEROMETER: u16 = 0x06;
pub const INPUT_PROP_MAX: u16 = 0x1f;
pub const INPUT_PROP_CNT: u16 = INPUT_PROP_MAX + 1;
pub const INPUT_PROP_CNT: u16 = (INPUT_PROP_MAX + 1);
}
/// Event types
@ -38,7 +41,7 @@ pub mod ev {
pub const EV_PWR: u16 = 0x16;
pub const EV_FF_STATUS: u16 = 0x17;
pub const EV_MAX: u16 = 0x1f;
pub const EV_CNT: u16 = EV_MAX + 1;
pub const EV_CNT: u16 = (EV_MAX + 1);
}
/// Synchronization events
@ -48,7 +51,7 @@ pub mod syn {
pub const SYN_MT_REPORT: u16 = 2;
pub const SYN_DROPPED: u16 = 3;
pub const SYN_MAX: u16 = 0xf;
pub const SYN_CNT: u16 = SYN_MAX + 1;
pub const SYN_CNT: u16 = (SYN_MAX + 1);
}
/// Keys and buttons
@ -658,7 +661,7 @@ pub mod key {
pub const KEY_MIN_INTERESTING: u16 = KEY_MUTE;
pub const KEY_MAX: u16 = 0x2ff;
pub const KEY_CNT: u16 = KEY_MAX + 1;
pub const KEY_CNT: u16 = (KEY_MAX + 1);
}
/// Relative axes
@ -678,7 +681,7 @@ pub mod rel {
pub const REL_WHEEL_HI_RES: u16 = 0x0b;
pub const REL_HWHEEL_HI_RES: u16 = 0x0c;
pub const REL_MAX: u16 = 0x0f;
pub const REL_CNT: u16 = REL_MAX + 1;
pub const REL_CNT: u16 = (REL_MAX + 1);
}
/// Absolute axes
@ -731,7 +734,7 @@ pub mod abs {
pub const ABS_MT_TOOL_Y: u16 = 0x3d;
pub const ABS_MAX: u16 = 0x3f;
pub const ABS_CNT: u16 = ABS_MAX + 1;
pub const ABS_CNT: u16 = (ABS_MAX + 1);
}
/// Switch events
@ -755,7 +758,7 @@ pub mod sw {
pub const SW_MUTE_DEVICE: u16 = 0x0e;
pub const SW_PEN_INSERTED: u16 = 0x0f;
pub const SW_MAX: u16 = 0x0f;
pub const SW_CNT: u16 = SW_MAX + 1;
pub const SW_CNT: u16 = (SW_MAX + 1);
}
/// Misc events
@ -767,7 +770,7 @@ pub mod msc {
pub const MSC_SCAN: u16 = 0x04;
pub const MSC_TIMESTAMP: u16 = 0x05;
pub const MSC_MAX: u16 = 0x07;
pub const MSC_CNT: u16 = MSC_MAX + 1;
pub const MSC_CNT: u16 = (MSC_MAX + 1);
}
/// LEDs
@ -784,7 +787,7 @@ pub mod led {
pub const LED_MAIL: u16 = 0x09;
pub const LED_CHARGING: u16 = 0x0a;
pub const LED_MAX: u16 = 0x0f;
pub const LED_CNT: u16 = LED_MAX + 1;
pub const LED_CNT: u16 = (LED_MAX + 1);
}
/// Autorepeat values
@ -792,7 +795,7 @@ pub mod rep {
pub const REP_DELAY: u16 = 0x00;
pub const REP_PERIOD: u16 = 0x01;
pub const REP_MAX: u16 = 0x01;
pub const REP_CNT: u16 = REP_MAX + 1;
pub const REP_CNT: u16 = (REP_MAX + 1);
}
/// Sounds
@ -801,5 +804,5 @@ pub mod snd {
pub const SND_BELL: u16 = 0x01;
pub const SND_TONE: u16 = 0x02;
pub const SND_MAX: u16 = 0x07;
pub const SND_CNT: u16 = SND_MAX + 1;
pub const SND_CNT: u16 = (SND_MAX + 1);
}

View File

@ -1,200 +0,0 @@
use crate::prelude::IrqHandler;
use crate::scheme::{IrqScheme, Scheme};
use crate::utils::IrqManager;
use crate::DeviceResult;
use lock::Mutex;
pub static GICC_SIZE: usize = 0x1000;
pub static GICD_SIZE: usize = 0x1000;
static GICD_CTLR: u32 = 0x000;
static GICD_TYPER: u32 = 0x004;
static GICD_ISENABLER: u32 = 0x100;
static GICD_ICENABLER: u32 = 0x180;
static GICD_IPRIORITY: u32 = 0x400;
static GICD_ITARGETSR: u32 = 0x800;
static GICD_ICFGR: u32 = 0xc00;
static GICC_IAR: u32 = 0x000c;
static GICC_EOIR: u32 = 0x0010;
static GICC_CTLR: u32 = 0x0000;
static GICC_PMR: u32 = 0x0004;
pub struct IntController {
gicc: GicCpuIf,
gicd: GicDistIf,
manager: Mutex<IrqManager<50>>,
}
struct GicDistIf {
pub address: usize,
pub ncpus: u32,
pub nirqs: u32,
}
struct GicCpuIf {
address: usize,
}
impl IntController {
pub fn new(gicc_base: usize, gicd_base: usize) -> Self {
Self {
gicc: GicCpuIf { address: gicc_base },
gicd: GicDistIf {
address: gicd_base,
ncpus: 0,
nirqs: 0,
},
manager: Mutex::new(IrqManager::new(0..50)),
}
}
fn init(&mut self) {
unsafe {
// Disable IRQ Distribution
self.gicd.write(GICD_CTLR, 0);
let typer = self.gicd.read(GICD_TYPER);
self.gicd.ncpus = ((typer & (0x7 << 5)) >> 5) + 1;
self.gicd.nirqs = ((typer & 0x1f) + 1) * 32;
// Set all SPIs to level triggered
for irq in (32..self.gicd.nirqs).step_by(16) {
self.gicd.write(GICD_ICFGR + ((irq / 16) * 4), 0);
}
// Disable all SPIs
for irq in (32..self.gicd.nirqs).step_by(32) {
self.gicd
.write(GICD_ICENABLER + ((irq / 32) * 4), 0xffff_ffff);
}
// Affine all SPIs to CPU0 and set priorities for all IRQs
for irq in 0..self.gicd.nirqs {
if irq > 31 {
let ext_offset = GICD_ITARGETSR + (4 * (irq / 4));
let int_offset = irq % 4;
let mut val = self.gicd.read(ext_offset);
val |= 0b0000_0001 << (8 * int_offset);
self.gicd.write(ext_offset, val);
}
let ext_offset = GICD_IPRIORITY + (4 * (irq / 4));
let int_offset = irq % 4;
let mut val = self.gicd.read(ext_offset);
val |= 0b0000_0000 << (8 * int_offset);
self.gicd.write(ext_offset, val);
}
// Enable CPU0's GIC interface
self.gicc.write(GICC_CTLR, 1);
// Set CPU0's Interrupt Priority Mask
self.gicc.write(GICC_PMR, 0xff);
// Enable IRQ distribution
self.gicd.write(GICD_CTLR, 0x1);
}
}
pub fn irq_enable(&self, irq: u32) {
unsafe {
let offset = GICD_ISENABLER + (4 * (irq / 32));
self.gicd.write(offset, 1 << (irq % 32));
}
}
pub fn irq_disable(&self, irq: u32) {
unsafe {
let offset = GICD_ICENABLER + (4 * (irq / 32));
self.gicd.write(offset, 1 << (irq % 32));
}
}
pub fn irq_eoi(&self, irq: u32) {
unsafe {
self.gicc.write(GICC_EOIR, irq);
}
}
pub fn pending_irq(&self) -> usize {
let iar = unsafe { self.gicc.read(GICC_IAR) as usize };
if iar >= 0x3fe {
usize::MAX
} else {
iar
}
}
}
impl Scheme for IntController {
fn name(&self) -> &str {
"ARM Generic Interrupt Controller"
}
fn handle_irq(&self, irq_num: usize) {
if irq_num != usize::MAX {
self.manager.lock().handle(irq_num).ok();
}
self.irq_eoi(irq_num as u32);
}
}
impl IrqScheme for IntController {
fn is_valid_irq(&self, irq_num: usize) -> bool {
irq_num != usize::MAX
}
fn mask(&self, irq_num: usize) -> DeviceResult {
self.irq_disable(irq_num as u32);
Ok(())
}
fn unmask(&self, irq_num: usize) -> DeviceResult {
self.irq_enable(irq_num as u32);
Ok(())
}
fn register_handler(&self, irq_num: usize, handler: IrqHandler) -> DeviceResult {
self.manager
.lock()
.register_handler(irq_num, handler)
.map_err(|irq_num| {
trace!("Unknown irq_num: {:?}", irq_num);
})
.ok();
Ok(())
}
fn unregister(&self, _irq_num: usize) -> DeviceResult {
todo!()
}
}
impl GicDistIf {
unsafe fn read(&self, reg: u32) -> u32 {
core::ptr::read_volatile((self.address + reg as usize) as *const u32)
}
unsafe fn write(&self, reg: u32, value: u32) {
core::ptr::write_volatile((self.address + reg as usize) as *mut u32, value);
}
}
impl GicCpuIf {
unsafe fn read(&self, reg: u32) -> u32 {
core::ptr::read_volatile((self.address + reg as usize) as *const u32)
}
unsafe fn write(&self, reg: u32, value: u32) {
core::ptr::write_volatile((self.address + reg as usize) as *mut u32, value);
}
}
pub fn init(gicc_base: usize, gicd_base: usize) -> IntController {
let mut controller = IntController::new(gicc_base, gicd_base);
controller.init();
controller
}
pub fn get_irq_num(gicc_base: usize, gicd_base: usize) -> usize {
IntController::new(gicc_base, gicd_base).pending_irq()
}

View File

@ -18,7 +18,5 @@ cfg_if::cfg_if! {
pub mod x86 {
pub use super::x86_apic::Apic;
}
} else if #[cfg(target_arch = "aarch64")] {
pub mod gic_400;
}
}

View File

@ -1,25 +1,19 @@
use core::arch::asm;
use core::ops::Range;
use lock::Mutex;
use crate::io::{Io, Mmio};
use crate::prelude::IrqHandler;
use crate::scheme::{IrqScheme, Scheme};
use crate::{utils::IrqManager, DeviceError, DeviceResult};
use cfg_if::cfg_if;
use lock::Mutex;
const IRQ_RANGE: Range<usize> = 1..1024;
const PLIC_PRIORITY_BASE: usize = 0x0;
cfg_if! {
if #[cfg(feature = "fu740")] {
const PLIC_ENABLE_BASE: usize = 0x2000;
const PLIC_CONTEXT_BASE: usize = 0x20_0000;
} else {
const PLIC_ENABLE_BASE: usize = 0x2080;
const PLIC_CONTEXT_BASE: usize = 0x20_1000;
}
}
const PLIC_ENABLE_BASE: usize = 0x2080;
const PLIC_CONTEXT_BASE: usize = 0x20_1000;
const PLIC_CONTEXT_THRESHOLD: usize = 0x0;
const PLIC_CONTEXT_CLAIM: usize = 0x4 / core::mem::size_of::<u32>();
@ -93,7 +87,7 @@ impl PlicUnlocked {
}
fn init_hart(&mut self) {
self.set_threshold(1);
self.set_threshold(0);
}
}
@ -122,7 +116,6 @@ impl Scheme for Plic {
while let Some(irq_num) = inner.pending_irq() {
if inner.manager.handle(irq_num).is_err() {
warn!("no registered handler for IRQ {}!", irq_num);
inner.set_priority(irq_num, 0);
}
trace!("riscv plic handle irq: {}", irq_num);
inner.eoi(irq_num);

View File

@ -1,7 +1,6 @@
//! Device drivers of zCore.
#![cfg_attr(not(feature = "mock"), no_std)]
#![deny(warnings)]
#![feature(doc_cfg)]
extern crate alloc;
@ -27,7 +26,6 @@ pub mod input;
pub mod io;
pub mod irq;
pub mod net;
pub mod nvme;
pub mod prelude;
pub mod scheme;
pub mod uart;

View File

@ -1,5 +1,5 @@
//! Intel PRO/1000 Network Adapter i.e. e1000 network driver
//! Datasheet: <https://www.intel.ca/content/dam/doc/datasheet/82574l-gbe-controller-datasheet.pdf>
//! Datasheet: https://www.intel.ca/content/dam/doc/datasheet/82574l-gbe-controller-datasheet.pdf
use alloc::collections::BTreeMap;
use alloc::string::String;
@ -12,7 +12,8 @@ use smoltcp::time::Instant;
use smoltcp::wire::*;
use smoltcp::Result;
use super::{timer_now_as_micros, ProviderImpl};
use super::ProviderImpl;
use super::PAGE_SIZE;
use crate::net::get_sockets;
use crate::scheme::{NetScheme, Scheme};
use crate::{DeviceError, DeviceResult};
@ -45,7 +46,9 @@ impl Scheme for E1000Interface {
let data = self.driver.0.lock().handle_interrupt();
if data {
let timestamp = Instant::from_micros(timer_now_as_micros() as i64);
//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) {
@ -76,13 +79,14 @@ impl NetScheme for E1000Interface {
}
fn poll(&self) -> DeviceResult {
let timestamp = Instant::from_micros(timer_now_as_micros() as i64);
//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();
trace!("e1000 NetScheme poll: {:?}", p);
info!("e1000 NetScheme poll: {:?}", p);
Ok(())
}
Err(err) => {
@ -123,7 +127,7 @@ impl phy::Device<'_> for E1000Driver {
self.0
.lock()
.receive()
.map(|vec_recv| (E1000RxToken(vec_recv), E1000TxToken(self.clone())))
.map(|vec| (E1000RxToken(vec), E1000TxToken(self.clone())))
}
fn transmit(&mut self) -> Option<Self::TxToken> {
@ -156,11 +160,11 @@ impl phy::TxToken for E1000TxToken {
where
F: FnOnce(&mut [u8]) -> Result<R>,
{
let mut buffer = [0u8; 1536];
let mut buffer = [0u8; PAGE_SIZE];
let result = f(&mut buffer[..len]);
let mut driver = (self.0).0.lock();
driver.send(&buffer[..len]);
driver.send(&buffer);
result
}
@ -189,8 +193,8 @@ pub fn init(
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 neighbor_cache = NeighborCache::new(BTreeMap::new());
let iface = InterfaceBuilder::new(net_driver.clone())
.ethernet_addr(ethernet_addr)
.neighbor_cache(neighbor_cache)

View File

@ -49,14 +49,12 @@ impl NetScheme for LoopbackInterface {
}
fn get_mac(&self) -> EthernetAddress {
self.iface.lock().ethernet_addr()
unimplemented!()
}
fn get_ifname(&self) -> String {
self.name.clone()
unimplemented!()
}
fn get_ip_address(&self) -> Vec<IpCidr> {
Vec::from(self.iface.lock().ip_addrs())
unimplemented!()
}
}

View File

@ -1,15 +1,6 @@
//! LAN driver, only for Realtek currently.
#![allow(unused)]
use alloc::{sync::Arc, vec};
use lock::Mutex;
use smoltcp::socket::SocketSet;
pub mod e1000;
pub mod loopback;
pub use isomorphic_drivers::provider::Provider;
pub use loopback::LoopbackInterface;
cfg_if::cfg_if! {
if #[cfg(target_arch = "riscv64")] {
mod realtek;
@ -34,6 +25,7 @@ pub trait Provider {
fn dealloc_dma(vaddr: usize, size: usize);
}
*/
pub use isomorphic_drivers::provider::Provider;
pub struct ProviderImpl;
@ -60,16 +52,11 @@ pub fn virt_to_phys(vaddr: VirtAddr) -> PhysAddr {
unsafe { drivers_virt_to_phys(vaddr) }
}
pub fn timer_now_as_micros() -> u64 {
unsafe { drivers_timer_now_as_micros() }
}
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;
fn drivers_timer_now_as_micros() -> u64;
}
pub const PAGE_SIZE: usize = 4096;
@ -77,12 +64,20 @@ pub const PAGE_SIZE: usize = 4096;
type VirtAddr = usize;
type PhysAddr = usize;
pub mod loopback;
pub use loopback::LoopbackInterface;
use alloc::sync::Arc;
use alloc::vec;
use lock::Mutex;
use smoltcp::socket::SocketSet;
lazy_static::lazy_static! {
pub static ref SOCKETS: Arc<Mutex<SocketSet<'static>>> =
Arc::new(Mutex::new(SocketSet::new(vec![])));
}
// 注意!这个容易出现死锁
pub fn get_sockets() -> Arc<Mutex<SocketSet<'static>>> {
SOCKETS.clone()
}

View File

@ -97,8 +97,8 @@ pub const LPA_RFAULT: u32 = 0x2000;
pub const LPA_LPACK: u32 = 0x4000;
pub const LPA_NPAGE: u32 = 0x8000;
pub const LPA_DUPLEX: u32 = LPA_10FULL | LPA_100FULL;
pub const LPA_100: u32 = LPA_100FULL | LPA_100HALF | LPA_100BASE4;
pub const LPA_DUPLEX: u32 = (LPA_10FULL | LPA_100FULL);
pub const LPA_100: u32 = (LPA_100FULL | LPA_100HALF | LPA_100BASE4);
/* 1000BASE-T Control register */
pub const ADVERTISE_1000FULL: u32 = 0x0200;

View File

@ -1,4 +1,8 @@
use super::{phys_to_virt, virt_to_phys, Provider};
#![allow(unused)]
#![allow(non_camel_case_types)]
use super::Provider;
use super::{phys_to_virt, virt_to_phys};
#[macro_use]
mod log {

View File

@ -1,5 +1,7 @@
// Supports Realtek RTL8211F on Allwinner D1
extern crate alloc;
use super::mii::*;
use super::utils::*;
@ -8,7 +10,9 @@ use core::mem::size_of;
use super::Provider;
use super::{phys_to_virt, virt_to_phys};
use alloc::boxed::Box;
use alloc::slice;
use alloc::string::String;
use alloc::sync::Arc;
use alloc::vec::Vec;
@ -131,7 +135,7 @@ const AUTONEG_ENABLE: usize = 1;
const FLOW_OFF: u32 = 0;
const FLOW_RX: u32 = 1;
const FLOW_TX: u32 = 2;
const FLOW_AUTO: u32 = FLOW_TX | FLOW_RX;
const FLOW_AUTO: u32 = (FLOW_TX | FLOW_RX);
const HASH_TABLE_SIZE: u32 = 64;
const PAUSE_TIME: u32 = 0x200;
const GMAC_MAX_UNICAST_ADDRESSES: u32 = 8;
@ -155,7 +159,7 @@ const BMCR_PDOWN: u32 = 0x0800;
#[derive(Debug, Copy, Clone)]
#[repr(packed)]
pub struct DmaDesc {
pub struct dma_desc {
// size: 16
desc0: u32, // Status
desc1: u32, // Buffer Size
@ -163,18 +167,18 @@ pub struct DmaDesc {
desc3: u32, // Next Desc
}
pub enum RxFrameStatus {
pub enum rx_frame_status {
/* IPC status */
GoodFrame = 0,
DiscardFrame = 1,
CsumNone = 2,
LlcSnap = 4,
good_frame = 0,
discard_frame = 1,
csum_none = 2,
llc_snap = 4,
}
pub enum TxDmaIrqStatus {
TxHardError = 1,
TxHardErrorBumpTc = 2,
HandleTxRx = 3,
pub enum tx_dma_irq_status {
tx_hard_error = 1,
tx_hard_error_bump_tc = 2,
handle_tx_rx = 3,
}
pub struct RTL8211F<P: Provider> {
@ -186,10 +190,10 @@ pub struct RTL8211F<P: Provider> {
mac: [u8; 6],
recv_buffers: Vec<usize>,
recv_ring: &'static mut [DmaDesc],
recv_ring: &'static mut [dma_desc],
send_buffers: Vec<usize>,
send_ring: &'static mut [DmaDesc],
send_ring: &'static mut [dma_desc],
phy_mode: usize,
@ -211,7 +215,7 @@ where
P: Provider,
{
pub fn new(mac_addr: &[u8; 6]) -> Self {
assert_eq!(size_of::<DmaDesc>(), 16);
assert_eq!(size_of::<dma_desc>(), 16);
let mut mac: [u8; 6] = [0; 6];
let v_addr = mac_addr[0] as u32
@ -245,25 +249,25 @@ where
let (recv_ring_va, recv_ring_pa) = P::alloc_dma(P::PAGE_SIZE);
let send_ring = unsafe {
slice::from_raw_parts_mut(
send_ring_va as *mut DmaDesc,
P::PAGE_SIZE / size_of::<DmaDesc>(), // 4096/16 = 256 个 dma_desc
send_ring_va as *mut dma_desc,
P::PAGE_SIZE / size_of::<dma_desc>(), // 4096/16 = 256 个 dma_desc
)
};
let recv_ring = unsafe {
slice::from_raw_parts_mut(
recv_ring_va as *mut DmaDesc,
P::PAGE_SIZE / size_of::<DmaDesc>(),
recv_ring_va as *mut dma_desc,
P::PAGE_SIZE / size_of::<dma_desc>(),
)
};
send_ring.fill(DmaDesc {
send_ring.fill(dma_desc {
desc0: 0,
desc1: 0,
desc2: 0,
desc3: 0,
});
recv_ring.fill(DmaDesc {
recv_ring.fill(dma_desc {
desc0: 0,
desc1: 0,
desc2: 0,
@ -279,15 +283,15 @@ where
let (buffer_page_va, buffer_page_pa) = P::alloc_dma(P::PAGE_SIZE); // 其实buffer申请2K左右就可以
// desc1.all |= (1 << 24) Chain mode
send_ring[i].desc1 |= 1 << 24;
send_ring[i].desc1 |= (1 << 24);
send_ring[i].desc2 = buffer_page_pa as u32;
if (i + 1) == send_ring.len() {
send_ring[i].desc3 = virt_to_phys(&send_ring[0] as *const DmaDesc as usize) as u32;
send_ring[i].desc3 = virt_to_phys(&send_ring[0] as *const dma_desc as usize) as u32;
} else {
send_ring[i].desc3 =
virt_to_phys(&send_ring[i + 1] as *const DmaDesc as usize) as u32;
virt_to_phys(&send_ring[i + 1] as *const dma_desc as usize) as u32;
}
send_buffers.push(buffer_page_va);
@ -298,21 +302,21 @@ where
for i in 0..recv_ring.len() {
let (buffer_page_va, buffer_page_pa) = P::alloc_dma(P::PAGE_SIZE);
recv_ring[i].desc1 |= 1 << 24;
recv_ring[i].desc1 |= (1 << 24);
//recv_ring[i].desc2 = buffer_page_pa as u32;
if (i + 1) == recv_ring.len() {
recv_ring[i].desc3 = virt_to_phys(&recv_ring[0] as *const DmaDesc as usize) as u32;
recv_ring[i].desc3 = virt_to_phys(&recv_ring[0] as *const dma_desc as usize) as u32;
} else {
recv_ring[i].desc3 =
virt_to_phys(&recv_ring[i + 1] as *const DmaDesc as usize) as u32;
virt_to_phys(&recv_ring[i + 1] as *const dma_desc as usize) as u32;
}
recv_buffers.push(buffer_page_va);
// geth_rx_refill, 实际运行refill时却是priv->rx_clean: 0 ~ 254 ?
// desc_buf_set(&mut recv_ring[i], buffer_page_pa as u32, MAX_BUF_SZ);
recv_ring[i].desc1 &= !((1 << 11) - 1);
recv_ring[i].desc1 |= MAX_BUF_SZ & ((1 << 11) - 1);
recv_ring[i].desc1 &= (!((1 << 11) - 1));
recv_ring[i].desc1 |= (MAX_BUF_SZ & ((1 << 11) - 1));
recv_ring[i].desc2 = buffer_page_pa as u32;
// sync memery, fence指令
@ -388,10 +392,10 @@ where
}
let mii_bmcr_value = self.mdio_read(phyaddr, MII_BMCR);
self.mdio_write(phyaddr, MII_BMCR, mii_bmcr_value & !BMCR_PDOWN);
self.mdio_write(phyaddr, MII_BMCR, (mii_bmcr_value & !BMCR_PDOWN));
info!("Read MII_BMCR: {:#x}", mii_bmcr_value);
self.mac_reset().unwrap();
self.mac_reset();
self.mac_init(1, 1);
@ -404,18 +408,18 @@ where
self.rx_refill();
flush_cache(
virt_to_phys(&self.recv_ring[0] as *const DmaDesc as usize) as u64,
(size_of::<DmaDesc>() * self.recv_ring.len()) as u64,
virt_to_phys(&self.recv_ring[0] as *const dma_desc as usize) as u64,
(size_of::<dma_desc>() * self.recv_ring.len()) as u64,
);
flush_cache(
virt_to_phys(&self.send_ring[0] as *const DmaDesc as usize) as u64,
(size_of::<DmaDesc>() * self.send_ring.len()) as u64,
virt_to_phys(&self.send_ring[0] as *const dma_desc as usize) as u64,
(size_of::<dma_desc>() * self.send_ring.len()) as u64,
);
// phy_start
// 注意地址32位对齐
self.start_rx(virt_to_phys(&self.recv_ring[0] as *const DmaDesc as usize) as u32);
self.start_tx(virt_to_phys(&self.send_ring[0] as *const DmaDesc as usize) as u32);
self.start_rx(virt_to_phys(&self.recv_ring[0] as *const dma_desc as usize) as u32);
self.start_tx(virt_to_phys(&self.send_ring[0] as *const dma_desc as usize) as u32);
// Enable the Rx/Tx
self.mac_enable();
@ -506,7 +510,7 @@ where
/* Setup standard advertisement */
let adv = ADVERTISE_ALL;
let _ = self.phy_modify(
self.phy_modify(
MII_ADVERTISE,
ADVERTISE_ALL | ADVERTISE_100BASE4 | ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM,
adv,
@ -516,7 +520,7 @@ where
let bmcr = self.mdio_read(phyaddr, MII_BMSR);
if (bmcr & BMSR_ESTATEN) != 0 {
let adv = ADVERTISE_1000FULL;
let _ = self.phy_modify(MII_CTRL1000, ADVERTISE_1000FULL | ADVERTISE_1000HALF, adv);
self.phy_modify(MII_CTRL1000, ADVERTISE_1000FULL | ADVERTISE_1000HALF, adv);
}
self.phy_restart_aneg();
@ -597,7 +601,7 @@ where
//let ctl = BMCR_SPEED1000 | BMCR_FULLDPLX;
// 默认设成 100/FULL
let ctl = BMCR_SPEED100 | BMCR_FULLDPLX;
let _ = self.phy_modify(MII_BMCR, !(BMCR_LOOPBACK | BMCR_ISOLATE | BMCR_PDOWN), ctl);
self.phy_modify(MII_BMCR, !(BMCR_LOOPBACK | BMCR_ISOLATE | BMCR_PDOWN), ctl);
// 开始check网卡link状态, 然后设置speed/duplex
// genphy_read_status()
@ -626,7 +630,7 @@ where
let status = self.mdio_read(phyaddr, MII_BMSR);
link = status & BMSR_LSTATUS;
if link == BMSR_LSTATUS {
if (link == BMSR_LSTATUS) {
info!("Link is up! status: {:#x}", status);
break;
}
@ -649,8 +653,8 @@ where
pub fn can_recv(&mut self) -> bool {
let desc = &self.recv_ring[self.rx_dirty];
invalidate_dcache(
virt_to_phys(desc as *const DmaDesc as usize) as u64,
size_of::<DmaDesc>() as u64,
virt_to_phys(desc as *const dma_desc as usize) as u64,
size_of::<dma_desc>() as u64,
);
desc_get_own(desc) == 0
}
@ -668,8 +672,8 @@ where
let mut desc = &mut self.recv_ring[entry];
invalidate_dcache(
virt_to_phys(desc as *const DmaDesc as usize) as u64,
size_of::<DmaDesc>() as u64,
virt_to_phys(desc as *const dma_desc as usize) as u64,
size_of::<dma_desc>() as u64,
);
if desc_get_own(desc) != 0 {
@ -685,9 +689,9 @@ where
//discard frame when last_desc, err_sum, len_err, mii_err
let status = if (((desc.desc0 >> 8) & 0x1) == 0) || ((desc.desc0 & 0x9008) != 0) {
RxFrameStatus::DiscardFrame as i32
rx_frame_status::discard_frame as i32
} else {
RxFrameStatus::GoodFrame as i32
rx_frame_status::good_frame as i32
};
info!("RX frame size {}, status: {:?}", frame_len, status);
@ -709,7 +713,7 @@ where
info!("========== RX PKT DATA: <<<<<<<<<<");
print_hex_dump(skb, 64);
if status == RxFrameStatus::DiscardFrame as i32 {
if status == rx_frame_status::discard_frame as i32 {
debug!("Get error packet");
// Just need to clear 64 bits header
@ -721,7 +725,7 @@ where
continue;
}
if status != RxFrameStatus::LlcSnap as i32 {
if status != rx_frame_status::llc_snap as i32 {
frame_len -= 4; // ETH_FCS_LEN, 帧出错检验
}
@ -790,7 +794,7 @@ where
pub fn can_send(&mut self) -> bool {
let avail_tx = if self.tx_clean >= (self.tx_dirty + 1) {
self.tx_clean - (self.tx_dirty + 1)
(self.tx_clean - (self.tx_dirty + 1))
} else {
DMA_DESC_TX - ((self.tx_dirty + 1) - self.tx_clean)
};
@ -803,8 +807,8 @@ where
let desc = &self.send_ring[self.tx_dirty];
invalidate_dcache(
virt_to_phys(desc as *const DmaDesc as usize) as u64,
size_of::<DmaDesc>() as u64,
virt_to_phys(desc as *const dma_desc as usize) as u64,
size_of::<dma_desc>() as u64,
);
if desc_get_own(desc) != 0 {
return false;
@ -860,7 +864,7 @@ where
/* Don't set the first's own bit, here */
// (first != desc)
if first != entry {
if (first != entry) {
//self.send_buffers[entry] = 0;
desc_set_own(desc);
}
@ -880,8 +884,8 @@ where
// 再判断下环形缓冲区的空间
flush_cache(
virt_to_phys(&self.send_ring[desc_count] as *const DmaDesc as usize) as u64,
size_of::<DmaDesc>() as u64,
virt_to_phys(&self.send_ring[desc_count] as *const dma_desc as usize) as u64,
size_of::<dma_desc>() as u64,
);
flush_cache(
virt_to_phys(self.send_buffers[desc_count] as usize) as u64,
@ -916,7 +920,7 @@ where
pub fn rx_refill(&mut self) {
while if self.rx_dirty >= (self.rx_clean + 1) {
self.rx_dirty - (self.rx_clean + 1)
(self.rx_dirty - (self.rx_clean + 1))
} else {
DMA_DESC_RX - ((self.rx_clean + 1) - self.rx_dirty)
// (self.rx_dirty - (self.rx_clean + 1)) & (DMA_DESC_RX - 1)
@ -944,8 +948,8 @@ where
desc_buf_set(desc, paddr, MAX_BUF_SZ);
desc_set_own(desc);
flush_cache(
virt_to_phys(&self.recv_ring[entry] as *const DmaDesc as usize) as u64,
size_of::<DmaDesc>() as u64,
virt_to_phys(&self.recv_ring[entry] as *const dma_desc as usize) as u64,
size_of::<dma_desc>() as u64,
);
// sync memery
@ -962,7 +966,7 @@ where
let mut tx_errors: u64 = 0;
while if self.tx_dirty >= self.tx_clean {
self.tx_dirty - self.tx_clean
(self.tx_dirty - self.tx_clean)
} else {
DMA_DESC_TX - (self.tx_clean - self.tx_dirty)
//(self.tx_dirty - self.tx_clean) & (DMA_DESC_TX - 1)
@ -977,8 +981,8 @@ where
let mut desc = &mut self.send_ring[entry];
invalidate_dcache(
virt_to_phys(desc as *const DmaDesc as usize) as u64,
size_of::<DmaDesc>() as u64,
virt_to_phys(desc as *const dma_desc as usize) as u64,
size_of::<dma_desc>() as u64,
);
if desc_get_own(desc) != 0 {
warn!("tx_complete get desc own failed !");
@ -1017,7 +1021,7 @@ where
// Enable and Restart Autonegotiation
pub fn phy_restart_aneg(&mut self) {
// Don't isolate the PHY if we're negotiating
let _ = self.phy_modify(MII_BMCR, BMCR_ISOLATE, BMCR_ANENABLE | BMCR_ANRESTART);
self.phy_modify(MII_BMCR, BMCR_ISOLATE, BMCR_ANENABLE | BMCR_ANRESTART);
info!("Enable and Restart Autonegotiation ...");
// NOLINK --> autoneg_complete --> set speed and duplex --> LINK
@ -1085,10 +1089,10 @@ where
if self.phy_mode == RGMII {
clk_value |= 0x00000004; // set RGMII
} else {
clk_value &= !0x00000004;
clk_value &= (!0x00000004);
}
clk_value &= !0x00002003; // clear RMII_EN, ETCS
clk_value &= (!0x00002003); // clear RMII_EN, ETCS
if (self.phy_mode == RGMII) || (self.phy_mode == GMII) {
clk_value |= 0x00000002; // set ETCS=2
@ -1100,9 +1104,9 @@ where
// Adjust Tx/Rx clock delay
clk_value &= !(0x07 << 10);
clk_value |= (self.tx_delay & 0x07) << 10;
clk_value |= ((self.tx_delay & 0x07) << 10);
clk_value &= !(0x1F << 5);
clk_value |= (self.rx_delay & 0x1F) << 5;
clk_value |= ((self.rx_delay & 0x1F) << 5);
info!("clk enable, write clk value: {:#x}", clk_value);
write_volatile((self.base_phy + EMAC_EPHY_CLK_REG0) as *mut u32, clk_value);
@ -1114,7 +1118,7 @@ where
value &= !(1 << 16); // assert reset
write_volatile((self.base_ccu + EMAC_BGR_REG) as *mut u32, value);
value |= 1 << 16; // deassert reset
value |= (1 << 16); // deassert reset
value |= 1; // enable bus clock
write_volatile((self.base_ccu + EMAC_BGR_REG) as *mut u32, value);
}
@ -1131,16 +1135,16 @@ where
let mut status = 0;
// 不正常的中断
if (intr_status & TX_UNF_INT) != 0 {
status = TxDmaIrqStatus::TxHardErrorBumpTc as i32;
status = tx_dma_irq_status::tx_hard_error_bump_tc as i32;
}
if (intr_status & TX_STOP_INT) != 0 {
status = TxDmaIrqStatus::TxHardError as i32;
status = tx_dma_irq_status::tx_hard_error as i32;
}
/* 正常的 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 = TxDmaIrqStatus::HandleTxRx as i32;
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);
@ -1152,7 +1156,7 @@ where
let status = self.interrupt_status();
// 处理
if status == TxDmaIrqStatus::HandleTxRx as i32 {
if status == tx_dma_irq_status::handle_tx_rx as i32 {
self.int_disable();
// geth_poll()
@ -1162,7 +1166,7 @@ where
if work_done < BUDGET as i32 {
self.int_enable();
}
} else if status == TxDmaIrqStatus::TxHardError as i32 {
} else if status == tx_dma_irq_status::tx_hard_error as i32 {
error!("gmac interrupt handle tx error !");
} else {
info!("gmac interrupt handle status: {}, Do nothing ...", status);
@ -1183,7 +1187,7 @@ where
pub fn desc_tx_close(&mut self, first: usize, end: usize, csum_insert: usize) {
let mut count = first;
let mut desc = (&mut self.send_ring[first]) as *mut DmaDesc;
let mut desc = (&mut self.send_ring[first]) as *mut dma_desc;
//let mut desc = first as *mut dma_desc;
self.send_ring[first].desc1 |= 1 << 29; //First Segment,
@ -1215,8 +1219,8 @@ where
}
pub fn dma_init(&mut self) {
write_volatile((self.base + GETH_BASIC_CTL1) as *mut u32, 8 << 24); // burst
// 打开网卡中断
write_volatile((self.base + GETH_BASIC_CTL1) as *mut u32, (8 << 24)); // burst
// 打开网卡中断
self.int_enable();
}
@ -1245,20 +1249,20 @@ where
/* Initialize the core component */
let mut value: u32 = read_volatile((self.base + GETH_TX_CTL0) as *mut u32);
value |= 1 << 30; /* Jabber Disable */
value |= (1 << 30); /* Jabber Disable */
write_volatile((self.base + GETH_TX_CTL0) as *mut u32, value);
info!("mac init, write TX_CTL0 {:#x}", value);
let mut value: u32 = read_volatile((self.base + GETH_RX_CTL0) as *mut u32);
value &= !(1 << 27); /* Disable CRC & IPv4 Header Checksum */
value &= !(1 << 28); /* Keep Pad/CRC */
value |= 1 << 29; /* Jumbo Frame Enable */
value |= (1 << 27); /* Enable CRC & IPv4 Header Checksum */
value |= (1 << 28); /* Automatic Pad/CRC Stripping */
value |= (1 << 29); /* Jumbo Frame Enable */
write_volatile((self.base + GETH_RX_CTL0) as *mut u32, value);
info!("mac init, write RX_CTL0 {:#x}", value);
write_volatile(
(self.base + GETH_MDIO_ADDR) as *mut u32,
MDC_CLOCK_RATIO << 20,
(MDC_CLOCK_RATIO << 20),
); /* MDC_DIV_RATIO */
/* Set the Rx&Tx mode */
@ -1302,18 +1306,18 @@ where
}
}
/* Forward frames with error and undersized good frame. */
value |= RX_ERR_FRM | RX_RUNT_FRM;
value |= (RX_ERR_FRM | RX_RUNT_FRM);
write_volatile((self.base + GETH_RX_CTL1) as *mut u32, value);
info!("mac init, write RX_CTL1 {:#x}", value);
}
pub fn mac_enable(&mut self) {
let mut value: u32 = read_volatile((self.base + GETH_TX_CTL0) as *mut u32);
value |= 1 << 31;
value |= (1 << 31);
write_volatile((self.base + GETH_TX_CTL0) as *mut u32, value);
let mut value: u32 = read_volatile((self.base + GETH_RX_CTL0) as *mut u32);
value |= 1 << 31;
value |= (1 << 31);
write_volatile((self.base + GETH_RX_CTL0) as *mut u32, value);
}
@ -1429,7 +1433,7 @@ where
1000 => ctrl &= !0x0C,
_ => {
ctrl |= 0x08;
if speed == 100 {
if (speed == 100) {
ctrl |= 0x04;
} else {
ctrl &= !0x04;
@ -1477,7 +1481,7 @@ where
if duplex != 0 {
flow = read_volatile((self.base + GETH_TX_FLOW_CTL) as *mut u32);
flow |= pause << 4;
flow |= (pause << 4);
write_volatile((self.base + GETH_TX_FLOW_CTL) as *mut u32, flow);
}
}
@ -1485,9 +1489,9 @@ where
pub fn mdio_read(&mut self, phyaddr: u32, phyreg: u32) -> u32 {
let mut value: u32 = 0;
value |= (MDC_CLOCK_RATIO & 0x07) << 20;
value |= ((MDC_CLOCK_RATIO & 0x07) << 20);
value |= ((phyaddr << 12) & (0x0001F000)) | ((phyreg << 4) & (0x000007F0)) | MII_BUSY;
value |= (((phyaddr << 12) & (0x0001F000)) | ((phyreg << 4) & (0x000007F0)) | MII_BUSY);
while (read_volatile((self.base + GETH_MDIO_ADDR) as *mut u32) & MII_BUSY) == 1 {}
@ -1503,8 +1507,9 @@ where
}
pub fn mdio_write(&mut self, phyaddr: u32, phyreg: u32, data: u32) {
let mut value: u32 = (0x07 << 20) & read_volatile((self.base + GETH_MDIO_ADDR) as *mut u32)
| (MDC_CLOCK_RATIO << 20);
let mut value: u32 = ((0x07 << 20)
& read_volatile((self.base + GETH_MDIO_ADDR) as *mut u32)
| (MDC_CLOCK_RATIO << 20));
value |= (((phyaddr << 12) & (0x0001F000)) | ((phyreg << 4) & (0x000007F0)))
| MII_WRITE
@ -1519,31 +1524,31 @@ where
}
pub fn mdio_reset(&mut self) {
write_volatile((self.base + GETH_MDIO_ADDR) as *mut u32, 4 << 2);
write_volatile((self.base + GETH_MDIO_ADDR) as *mut u32, (4 << 2));
}
}
pub fn desc_set_own(desc: &mut DmaDesc) {
pub fn desc_set_own(desc: &mut dma_desc) {
desc.desc0 |= 0x80000000;
}
pub fn desc_get_own(desc: &DmaDesc) -> u32 {
pub fn desc_get_own(desc: &dma_desc) -> u32 {
desc.desc0 & 0x80000000
}
pub fn desc_get_tx_ls(desc: &DmaDesc) -> u32 {
pub fn desc_get_tx_ls(desc: &dma_desc) -> u32 {
desc.desc1 & 0x40000000 // Last Segment
}
pub fn desc_buf_set(desc: &mut DmaDesc, paddr: u32, size: u32) {
desc.desc1 &= !((1 << 11) - 1);
desc.desc1 |= size & ((1 << 11) - 1);
pub fn desc_buf_set(desc: &mut dma_desc, paddr: u32, size: u32) {
desc.desc1 &= (!((1 << 11) - 1));
desc.desc1 |= (size & ((1 << 11) - 1));
desc.desc2 = paddr;
}
pub fn desc_init(desc: &mut DmaDesc) {
pub fn desc_init(desc: &mut dma_desc) {
desc.desc1 = 0;
desc.desc1 |= 1 << 24;
desc.desc1 |= (1 << 24);
// 这里用的Buffer Addr不发生改变
//desc.desc2 = 0;

View File

@ -86,7 +86,6 @@ pub fn usdelay(us: u64) {
}
// 毫秒(ms)
#[allow(unused)]
pub fn msdelay(ms: u64) {
usdelay(ms * 1000);
}

View File

@ -1,6 +1,7 @@
use alloc::collections::BTreeMap;
use alloc::string::String;
use alloc::sync::Arc;
// use alloc::vec;
use alloc::vec::Vec;
use lock::Mutex;
@ -11,8 +12,11 @@ use smoltcp::time::Instant;
use smoltcp::wire::*;
use smoltcp::Result;
use super::realtek::rtl8211f::{self, RTL8211F};
use super::{timer_now_as_micros, ProviderImpl, PAGE_SIZE};
use super::realtek::rtl8211f;
use super::realtek::rtl8211f::RTL8211F;
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};
@ -44,7 +48,7 @@ impl Scheme for RTLxInterface {
let handle_tx_rx = 3;
if status == handle_tx_rx {
let timestamp = Instant::from_micros(timer_now_as_micros() as i64);
let timestamp = Instant::from_millis(0);
let sockets = get_sockets();
let mut sockets = sockets.lock();
@ -77,7 +81,7 @@ impl NetScheme for RTLxInterface {
}
fn poll(&self) -> DeviceResult {
let timestamp = Instant::from_micros(timer_now_as_micros() 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) {

View File

@ -1,656 +0,0 @@
use alloc::string::String;
use alloc::vec;
use alloc::vec::Vec;
// use core::mem::size_of;
use alloc::sync::Arc;
use core::ptr::{read_volatile, write_volatile};
use crate::scheme::{BlockScheme, Scheme};
use crate::DeviceResult;
use lock::Mutex;
use super::nvme_queue::*;
pub struct NvmeInterface {
name: String,
admin_queue: Arc<Mutex<NvmeQueue<ProviderImpl>>>,
io_queues: Vec<Arc<Mutex<NvmeQueue<ProviderImpl>>>>,
bar: usize,
irq: usize,
}
impl NvmeInterface {
pub fn new(bar: usize, irq: usize) -> DeviceResult<NvmeInterface> {
let admin_queue = Arc::new(Mutex::new(NvmeQueue::new(0, 0)));
let io_queues = vec![Arc::new(Mutex::new(NvmeQueue::<ProviderImpl>::new(1, 0x8)))];
let mut interface = NvmeInterface {
name: String::from("nvme"),
admin_queue,
io_queues,
bar,
irq,
};
interface.init();
Ok(interface)
}
// config admin queue ,io queue
pub fn init(&mut self) {
self.nvme_configure_admin_queue();
self.nvme_alloc_io_queue();
}
pub fn get_name_irq(&self) -> (String, usize) {
(self.name.clone(), self.irq)
}
}
impl NvmeInterface {
pub fn nvme_configure_admin_queue(&mut self) {
let mut admin_queue = self.admin_queue.lock();
let bar = self.bar;
let dbs = bar + NVME_REG_DBS;
let sq_dma_pa = admin_queue.sq_pa as u32;
let cq_dma_pa = admin_queue.cq_pa as u32;
let data_dma_pa = admin_queue.data_pa as u64;
let aqa_low_16 = 31_u16;
let aqa_high_16 = 31_u16;
let aqa = (aqa_high_16 as u32) << 16 | aqa_low_16 as u32;
let aqa_address = bar + NVME_REG_AQA;
// 将admin queue配置信息写入nvme设备寄存器AQA (admin_queue_attributes)
unsafe {
write_volatile(aqa_address as *mut u32, aqa);
}
// 将admin queue的sq dma物理地址写入nvme设备上的寄存器ASQ
let asq_address = bar + NVME_REG_ASQ;
unsafe {
write_volatile(asq_address as *mut u32, sq_dma_pa);
}
// 将admin queue的cq dma物理地址写入nvme设备上的寄存器ACQ
let acq_address = bar + NVME_REG_ACQ;
unsafe {
write_volatile(acq_address as *mut u32, cq_dma_pa);
}
// enable ctrl
let mut ctrl_config = NVME_CC_ENABLE | NVME_CC_CSS_NVM;
ctrl_config |= 0 << NVME_CC_MPS_SHIFT;
ctrl_config |= NVME_CC_ARB_RR | NVME_CC_SHN_NONE;
ctrl_config |= NVME_CC_IOSQES | NVME_CC_IOCQES;
unsafe { write_volatile((bar + NVME_REG_CC) as *mut u32, ctrl_config) }
let _dev_status = unsafe { read_volatile((bar + NVME_REG_CSTS) as *mut u32) };
// warn!("nvme status {}", _dev_status);
// config identify
let mut cmd = NvmeIdentify::new();
cmd.prp1 = data_dma_pa;
cmd.command_id = 0x1018; //random number
cmd.nsid = 1;
let common_cmd = unsafe { core::mem::transmute(cmd) };
admin_queue.sq[0].write(common_cmd);
admin_queue.sq_tail += 1;
let admin_q_db = dbs + admin_queue.db_offset;
unsafe { write_volatile(admin_q_db as *mut u32, 1) }
loop {
let status = admin_queue.cq[0].read();
if status.status != 0 {
// warn!("nvme cq :{:#x?}", status);
unsafe { write_volatile((admin_q_db + 0x4) as *mut u32, 1) }
break;
}
}
}
pub fn nvme_alloc_io_queue(&mut self) {
let mut admin_queue = self.admin_queue.lock();
// let io_queue = self.io_queues[0].lock();
let bar = self.bar;
let dev_dbs = bar + NVME_REG_DBS;
let admin_q_db = dev_dbs;
// nvme_set_queue_count
let mut cmd = NvmeCommonCommand::new();
cmd.opcode = 0x09;
cmd.command_id = 0x2;
cmd.nsid = 1;
cmd.cdw10 = 0x7;
admin_queue.sq[1].write(cmd);
admin_queue.sq_tail += 1;
unsafe { write_volatile(admin_q_db as *mut u32, 2) }
loop {
let status = admin_queue.cq[1].read();
if status.status != 0 {
// warn!("nvme cq :{:#x?}", status);
unsafe { write_volatile((admin_q_db + 0x4) as *mut u32, 2) }
break;
}
}
//nvme create cq
let mut cmd = NvmeCreateCq::new();
cmd.opcode = 0x05;
cmd.command_id = 0x3;
cmd.nsid = 1;
cmd.prp1 = admin_queue.cq_pa as u64;
cmd.cqid = 1;
cmd.qsize = 1023;
cmd.cq_flags = NVME_QUEUE_PHYS_CONTIG | NVME_CQ_IRQ_ENABLED;
// let mut cmd = NvmeCommonCommand::new();
// cmd.opcode = 0x05;
// cmd.command_id = 0x3;
// cmd.nsid = 1;
// cmd.prp1 = admin_queue.cq_pa as u64;
// cmd.cdw10 = 0x3ff0001;
// cmd.cdw11 = 0x3;
let common_cmd = unsafe { core::mem::transmute(cmd) };
admin_queue.sq[2].write(common_cmd);
admin_queue.sq_tail += 1;
unsafe { write_volatile(admin_q_db as *mut u32, 3) }
loop {
let status = admin_queue.cq[2].read();
if status.status != 0 {
// warn!("nvme cq :{:#x?}", status);
unsafe { write_volatile((admin_q_db + 0x4) as *mut u32, 3) }
break;
}
}
// nvme create sq
let mut cmd = NvmeCreateSq::new();
cmd.opcode = 0x01;
cmd.command_id = 0x4;
cmd.nsid = 1;
cmd.prp1 = admin_queue.sq_pa as u64;
cmd.sqid = 1;
cmd.qsize = 1023;
cmd.sq_flags = 0x1;
cmd.cqid = 0x1;
// let mut cmd = NvmeCommonCommand::new();
// cmd.opcode = 0x01;
// cmd.command_id = 0x2018;
// cmd.nsid = 1;
// cmd.prp1 = admin_queue.sq_pa as u64;
// cmd.cdw10 = 0x3ff0001;
// cmd.cdw11 = 0x10001;
let common_cmd = unsafe { core::mem::transmute(cmd) };
// write command to sq
admin_queue.sq[3].write(common_cmd);
admin_queue.sq_tail += 1;
// write doorbell register
unsafe { write_volatile(admin_q_db as *mut u32, 4) }
// wait for command complete
loop {
let status = admin_queue.cq[3].read();
if status.status != 0 {
// warn!("nvme cq :{:#x?}", status);
// write doorbell register
unsafe { write_volatile((admin_q_db + 0x4) as *mut u32, 4) }
break;
}
}
}
}
impl BlockScheme for NvmeInterface {
// 每个NVMe命令中有两个域PRP1和PRP2Host就是通过这两个域告诉SSD数据在内存中的位置或者数据需要写入的地址
// 首先对prp1进行读写如果数据还没完就看数据量是不是在一个page内在的话只需要读写prp2内存地址就可以了数据量大于1个page就需要读出prp list
// 由于只读一块, 小于一页, 所以只需要prp1
// prp1 = dma_addr
// prp2 = 0
// prp设置
// uboot中对应实现 nvme_setup_prps
// linux中对应实现 nvme_pci_setup_prps
// SLBA = start logical block address
// length = 1 = 512B
// 1 SLBA = 512B
fn read_block(&self, block_id: usize, read_buf: &mut [u8]) -> DeviceResult {
let io_queue = self.io_queues[0].lock();
let db_offset = io_queue.db_offset;
let mut admin_queue = self.admin_queue.lock();
let bar = self.bar;
let dbs = bar + NVME_REG_DBS;
// let db_offset = io_queue.db_offset;
// 这里dma addr 就是buffer的地址
let ptr = read_buf.as_mut_ptr();
let addr = virt_to_phys(ptr as usize);
// build nvme read command
let mut cmd = NvmeRWCommand::new_read_command();
cmd.nsid = 1;
cmd.prp1 = addr as u64;
cmd.command_id = 101;
cmd.length = 1;
cmd.slba = block_id as u64;
//transfer to common command
let common_cmd = unsafe { core::mem::transmute(cmd) };
let tail = admin_queue.sq_tail;
// write command to sq
admin_queue.sq[tail].write(common_cmd);
admin_queue.sq_tail += 1;
// write doorbell register
unsafe { write_volatile((dbs + db_offset) as *mut u32, (tail + 1) as u32) }
// wait for command complete
loop {
let status = admin_queue.cq[tail].read();
if status.status != 0 {
// warn!("nvme cq :{:#x?}", status);
// write doorbell
unsafe { write_volatile((dbs + db_offset + 0x4) as *mut u32, (tail + 1) as u32) }
break;
}
}
// admin_queue.cq_head = admin_queue.sq_tail;
Ok(())
}
// prp1 = write_buf physical address
// prp2 = 0
// SLBA = start logical block address
// length = 1 = 512B
fn write_block(&self, block_id: usize, write_buf: &[u8]) -> DeviceResult {
// warn!("write block");
let io_queue = self.io_queues[0].lock();
let db_offset = io_queue.db_offset;
let mut admin_queue = self.admin_queue.lock();
let bar = self.bar;
let dbs = bar + NVME_REG_DBS;
let ptr = write_buf.as_ptr();
let addr = virt_to_phys(ptr as usize);
// build nvme write command
let mut cmd = NvmeRWCommand::new_write_command();
cmd.nsid = 1;
cmd.prp1 = addr as u64;
cmd.length = 1;
cmd.command_id = 100;
cmd.slba = block_id as u64;
// transmute to common command
let common_cmd = unsafe { core::mem::transmute(cmd) };
let mut tail = admin_queue.sq_tail;
if tail > 1023 {
tail = 0;
}
// push command to sq
admin_queue.sq[tail].write(common_cmd);
admin_queue.sq_tail += 1;
// write doorbell register
unsafe { write_volatile((dbs + db_offset) as *mut u32, (tail + 1) as u32) }
// wait for command complete
loop {
let status = admin_queue.cq[tail].read();
if status.status != 0 {
// warn!("nvme cq :{:#x?}", status);
// write doorbell
unsafe { write_volatile((dbs + db_offset + 0x4) as *mut u32, (tail + 1) as u32) }
break;
}
}
Ok(())
}
fn flush(&self) -> DeviceResult {
Ok(())
}
}
impl Scheme for NvmeInterface {
fn name(&self) -> &str {
"nvme"
}
fn handle_irq(&self, irq: usize) {
warn!("nvme device irq {}", irq);
}
}
#[repr(C)]
#[derive(Debug, Clone, Copy, Default)]
//64B
pub struct NvmeCommonCommand {
opcode: u8,
flags: u8,
command_id: u16,
nsid: u32,
cdw2: [u32; 2],
metadata: u64,
prp1: u64,
prp2: u64,
cdw10: u32,
cdw11: u32,
cdw12: u32,
cdw13: u32,
cdw14: u32,
cdw15: u32,
}
impl NvmeCommonCommand {
pub fn new() -> Self {
Self {
opcode: 0,
flags: 0,
command_id: 0,
nsid: 0,
cdw2: [0; 2],
metadata: 0,
prp1: 0,
prp2: 0,
cdw10: 0,
cdw11: 0,
cdw12: 0,
cdw13: 0,
cdw14: 0,
cdw15: 0,
}
}
}
#[repr(C)]
#[derive(Debug, Clone, Copy, Default)]
pub struct NvmeIdentify {
opcode: u8,
flags: u8,
command_id: u16,
nsid: u32,
rsvd2: [u64; 2],
prp1: u64,
prp2: u64,
cns: u8,
rsvd3: u8,
ctrlid: u16,
rsvd11: [u8; 3],
csi: u8,
rsvd12: [u32; 4],
}
impl NvmeIdentify {
pub fn new() -> Self {
Self {
opcode: 0x06,
flags: 0,
command_id: 0x1,
nsid: 1,
rsvd2: [0; 2],
prp1: 0,
prp2: 0,
cns: 1,
rsvd3: 0,
ctrlid: 0,
rsvd11: [0; 3],
csi: 0,
rsvd12: [0; 4],
}
}
}
#[repr(C)]
#[derive(Debug, Clone, Copy, Default)]
pub struct NvmeCreateCq {
pub opcode: u8,
pub flags: u8,
pub command_id: u16,
pub nsid: u32,
pub rsvd1: [u32; 4],
pub prp1: u64,
pub rsvd8: u64,
pub cqid: u16,
pub qsize: u16,
pub cq_flags: u16,
pub irq_vector: u16,
pub rsvd12: [u32; 4],
}
impl NvmeCreateCq {
fn new() -> Self {
Self {
opcode: 0x05,
flags: 0,
command_id: 0,
nsid: 0,
rsvd1: [0; 4],
prp1: 0,
rsvd8: 0,
cqid: 0,
qsize: 0,
cq_flags: 0,
irq_vector: 0,
rsvd12: [0; 4],
}
}
}
#[repr(C)]
#[derive(Debug, Clone, Copy, Default)]
pub struct NvmeCreateSq {
pub opcode: u8,
pub flags: u8,
pub command_id: u16,
pub nsid: u32,
pub rsvd1: [u32; 4],
pub prp1: u64,
pub rsvd8: u64,
pub sqid: u16,
pub qsize: u16,
pub sq_flags: u16,
pub cqid: u16,
pub rsvd12: [u32; 4],
}
impl NvmeCreateSq {
fn new() -> Self {
Self {
opcode: 0x01,
flags: 0,
command_id: 0,
nsid: 0,
rsvd1: [0; 4],
prp1: 0,
rsvd8: 0,
sqid: 0,
qsize: 0,
sq_flags: 0,
cqid: 0,
rsvd12: [0; 4],
}
}
}
#[repr(C)]
#[derive(Copy, Clone, Debug, Default)]
pub struct NvmeRWCommand {
pub opcode: u8,
pub flags: u8,
pub command_id: u16,
pub nsid: u32,
pub rsvd2: u64,
pub metadata: u64,
pub prp1: u64,
pub prp2: u64,
pub slba: u64,
pub length: u16,
pub control: u16,
pub dsmgmt: u32,
pub reftag: u32,
pub apptag: u16,
pub appmask: u16,
}
impl NvmeRWCommand {
pub fn new_write_command() -> Self {
Self {
opcode: 0x01,
flags: 0,
command_id: 0,
nsid: 0,
rsvd2: 0,
metadata: 0,
prp1: 0,
prp2: 0,
slba: 0,
length: 0,
control: 0,
dsmgmt: 0,
reftag: 0,
apptag: 0,
appmask: 0,
}
}
pub fn new_read_command() -> Self {
Self {
opcode: 0x02,
flags: 0,
command_id: 0,
nsid: 0,
rsvd2: 0,
metadata: 0,
prp1: 0,
prp2: 0,
slba: 0,
length: 0,
control: 0,
dsmgmt: 0,
reftag: 0,
apptag: 0,
appmask: 0,
}
}
}
#[repr(C)]
#[derive(Debug, Copy, Clone, Default)]
pub struct NvmeCompletion {
pub result: u64,
// pub rsvd: u32,
pub sq_head: u16,
pub sq_id: u16,
pub command_id: u16,
pub status: u16,
}
// NvmeRegister
pub const NVME_REG_CAP: usize = 0x0000; /* Controller Capabilities */
pub const NVME_REG_VS: usize = 0x0008; /* Version */
pub const NVME_REG_INTMS: usize = 0x000c; /* Interrupt Mask Set */
pub const NVME_REG_INTMC: usize = 0x0010; /* Interrupt Mask Clear */
pub const NVME_REG_CC: usize = 0x0014; /* Controller Configuration */
pub const NVME_REG_CSTS: usize = 0x001c; /* Controller Status */
pub const NVME_REG_NSSR: usize = 0x0020; /* NVM Subsystem Reset */
pub const NVME_REG_AQA: usize = 0x0024; /* Admin Queue Attributes */
pub const NVME_REG_ASQ: usize = 0x0028; /* Admin SQ Base Address */
pub const NVME_REG_ACQ: usize = 0x0030; /* Admin CQ Base Address */
pub const NVME_REG_CMBLOC: usize = 0x0038; /* Controller Memory Buffer Location */
pub const NVME_REG_CMBSZ: usize = 0x003c; /* Controller Memory Buffer Size */
pub const NVME_REG_BPINFO: usize = 0x0040; /* Boot Partition Information */
pub const NVME_REG_BPRSEL: usize = 0x0044; /* Boot Partition Read Select */
pub const NVME_REG_BPMBL: usize = 0x0048; /* Boot Partition Memory Buffer
* Location
*/
pub const NVME_REG_CMBMSC: usize = 0x0050; /* Controller Memory Buffer Memory
* Space Control
*/
pub const NVME_REG_CRTO: usize = 0x0068; /* Controller Ready Timeouts */
pub const NVME_REG_PMRCAP: usize = 0x0e00; /* Persistent Memory Capabilities */
pub const NVME_REG_PMRCTL: usize = 0x0e04; /* Persistent Memory Region Control */
pub const NVME_REG_PMRSTS: usize = 0x0e08; /* Persistent Memory Region Status */
pub const NVME_REG_PMREBS: usize = 0x0e0c; /* Persistent Memory Region Elasticity
* Buffer Size
*/
pub const NVME_REG_PMRSWTP: usize = 0x0e10; /* Persistent Memory Region Sustained
* Write Throughput
*/
pub const NVME_REG_DBS: usize = 0x1000; /* SQ 0 Tail Doorbell */
// NVME CONST
pub const NVME_CC_ENABLE: u32 = 1 << 0;
pub const NVME_CC_CSS_NVM: u32 = 0 << 4;
pub const NVME_CC_MPS_SHIFT: u32 = 7;
pub const NVME_CC_ARB_RR: u32 = 0 << 11;
pub const NVME_CC_ARB_WRRU: u32 = 1 << 11;
pub const NVME_CC_ARB_VS: u32 = 7 << 11;
pub const NVME_CC_SHN_NONE: u32 = 0 << 14;
pub const NVME_CC_SHN_NORMAL: u32 = 1 << 14;
pub const NVME_CC_SHN_ABRUPT: u32 = 2 << 14;
pub const NVME_CC_IOSQES: u32 = 6 << 16;
pub const NVME_CC_IOCQES: u32 = 4 << 20;
pub const NVME_CSTS_RDY: u32 = 1 << 0;
pub const NVME_CSTS_CFS: u32 = 1 << 1;
pub const NVME_CSTS_SHST_NORMAL: u32 = 0 << 2;
pub const NVME_CSTS_SHST_OCCUR: u32 = 1 << 2;
pub const NVME_CSTS_SHST_CMPLT: u32 = 2 << 2;
pub const NVME_QUEUE_PHYS_CONTIG: u16 = 1 << 0;
pub const NVME_CQ_IRQ_ENABLED: u16 = 1 << 1;
pub const NVME_SQ_PRIO_URGENT: u16 = 0 << 1;
pub const NVME_SQ_PRIO_HIGH: u16 = 1 << 1;
pub const NVME_SQ_PRIO_MEDIUM: u16 = 2 << 1;
pub const NVME_SQ_PRIO_LOW: u16 = 3 << 1;
pub const NVME_FEAT_ARBITRATION: u32 = 0x01;
pub const NVME_FEAT_POWER_MGMT: u32 = 0x02;
pub const NVME_FEAT_LBA_RANGE: u32 = 0x03;
pub const NVME_FEAT_TEMP_THRESH: u32 = 0x04;
pub const NVME_FEAT_ERR_RECOVERY: u32 = 0x05;
pub const NVME_FEAT_VOLATILE_WC: u32 = 0x06;
pub const NVME_FEAT_NUM_QUEUES: u32 = 0x07;
pub const NVME_FEAT_IRQ_COALESCE: u32 = 0x08;
pub const NVME_FEAT_IRQ_CONFIG: u32 = 0x09;
pub const NVME_FEAT_WRITE_ATOMIC: u32 = 0x0a;
pub const NVME_FEAT_ASYNC_EVENT: u32 = 0x0b;
pub const NVME_FEAT_SW_PROGRESS: u32 = 0x0c;

View File

@ -1,5 +0,0 @@
pub mod interface;
pub mod nvme_queue;
pub use interface::*;
pub use nvme_queue::*;

View File

@ -1,120 +0,0 @@
use alloc::slice;
use core::marker::PhantomData;
use volatile::Volatile;
use super::NvmeCommonCommand;
use super::NvmeCompletion;
#[derive(Debug)]
pub struct NvmeQueue<P: Provider> {
provider: PhantomData<P>,
pub sq: &'static mut [Volatile<NvmeCommonCommand>],
pub cq: &'static mut [Volatile<NvmeCompletion>],
pub db_offset: usize,
pub qid: usize,
pub cq_head: usize,
pub cq_phase: usize,
pub sq_tail: usize,
pub last_sq_tail: usize,
pub sq_pa: usize,
pub cq_pa: usize,
pub data_pa: usize,
}
impl<P: Provider> NvmeQueue<P> {
pub fn new(qid: usize, db_offset: usize) -> Self {
let (data_va, data_pa) = P::alloc_dma(P::PAGE_SIZE * 2);
let (sq_va, sq_pa) = P::alloc_dma(P::PAGE_SIZE * 2);
let (cq_va, cq_pa) = P::alloc_dma(P::PAGE_SIZE * 2);
trace!("data_va: {:x}, data_pa: {:x}", data_va, data_pa);
let submit_queue = unsafe {
slice::from_raw_parts_mut(sq_va as *mut Volatile<NvmeCommonCommand>, PAGE_SIZE)
};
let complete_queue =
unsafe { slice::from_raw_parts_mut(cq_va as *mut Volatile<NvmeCompletion>, PAGE_SIZE) };
NvmeQueue {
provider: PhantomData,
sq: submit_queue,
cq: complete_queue,
db_offset,
qid,
cq_head: 0,
cq_phase: 0,
sq_tail: 0,
last_sq_tail: 0,
sq_pa,
cq_pa,
data_pa,
}
}
}
/// External functions that drivers must use
pub trait Provider {
/// Page size (usually 4K)
const PAGE_SIZE: usize;
/// Allocate consequent physical memory for DMA.
/// Return (`virtual address`, `physical address`).
/// The address is page aligned.
fn alloc_dma(size: usize) -> (usize, usize);
/// Deallocate DMA
fn dealloc_dma(vaddr: usize, size: usize);
}
pub struct ProviderImpl;
impl Provider for ProviderImpl {
const PAGE_SIZE: usize = PAGE_SIZE;
fn alloc_dma(size: usize) -> (usize, usize) {
let paddr = unsafe { drivers_dma_alloc(size / PAGE_SIZE) };
let vaddr = phys_to_virt(paddr);
(vaddr, paddr)
}
fn dealloc_dma(vaddr: usize, size: usize) {
let paddr = virt_to_phys(vaddr);
unsafe { drivers_dma_dealloc(paddr, size / PAGE_SIZE) };
}
}
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) }
}
pub fn timer_now_as_micros() -> u64 {
unsafe { drivers_timer_now_as_micros() }
}
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;
fn drivers_timer_now_as_micros() -> u64;
}
pub const PAGE_SIZE: usize = 4096;
type VirtAddr = usize;
type PhysAddr = usize;

View File

@ -8,21 +8,3 @@ pub use uart_16550::Uart16550Mmio;
#[cfg(target_arch = "x86_64")]
pub use uart_16550::Uart16550Pmio;
#[cfg(target_arch = "aarch64")]
mod uart_pl011;
#[cfg(target_arch = "aarch64")]
pub use uart_pl011::Pl011Uart;
#[cfg(feature = "allwinner")]
mod uart_allwinner;
#[cfg(feature = "allwinner")]
pub use uart_allwinner::UartAllwinner;
#[cfg(feature = "fu740")]
mod uart_u740;
#[cfg(feature = "fu740")]
pub use uart_u740::UartU740Mmio;

View File

@ -1,132 +0,0 @@
use crate::{
scheme::{impl_event_scheme, Scheme, UartScheme},
utils::EventListener,
DeviceResult, VirtAddr,
};
use d1_pac::uart;
use lock::Mutex;
pub struct UartAllwinner {
inner: Mutex<Inner>,
listener: EventListener,
}
impl_event_scheme!(UartAllwinner);
impl UartAllwinner {
pub fn new(base: VirtAddr) -> Self {
let inner = Inner(base);
inner.init();
Self {
inner: Mutex::new(inner),
listener: EventListener::new(),
}
}
}
impl Scheme for UartAllwinner {
#[inline]
fn name(&self) -> &str {
"uart-allwinner"
}
#[inline]
fn handle_irq(&self, _irq_num: usize) {
self.listener.trigger(());
}
}
impl UartScheme for UartAllwinner {
#[inline]
fn try_recv(&self) -> DeviceResult<Option<u8>> {
self.inner.lock().try_recv()
}
#[inline]
fn send(&self, ch: u8) -> DeviceResult {
self.inner.lock().send(ch)
}
#[inline]
fn write_str(&self, s: &str) -> DeviceResult {
self.inner.lock().write_str(s)
}
}
struct Inner(VirtAddr);
impl Inner {
/// 初始化串口控制器
/// BAUD 115200
/// FIFO ON
fn init(&self) {
let block = self.block();
// disable interrupts
block.ier().reset();
// enable fifo
block.fcr().write(|w| w.fifoe().set_bit());
{
block.halt.write(|w| w.halt_tx().set_bit());
block.lcr.write(|w| w.dlab().set_bit());
// 13 for 115200
block.dll().write(|w| w.dll().variant(13));
block.dlh().write(|w| w.dlh().variant(0));
// no break | parity disabled | 1 stop bit | 8 data bits
block.lcr.write(|w| w.dls().eight());
#[rustfmt::skip]
block.halt.write(|w| w
.change_update().set_bit()
.chcfg_at_busy().set_bit());
}
// reset fifo
#[rustfmt::skip]
block.fcr().write(|w| w
.xfifor().set_bit()
.rfifor().set_bit()
.fifoe() .set_bit()
);
// uart mode
block.mcr.reset();
// enable interrupts
block.ier().write(|w| w.erbfi().set_bit());
}
/// 接收
fn try_recv(&self) -> DeviceResult<Option<u8>> {
let block = self.block();
if block.lsr.read().dr().bit_is_set() {
Ok(Some(block.rbr().read().bits() as _))
} else {
Ok(None)
}
}
/// 发送
fn send(&self, ch: u8) -> DeviceResult {
let block = self.block();
// 等待 FIFO 空位
while block.usr.read().tfnf().is_full() {
core::hint::spin_loop();
}
block.thr().write(|w| w.thr().variant(ch));
Ok(())
}
fn write_str(&mut self, s: &str) -> DeviceResult {
for b in s.bytes() {
match b {
b'\n' => {
self.send(b'\r')?;
self.send(b'\n')?;
}
_ => self.send(b)?,
}
}
Ok(())
}
#[inline]
fn block(&self) -> &uart::RegisterBlock {
unsafe { &*(self.0 as *const _) }
}
}

View File

@ -1,185 +0,0 @@
//! PL011 UART.
use crate::scheme::{impl_event_scheme, Scheme, UartScheme};
use crate::utils::EventListener;
use crate::DeviceResult;
use bitflags::*;
use core::ptr;
bitflags! {
/// UARTFR
struct UartFrFlags: u16 {
const TXFE = 1 << 7;
const RXFF = 1 << 6;
const TXFF = 1 << 5;
const RXFE = 1 << 4;
const BUSY = 1 << 3;
}
}
bitflags! {
/// UARTCR
struct UartCrFlags: u16 {
const RXE = 1 << 9;
const TXE = 1 << 8;
const UARTEN = 1 << 0;
}
}
bitflags! {
// UARTIMSC
struct UartImscFlags: u16 {
const RTIM = 1 << 6;
const TXIM = 1 << 5;
const RXIM = 1 << 4;
}
}
bitflags! {
// UARTICR
struct UartIcrFlags: u16 {
const RTIC = 1 << 6;
const TXIC = 1 << 5;
const RXIC = 1 << 4;
}
}
bitflags! {
//UARTMIS
struct UartMisFlags: u16 {
const TXMIS = 1 << 5;
const RXMIS = 1 << 4;
}
}
bitflags! {
//UARTLCR_H
struct UartLcrhFlags: u16 {
const FEN = 1 << 4;
}
}
#[allow(dead_code)]
pub struct Pl011Uart {
inner: Pl011Inner,
listener: EventListener,
}
impl Pl011Uart {
pub fn new(base: usize) -> Self {
Self {
inner: {
let inner = Pl011Inner::new(base);
inner.init();
inner
},
listener: EventListener::new(),
}
}
fn getchar(&self) -> Option<u8> {
self.inner.getchar()
}
fn putchar(&self, data: u8) {
self.inner.putchar(data);
}
}
struct Pl011Inner {
base: usize,
data_reg: u8,
flag_reg: u8,
line_ctrl_reg: u8,
ctrl_reg: u8,
intr_mask_setclr_reg: u8,
intr_clr_reg: u8,
}
impl Pl011Inner {
pub fn new(base: usize) -> Pl011Inner {
Pl011Inner {
base,
data_reg: 0x00,
flag_reg: 0x18,
line_ctrl_reg: 0x2c,
ctrl_reg: 0x30,
intr_mask_setclr_reg: 0x38,
intr_clr_reg: 0x44,
}
}
fn read_reg(&self, register: u8) -> u16 {
unsafe { ptr::read_volatile((self.base + register as usize) as *mut u16) }
}
fn write_reg(&self, register: u8, data: u16) {
unsafe {
ptr::write_volatile((self.base + register as usize) as *mut u16, data);
}
}
fn init(&self) {
// Enable RX, TX, UART
let flags = UartCrFlags::RXE | UartCrFlags::TXE | UartCrFlags::UARTEN;
self.write_reg(self.ctrl_reg, flags.bits());
// Disable FIFOs (use character mode instead)
let mut flags = UartLcrhFlags::from_bits_truncate(self.read_reg(self.line_ctrl_reg));
flags.remove(UartLcrhFlags::FEN);
self.write_reg(self.line_ctrl_reg, flags.bits());
// Enable IRQs
let flags = UartImscFlags::RXIM;
self.write_reg(self.intr_mask_setclr_reg, flags.bits);
// Clear pending interrupts
self.write_reg(self.intr_clr_reg, 0x7ff);
}
fn line_sts(&self) -> UartFrFlags {
UartFrFlags::from_bits_truncate(self.read_reg(self.flag_reg))
}
fn getchar(&self) -> Option<u8> {
if self.line_sts().contains(UartFrFlags::RXFF) {
Some(self.read_reg(self.data_reg) as u8)
} else {
None
}
}
fn putchar(&self, data: u8) {
while !self.line_sts().contains(UartFrFlags::TXFE) {}
self.write_reg(self.data_reg, data as u16);
}
}
impl Scheme for Pl011Uart {
fn name(&self) -> &str {
"Pl011 ARM series uart"
}
fn handle_irq(&self, _irq_num: usize) {
self.listener.trigger(())
}
}
impl_event_scheme!(Pl011Uart);
impl UartScheme for Pl011Uart {
fn try_recv(&self) -> DeviceResult<Option<u8>> {
Ok(self.getchar())
}
fn send(&self, ch: u8) -> DeviceResult {
self.putchar(ch);
Ok(())
}
fn write_str(&self, s: &str) -> DeviceResult {
for c in s.bytes() {
self.send(c)?;
}
Ok(())
}
}

View File

@ -1,214 +0,0 @@
use bitflags::bitflags;
use core::convert::TryInto;
use core::ops::{BitAnd, BitOr, Not};
use lock::Mutex;
use crate::io::{Io, Mmio, ReadOnly};
use crate::scheme::{impl_event_scheme, Scheme, UartScheme};
use crate::utils::EventListener;
use crate::DeviceResult;
bitflags! {
/// TXDATA fields
struct TXDATAFlags: u32 {
const TXFULL = 1 << 31;
}
}
bitflags! {
/// RXDATA fields
struct RXDATAFlags: u32 {
const RXEMPTY = 1 << 31;
}
}
bitflags! {
/// TXCTRL fields
struct TXCTRLFlags: u32 {
const TXEN = 1;
const NSTOP = 1 << 1;
}
}
bitflags! {
/// RXCTRL fields
struct RXCTRLFlags: u32 {
const RXEN = 1;
}
}
bitflags! {
/// IE fields
struct IEFlags: u32 {
const TXWM = 1;
const RXWM = 1 << 1;
}
}
#[repr(C)]
struct UartU740Inner<T: Io> {
/// Transmit data register
tx_data: T,
/// Receive data register
rx_data: ReadOnly<T>,
/// Transmit control register
tx_ctrl: T,
/// Receive control register
rx_ctrl: T,
/// UART interrupt enable
ie: T,
/// UART interrupt pending
ip: ReadOnly<T>,
/// Baud rate divisor
div: T,
}
impl<T: Io> UartU740Inner<T>
where
T::Value: From<u8> + TryInto<u8> + From<u32> + TryInto<u32>,
{
fn init(&mut self) {
// Enable transmit and set 1 stop bit and interrupt watermark
self.tx_ctrl
.write((self.tx_ctrl.read().try_into().unwrap_or(0) | TXCTRLFlags::TXEN.bits()).into());
// Enable receive and set interrupt watermark
self.rx_ctrl
.write((self.rx_ctrl.read().try_into().unwrap_or(0) | RXCTRLFlags::RXEN.bits()).into());
// Enable TX & RX interrupt
self.ie.write(
(self.ie.read().try_into().unwrap_or(0) | IEFlags::TXWM.bits() | IEFlags::RXWM.bits())
.into(),
);
}
fn try_recv(&mut self) -> DeviceResult<Option<u8>> {
let ch = self.rx_data.read();
if RXDATAFlags::from_bits_truncate(ch.try_into().unwrap_or(0))
.contains(RXDATAFlags::RXEMPTY)
{
Ok(None)
} else {
Ok(Some(ch.try_into().unwrap_or(0) & 0xFF))
}
}
fn send(&mut self, ch: u8) -> DeviceResult {
let mut status;
loop {
status = self.tx_data.read();
if !TXDATAFlags::from_bits_truncate(status.try_into().unwrap_or(0))
.contains(TXDATAFlags::TXFULL)
{
break;
}
}
self.tx_data.write(ch.into());
Ok(())
}
fn write_str(&mut self, s: &str) -> DeviceResult {
for b in s.bytes() {
match b {
b'\n' => {
self.send(b'\r')?;
self.send(b'\n')?;
}
_ => {
self.send(b)?;
}
}
}
Ok(())
}
}
/// MMIO driver for UART 16550
pub struct UartU740Mmio<V: 'static>
where
V: Copy + BitAnd<Output = V> + BitOr<Output = V> + Not<Output = V>,
{
inner: Mutex<&'static mut UartU740Inner<Mmio<V>>>,
listener: EventListener,
}
impl_event_scheme!(UartU740Mmio<V>
where
V: Copy
+ BitAnd<Output = V>
+ BitOr<Output = V>
+ Not<Output = V>
+ From<u8>
+ TryInto<u8>
+ Send
);
impl<V> Scheme for UartU740Mmio<V>
where
V: Copy + BitAnd<Output = V> + BitOr<Output = V> + Not<Output = V> + Send,
{
fn name(&self) -> &str {
"uart-u740-mmio"
}
fn handle_irq(&self, _irq_num: usize) {
self.listener.trigger(());
}
}
impl<V> UartScheme for UartU740Mmio<V>
where
V: Copy
+ BitAnd<Output = V>
+ BitOr<Output = V>
+ Not<Output = V>
+ From<u8>
+ TryInto<u8>
+ From<u32>
+ TryInto<u32>
+ Send,
{
fn try_recv(&self) -> DeviceResult<Option<u8>> {
self.inner.lock().try_recv()
}
fn send(&self, ch: u8) -> DeviceResult {
self.inner.lock().send(ch)
}
fn write_str(&self, s: &str) -> DeviceResult {
self.inner.lock().write_str(s)
}
}
impl<V> UartU740Mmio<V>
where
V: Copy
+ BitAnd<Output = V>
+ BitOr<Output = V>
+ Not<Output = V>
+ From<u8>
+ TryInto<u8>
+ From<u32>
+ TryInto<u32>
+ Send,
{
unsafe fn new_common(base: usize) -> Self {
let uart: &mut UartU740Inner<Mmio<V>> = Mmio::<V>::from_base_as(base);
uart.init();
Self {
inner: Mutex::new(uart),
listener: EventListener::new(),
}
}
}
impl UartU740Mmio<u32> {
/// # Safety
///
/// This function is unsafe because `base_addr` may be an arbitrary address.
pub unsafe fn new(base: usize) -> Self {
Self::new_common(base)
}
}

View File

@ -31,7 +31,6 @@ pub struct InheritProps {
impl Devicetree {
/// Load the device tree blob from the given virtual address.
pub fn from(dtb_base_vaddr: VirtAddr) -> DeviceResult<Self> {
info!("Loading device tree blob from {:#x}", dtb_base_vaddr);
match unsafe { DeviceTreeInner::load_from_raw_pointer(dtb_base_vaddr as *const _) } {
Ok(dt) => Ok(Self(dt)),
Err(err) => {

View File

@ -1,6 +1,9 @@
#![allow(dead_code)]
use core::ops::Range;
use super::IdAllocator;
use crate::{prelude::IrqHandler, DeviceError, DeviceResult};
use core::ops::Range;
pub struct IrqManager<const IRQ_COUNT: usize> {
irq_range: Range<usize>,
@ -20,7 +23,6 @@ impl<const IRQ_COUNT: usize> IrqManager<IRQ_COUNT> {
}
}
#[allow(unused)]
pub fn alloc_block(&mut self, count: usize) -> DeviceResult<usize> {
info!("IRQ alloc_block {}", count);
debug_assert!(count.is_power_of_two());
@ -28,7 +30,6 @@ impl<const IRQ_COUNT: usize> IrqManager<IRQ_COUNT> {
self.allocator.alloc_contiguous(count, align_log2 as _)
}
#[allow(unused)]
pub fn free_block(&mut self, start: usize, count: usize) -> DeviceResult {
info!("IRQ free_block {:#x?}", start..start + count);
self.allocator.free(start, count)
@ -51,7 +52,6 @@ impl<const IRQ_COUNT: usize> IrqManager<IRQ_COUNT> {
Ok(irq_num)
}
#[cfg(not(target_arch = "aarch64"))]
pub fn unregister_handler(&mut self, irq_num: usize) -> DeviceResult {
info!("IRQ unregister handler {}", irq_num);
if !self.allocator.is_alloced(irq_num) {
@ -63,7 +63,6 @@ impl<const IRQ_COUNT: usize> IrqManager<IRQ_COUNT> {
}
}
#[allow(unused)]
pub fn overwrite_handler(&mut self, irq_num: usize, handler: IrqHandler) -> DeviceResult {
info!("IRQ overwrite handle {}", irq_num);
if !self.allocator.is_alloced(irq_num) {

View File

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

View File

@ -9,7 +9,6 @@ pub use blk::VirtIoBlk;
pub use console::VirtIoConsole;
pub use gpu::VirtIoGpu;
pub use input::VirtIoInput;
pub use virtio_drivers::VirtIOHeader;
use crate::DeviceError;
use core::convert::From;

View File

@ -2,8 +2,8 @@
name = "kernel-hal"
version = "0.1.0"
authors = [
"Runji Wang <wangrunji0408@163.com>",
"Yuekai Jia <equation618@gmail.com>",
"Runji Wang <wangrunji0408@163.com>",
"Yuekai Jia <equation618@gmail.com>",
]
edition = "2018"
description = "Kernel HAL interface definations."
@ -12,28 +12,17 @@ description = "Kernel HAL interface definations."
[features]
default = ["libos"]
smp = []
libos = [
"nix",
"tempfile",
"async-std",
"bitmap-allocator",
"zcore-drivers/mock",
"nix",
"tempfile",
"async-std",
"bitmap-allocator",
"zcore-drivers/mock",
]
# TODO
loopback = ["zcore-drivers/loopback", "no-pci"]
# Enable graphical output
graphic = ["zcore-drivers/graphic"]
board-c910light = []
link-user-img = []
# Enable extra page table falgs for T-Head CPU with MAEE on
thead-maee = []
# Disable PCI
no-pci = ["zcore-drivers/no-pci"]
# Enable allwinner drivers
allwinner-drivers = ["zcore-drivers/allwinner"]
# Enable fu740 drivers
fu740-drivers = ["zcore-drivers/fu740"]
loopback = []
[dependencies]
log = "0.4"
@ -45,22 +34,11 @@ 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 = "8486b8" }
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",
] }
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]
nix = { version = "0.23", optional = true }
tempfile = { version = "3", optional = true }
async-std = { version = "1.10", optional = true }
@ -68,27 +46,21 @@ bitmap-allocator = { git = "https://github.com/rcore-os/bitmap-allocator.git", r
# Bare-metal mode
[target.'cfg(target_os = "none")'.dependencies]
executor = { git = "https://github.com/DeathWish5/PreemptiveScheduler", rev = "3b04ba4" }
naive-timer = "0.2.0"
executor = { git = "https://github.com/DeathWish5/PreemptiveScheduler", rev = "e8cd353" }
# For riscv
[target.'cfg(any(target_arch = "riscv32", target_arch = "riscv64"))'.dependencies]
riscv = "0.9"
sbi-rt = { version = "0.0.2", features = ["legacy"] }
# For x86_64
# All mode on x86_64
[target.'cfg(target_arch = "x86_64")'.dependencies]
x86 = "0.46"
x86_64 = "0.14"
# For aarch64
[target.'cfg(target_arch = "aarch64")'.dependencies]
tock-registers = "0.7"
cortex-a = "7.2.0"
# Bare-metal mode on x86_64
[target.'cfg(all(target_os = "none", target_arch = "x86_64"))'.dependencies]
uefi = "0.16"
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"

View File

@ -1,28 +0,0 @@
//! Kernel configuration.
use crate::PAGE_SIZE;
/// Kernel configuration passed by kernel when calls [`crate::primary_init_early()`].
#[repr(C)]
#[derive(Debug, Clone)]
pub struct KernelConfig {
/// boot cmd line
pub cmdline: &'static str,
/// firmware type
pub firmware_type: &'static str,
/// UART base address
pub uart_base: usize,
/// GIC base address
pub gic_base: usize,
/// phystovirt offset
pub phys_to_virt_offset: usize,
}
pub const PHYS_MEMORY_BASE: usize = 0x4000_0000;
pub const UART_SIZE: usize = 0x1000;
pub const VIRTIO_BASE: usize = 0x0a00_0000;
pub const VIRTIO_SIZE: usize = 0x100;
pub const PA_1TB_BITS: usize = 40;
pub const PHYS_ADDR_MAX: usize = (1 << PA_1TB_BITS) - 1;
pub const PHYS_ADDR_MASK: usize = PHYS_ADDR_MAX & !(PAGE_SIZE - 1);
pub const PHYS_MEMORY_END: usize = PHYS_MEMORY_BASE + 100 * 1024 * 1024;
pub const USER_TABLE_FLAG: usize = 0xabcd_0000_0000_0000;

View File

@ -1,29 +0,0 @@
//! CPU information.
use cortex_a::registers::*;
use tock_registers::interfaces::Readable;
hal_fn_impl! {
impl mod crate::hal_fn::cpu {
fn cpu_id() -> u8 {
let id = MPIDR_EL1.get() & 0x3;
id as u8
}
fn cpu_frequency() -> u16 {
0
}
fn reset() -> ! {
info!("shutdown...");
let psci_system_off = 0x8400_0008_usize;
unsafe {
core::arch::asm!(
"hvc #0",
in("x0") psci_system_off
);
}
unreachable!()
}
}
}

View File

@ -1,38 +0,0 @@
use crate::arch::timer::set_next_trigger;
use crate::drivers;
use crate::hal_fn::mem::phys_to_virt;
use crate::imp::config::VIRTIO_BASE;
use crate::KCONFIG;
use alloc::boxed::Box;
use alloc::sync::Arc;
use zcore_drivers::irq::gic_400;
use zcore_drivers::scheme::IrqScheme;
use zcore_drivers::uart::{BufferedUart, Pl011Uart};
use zcore_drivers::virtio::{VirtIOHeader, VirtIoBlk};
use zcore_drivers::Device;
pub fn init_early() {
let uart = Pl011Uart::new(phys_to_virt(KCONFIG.uart_base));
let uart = Arc::new(uart);
let gic = gic_400::init(
phys_to_virt(KCONFIG.gic_base + 0x1_0000),
phys_to_virt(KCONFIG.gic_base),
);
gic.irq_enable(30);
gic.irq_enable(33);
gic.register_handler(33, Box::new(handle_uart_irq)).ok();
gic.register_handler(30, Box::new(set_next_trigger)).ok();
drivers::add_device(Device::Irq(Arc::new(gic)));
drivers::add_device(Device::Uart(BufferedUart::new(uart)));
}
pub fn init() {
let virtio_blk = Arc::new(
VirtIoBlk::new(unsafe { &mut *(phys_to_virt(VIRTIO_BASE) as *mut VirtIOHeader) }).unwrap(),
);
drivers::add_device(Device::Block(virtio_blk));
}
fn handle_uart_irq() {
crate::drivers::all_uart().first_unwrap().handle_irq(0);
}

View File

@ -1,49 +0,0 @@
//! Interrupts management.
use crate::HalResult;
use alloc::vec::Vec;
use cortex_a::asm::wfi;
hal_fn_impl! {
impl mod crate::hal_fn::interrupt {
fn wait_for_interrupt() {
intr_on();
wfi();
intr_off();
}
fn handle_irq(vector: usize) {
// TODO: timer and other devices with GIC interrupt controller
crate::drivers::all_irq().first_unwrap().handle_irq(vector);
if vector == 30 {
debug!("Timer");
}
}
fn intr_off() {
unsafe {
core::arch::asm!("msr daifset, #2");
}
}
fn intr_on() {
unsafe {
core::arch::asm!("msr daifclr, #2");
}
}
fn intr_get() -> bool {
use cortex_a::registers::DAIF;
use tock_registers::interfaces::Readable;
!DAIF.is_set(DAIF::I)
}
fn send_ipi(cpuid: usize, reason: usize) -> HalResult {
trace!("ipi [{}] => [{}]: {:x}", super::cpu::cpu_id(), cpuid, reason);
panic!("send_ipi unsupported for aarch64");
}
fn ipi_reason() -> Vec<usize> {
panic!("ipi_reason unsupported for aarch64");
}
}
}

View File

@ -1,20 +0,0 @@
use crate::imp::config::*;
use crate::PhysAddr;
use alloc::vec::Vec;
use core::ops::Range;
extern "C" {
fn ekernel();
}
pub fn free_pmem_regions() -> Vec<Range<PhysAddr>> {
let mut regions = Vec::new();
let start = ekernel as usize & PHYS_ADDR_MASK;
regions.push(start as PhysAddr..PHYS_MEMORY_END as PhysAddr);
regions
}
/// Flush the physical frame.
pub fn frame_flush(_target: PhysAddr) {
unimplemented!()
}

View File

@ -1,50 +0,0 @@
pub mod config;
pub mod cpu;
pub mod drivers;
pub mod interrupt;
pub mod mem;
pub mod timer;
pub mod trap;
pub mod vm;
use crate::KCONFIG;
use crate::{mem::phys_to_virt, utils::init_once::InitOnce, PhysAddr};
use alloc::string::{String, ToString};
use core::ops::Range;
hal_fn_impl_default!(crate::hal_fn::console);
static INITRD_REGION: InitOnce<Option<Range<PhysAddr>>> = InitOnce::new_with_default(None);
static CMDLINE: InitOnce<String> = InitOnce::new_with_default(String::new());
pub fn cmdline() -> String {
CMDLINE.clone()
}
pub fn init_ram_disk() -> Option<&'static mut [u8]> {
INITRD_REGION.as_ref().map(|range| unsafe {
core::slice::from_raw_parts_mut(phys_to_virt(range.start) as *mut u8, range.len())
})
}
pub fn primary_init_early() {
CMDLINE.init_once_by(KCONFIG.cmdline.to_string());
drivers::init_early();
}
pub fn primary_init() {
vm::init();
drivers::init();
}
pub fn secondary_init() {
unimplemented!()
}
pub const fn timer_interrupt_vector() -> usize {
30
}
pub fn timer_init() {
timer::init();
}

View File

@ -1,22 +0,0 @@
//! ARM Generic Timer.
use crate::timer::TICKS_PER_SEC;
use core::time::Duration;
use cortex_a::{asm::barrier, registers::*};
use tock_registers::interfaces::{Readable, Writeable};
pub fn timer_now() -> Duration {
unsafe { barrier::isb(barrier::SY) }
let cur_cnt = CNTPCT_EL0.get() * 1_000_000_000;
let freq = CNTFRQ_EL0.get() as u64;
Duration::from_nanos(cur_cnt / freq)
}
pub fn set_next_trigger() {
CNTP_TVAL_EL0.set(CNTFRQ_EL0.get() / TICKS_PER_SEC);
}
pub fn init() {
CNTP_CTL_EL0.write(CNTP_CTL_EL0::ENABLE::SET);
set_next_trigger();
}

View File

@ -1,51 +0,0 @@
use crate::context::TrapReason;
use crate::{Info, Kind, Source, KCONFIG};
use cortex_a::registers::FAR_EL1;
use tock_registers::interfaces::Readable;
use trapframe::TrapFrame;
use zcore_drivers::irq::gic_400::get_irq_num;
#[no_mangle]
pub extern "C" fn trap_handler(tf: &mut TrapFrame) {
let info = Info {
source: Source::from(tf.trap_num & 0xffff),
kind: Kind::from((tf.trap_num >> 16) & 0xffff),
};
trace!("Exception from {:?}", info.source);
match info.kind {
Kind::Synchronous => {
sync_handler(tf);
}
Kind::Irq => {
use crate::hal_fn::mem::phys_to_virt;
crate::interrupt::handle_irq(get_irq_num(
phys_to_virt(KCONFIG.gic_base + 0x1_0000),
phys_to_virt(KCONFIG.gic_base),
));
}
_ => {
panic!(
"Unsupported exception type: {:?}, TrapFrame: {:?}",
info.kind, tf
);
}
}
trace!("Exception end");
}
fn breakpoint(elr: &mut usize) {
info!("Exception::Breakpoint: A breakpoint set @0x{:x} ", elr);
*elr += 4;
}
fn sync_handler(tf: &mut TrapFrame) {
match TrapReason::from(tf.trap_num) {
TrapReason::PageFault(vaddr, flags) => crate::KHANDLER.handle_page_fault(vaddr, flags),
TrapReason::SoftwareBreakpoint => breakpoint(&mut tf.elr),
other => error!(
"Unsupported trap in kernel: {:?}, FAR_EL1: {:#x?}",
other,
FAR_EL1.get()
),
}
}

View File

@ -1,353 +0,0 @@
use crate::hal_fn::mem::phys_to_virt;
use crate::imp::config::*;
use crate::utils::page_table::{GenericPTE, PageTableImpl, PageTableLevel4};
use crate::MMUFlags;
use crate::{PhysAddr, VirtAddr, KCONFIG};
use core::fmt::{Debug, Formatter, Result};
use cortex_a::registers::*;
use lock::Mutex;
use tock_registers::interfaces::{Readable, Writeable};
use zcore_drivers::irq::gic_400::{GICC_SIZE, GICD_SIZE};
lazy_static! {
static ref KERNEL_PT: Mutex<PageTable> = Mutex::new(init_kernel_page_table().unwrap());
}
/// remap kernel ELF segments with 4K page
fn init_kernel_page_table() -> PagingResult<PageTable> {
extern "C" {
fn stext();
fn etext();
fn srodata();
fn erodata();
fn sdata();
fn edata();
fn sbss();
fn ebss();
fn boot_stack();
fn boot_stack_top();
}
let mut pt = PageTable::new();
let mut map_range = |start: VirtAddr, end: VirtAddr, flags: MMUFlags| -> PagingResult {
pt.map_cont(
crate::addr::align_down(start),
crate::addr::align_up(end - start),
start - KCONFIG.phys_to_virt_offset,
flags,
)
};
map_range(
stext as usize,
etext as usize,
MMUFlags::READ | MMUFlags::EXECUTE,
)?;
map_range(srodata as usize, erodata as usize, MMUFlags::READ)?;
map_range(
sdata as usize,
edata as usize,
MMUFlags::READ | MMUFlags::WRITE,
)?;
map_range(
sbss as usize,
ebss as usize,
MMUFlags::READ | MMUFlags::WRITE,
)?;
// stack
map_range(
boot_stack as usize,
boot_stack_top as usize,
MMUFlags::READ | MMUFlags::WRITE,
)?;
// uart
map_range(
phys_to_virt(KCONFIG.uart_base),
phys_to_virt(KCONFIG.uart_base) + UART_SIZE,
MMUFlags::READ | MMUFlags::WRITE | MMUFlags::DEVICE,
)?;
// gic
map_range(
phys_to_virt(KCONFIG.gic_base + 0x1_0000),
phys_to_virt(KCONFIG.gic_base + 0x1_0000) + GICC_SIZE,
MMUFlags::READ | MMUFlags::WRITE | MMUFlags::DEVICE,
)?;
map_range(
phys_to_virt(KCONFIG.gic_base),
phys_to_virt(KCONFIG.gic_base) + GICD_SIZE,
MMUFlags::READ | MMUFlags::WRITE | MMUFlags::DEVICE,
)?;
// virtio_drivers
map_range(
phys_to_virt(VIRTIO_BASE),
phys_to_virt(VIRTIO_BASE) + VIRTIO_SIZE,
MMUFlags::READ | MMUFlags::WRITE | MMUFlags::DEVICE,
)?;
// physical frames
for r in crate::mem::free_pmem_regions() {
map_range(
phys_to_virt(r.start),
phys_to_virt(r.end),
MMUFlags::READ | MMUFlags::WRITE,
)?;
}
Ok(pt)
}
pub fn init() {
let mut pt = KERNEL_PT.lock();
info!("initialized kernel page table @ {:#x}", pt.table_phys());
unsafe {
pt.activate();
TTBR0_EL1.set(0);
flush_tlb_all();
}
}
pub fn flush_tlb_all() {
unsafe {
core::arch::asm!(
"dsb ishst
tlbi vmalle1is
dsb ish
isb"
);
}
}
hal_fn_impl! {
impl mod crate::hal_fn::vm {
fn activate_paging(vmtoken: PhysAddr) {
let check_if_user = (vmtoken & USER_TABLE_FLAG) != 0;
let vmtoken = vmtoken & PHYS_ADDR_MASK;
info!("set {} page_table @ {:#x}", if check_if_user { "user" } else { "kernel" }, vmtoken);
if check_if_user {
TTBR0_EL1.set(vmtoken as _);
} else {
TTBR1_EL1.set(vmtoken as _);
}
flush_tlb_all();
}
fn current_vmtoken() -> PhysAddr {
TTBR1_EL1.get() as _
}
fn flush_tlb(vaddr: Option<VirtAddr>) {
// Translations used at EL1 for the specified address, for all ASID values,
// in the Inner Shareable shareability domain.
if let Some(vaddr) = vaddr {
unsafe {
core::arch::asm!(
"dsb ishst
tlbi vaae1is, {0}
dsb ish
isb",
in(reg) vaddr >> 12
);
}
} else {
flush_tlb_all();
}
}
fn pt_clone_kernel_space(dst_pt_root: PhysAddr, src_pt_root: PhysAddr) {
let entry_range = 0x100..0x200; // 0xffff_0000_8000_0000..0xffff_0000_c000_0000
let dst_table = unsafe { core::slice::from_raw_parts_mut(phys_to_virt(dst_pt_root) as *mut AARCH64PTE, 512) };
let src_table = unsafe { core::slice::from_raw_parts(phys_to_virt(src_pt_root) as *const AARCH64PTE, 512) };
for i in entry_range {
dst_table[i] = src_table[i];
if dst_table[i].is_unused() {
dst_table[i].0 |= PTF::NG.bits() as u64;
}
}
}
}
}
bitflags::bitflags! {
/// Possible flags for a page table entry.
struct PTF: usize {
// Attribute fields in stage 1 VMSAv8-64 Block and Page descriptors:
/// Whether the descriptor is valid.
const VALID = 1 << 0;
/// The descriptor gives the address of the next level of translation table or 4KB page.
/// (not a 2M, 1G block)
const NON_BLOCK = 1 << 1;
/// Memory attributes index field.
const ATTR_INDX = 0b111 << 2;
/// Non-secure bit. For memory accesses from Secure state, specifies whether the output
/// address is in Secure or Non-secure memory.
const NS = 1 << 5;
/// Access permission: accessable at EL0.
const AP_EL0 = 1 << 6;
/// Access permission: read-only.
const AP_RO = 1 << 7;
/// Shareability: Inner Shareable (otherwise Outer Shareable).
const INNER = 1 << 8;
/// Shareability: Inner or Outer Shareable (otherwise Non-shareable).
const SHAREABLE = 1 << 9;
/// The Access flag.
const AF = 1 << 10;
/// The not global bit.
const NG = 1 << 11;
/// Indicates that 16 adjacent translation table entries point to contiguous memory regions.
const CONTIGUOUS = 1 << 52;
/// The Privileged execute-never field.
const PXN = 1 << 53;
/// The Execute-never or Unprivileged execute-never field.
const UXN = 1 << 54;
// Next-level attributes in stage 1 VMSAv8-64 Table descriptors:
/// PXN limit for subsequent levels of lookup.
const PXN_TABLE = 1 << 59;
/// XN limit for subsequent levels of lookup.
const XN_TABLE = 1 << 60;
/// Access permissions limit for subsequent levels of lookup: access at EL0 not permitted.
const AP_NO_EL0_TABLE = 1 << 61;
/// Access permissions limit for subsequent levels of lookup: write access not permitted.
const AP_NO_WRITE_TABLE = 1 << 62;
/// For memory accesses from Secure state, specifies the Security state for subsequent
/// levels of lookup.
const NS_TABLE = 1 << 63;
}
}
#[repr(u64)]
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
enum MemType {
#[allow(dead_code)]
Device = 0,
Normal = 1,
}
impl PTF {
const ATTR_INDEX_MASK: u64 = 0b111_00;
const fn from_mem_type(mem_type: MemType) -> Self {
let mut bits = (mem_type as u64) << 2;
if matches!(mem_type, MemType::Normal) {
bits |= (Self::INNER.bits() | Self::SHAREABLE.bits()) as u64;
}
Self::from_bits_truncate(bits as usize)
}
#[allow(dead_code)]
fn mem_type(&self) -> MemType {
let idx = (self.bits() as u64 & Self::ATTR_INDEX_MASK) >> 2;
match idx {
0 => MemType::Device,
1 => MemType::Normal,
_ => panic!("Invalid memory attribute index"),
}
}
}
impl From<MMUFlags> for PTF {
fn from(f: MMUFlags) -> Self {
let mut flags = Self::from_mem_type(if f.contains(MMUFlags::DEVICE) {
MemType::Device
} else {
MemType::Normal
});
if f.is_empty() {
return flags;
}
if f.contains(MMUFlags::READ) {
flags |= PTF::VALID;
}
if !f.contains(MMUFlags::WRITE) {
flags |= PTF::AP_RO;
}
if f.contains(MMUFlags::USER) {
flags |= PTF::AP_EL0 | PTF::PXN;
if !f.contains(MMUFlags::EXECUTE) {
flags |= PTF::UXN;
}
} else {
flags |= PTF::UXN;
if !f.contains(MMUFlags::EXECUTE) {
flags |= PTF::PXN;
}
}
flags
}
}
impl From<PTF> for MMUFlags {
fn from(f: PTF) -> Self {
let mut ret = Self::empty();
if f.contains(PTF::VALID) {
ret |= Self::READ;
}
if !f.contains(PTF::AP_RO) {
ret |= Self::WRITE;
}
if f.contains(PTF::AP_EL0) {
ret |= Self::USER;
if !f.contains(PTF::UXN) {
ret |= Self::EXECUTE;
}
} else if f.intersects(PTF::PXN) {
ret |= Self::EXECUTE;
}
if f.mem_type() == MemType::Device {
ret |= Self::DEVICE;
}
ret
}
}
/// Page table entry.
#[derive(Clone, Copy)]
#[repr(transparent)]
pub struct AARCH64PTE(u64);
impl GenericPTE for AARCH64PTE {
fn addr(&self) -> PhysAddr {
(self.0 as usize & PHYS_ADDR_MASK) as _
}
fn flags(&self) -> MMUFlags {
PTF::from_bits_truncate(self.0 as usize).into()
}
fn is_unused(&self) -> bool {
self.0 == 0
}
fn is_present(&self) -> bool {
PTF::from_bits_truncate(self.0 as usize).contains(PTF::VALID)
}
fn is_leaf(&self) -> bool {
!PTF::from_bits_truncate(self.0 as usize).intersects(PTF::NON_BLOCK)
}
fn set_addr(&mut self, paddr: PhysAddr) {
self.0 = (paddr & PHYS_ADDR_MASK) as u64;
}
fn set_flags(&mut self, flags: MMUFlags, is_huge: bool) {
let mut flags = PTF::from(flags) | PTF::AF;
if !is_huge {
flags |= PTF::NON_BLOCK
}
self.0 = (self.0 & PHYS_ADDR_MASK as u64) | flags.bits() as u64;
}
fn set_table(&mut self, paddr: PhysAddr) {
self.0 = (((paddr as usize) & PHYS_ADDR_MASK) | PTF::VALID.bits() | PTF::NON_BLOCK.bits())
as u64;
}
fn clear(&mut self) {
self.0 = 0
}
}
impl Debug for AARCH64PTE {
fn fmt(&self, f: &mut Formatter) -> Result {
let mut f = f.debug_struct("AARCH64PTE");
f.field("raw", &self.0);
f.field("addr", &self.addr());
f.field("flags", &self.flags());
f.finish()
}
}
/// Sv48: Page-Based 48-bit Virtual-Memory System.
pub type PageTable = PageTableImpl<PageTableLevel4, AARCH64PTE>;

View File

@ -5,5 +5,4 @@
pub struct KernelConfig {
pub phys_to_virt_offset: usize,
pub dtb_paddr: usize,
pub dtb_size: usize,
}

View File

@ -1,7 +1,7 @@
//! CPU information.
use crate::utils::init_once::InitOnce;
pub(super) static CPU_FREQ_MHZ: InitOnce<u16> = InitOnce::new_with_default(1000); // 1GHz
pub(super) static CPU_FREQ_MHZ: InitOnce<u16> = InitOnce::new_with_default(10);
hal_fn_impl! {
impl mod crate::hal_fn::cpu {
@ -17,8 +17,7 @@ hal_fn_impl! {
fn reset() -> ! {
info!("shutdown...");
sbi_rt::system_reset(sbi_rt::Shutdown, sbi_rt::NoReason);
unreachable!()
super::sbi::shutdown()
}
}
}

View File

@ -13,12 +13,7 @@ struct IoMapperImpl;
impl IoMapper for IoMapperImpl {
fn query_or_map(&self, paddr: PhysAddr, size: usize) -> Option<VirtAddr> {
let vaddr = if paddr > (1 << 39) {
// To retrieve avaliable sv39 vaddr
paddr | (0x1ffffff << 39)
} else {
phys_to_virt(paddr)
};
let vaddr = phys_to_virt(paddr);
let mut pt = super::vm::kernel_page_table().lock();
if let Ok((paddr_mapped, _, _)) = pt.query(vaddr) {
if paddr_mapped == paddr {
@ -35,7 +30,6 @@ impl IoMapper for IoMapperImpl {
let flags = MMUFlags::READ
| MMUFlags::WRITE
| MMUFlags::HUGE_PAGE
| MMUFlags::DEVICE
| MMUFlags::from_bits_truncate(CachePolicy::UncachedDevice as usize);
if let Err(err) = pt.map_cont(vaddr, size, paddr, flags) {
warn!(
@ -68,7 +62,7 @@ pub(super) fn init() -> DeviceResult {
}
}
#[cfg(not(feature = "no-pci"))]
#[cfg(not(feature = "loopback"))]
{
use alloc::sync::Arc;
use zcore_drivers::bus::pci;

View File

@ -1,6 +1,5 @@
//! Interrupts management.
use crate::{HalError, HalResult};
use alloc::vec::Vec;
use riscv::{asm, register::sstatus};
hal_fn_impl! {
@ -18,10 +17,7 @@ hal_fn_impl! {
fn handle_irq(cause: usize) {
trace!("Handle irq cause: {}", cause);
let irq = crate::drivers::all_irq()
.find(alloc::format!("riscv-intc-cpu{}", crate::cpu::cpu_id()).as_str())
.expect("IRQ device 'riscv-intc' not initialized!");
irq.handle_irq(cause)
crate::drivers::all_irq().first_unwrap().handle_irq(cause)
}
fn intr_on() {
@ -35,25 +31,5 @@ hal_fn_impl! {
fn intr_get() -> bool {
sstatus::read().sie()
}
#[allow(deprecated)]
fn send_ipi(cpuid: usize, reason: usize) -> HalResult {
trace!("ipi [{}] => [{}]", super::cpu::cpu_id(), cpuid);
let queue = crate::common::ipi::ipi_queue(cpuid);
let idx = queue.alloc_entry();
if let Some(idx) = idx {
let entry = queue.entry_at(idx);
*entry = reason;
queue.commit_entry(idx);
let mask:usize = 1 << cpuid;
sbi_rt::legacy::send_ipi(&mask as *const usize as usize);
return Ok(());
}
Err(HalError)
}
fn ipi_reason() -> Vec<usize> {
crate::common::ipi::ipi_reason()
}
}
}

View File

@ -5,24 +5,6 @@ use crate::addr::{align_down, align_up};
use crate::utils::init_once::InitOnce;
use crate::{PhysAddr, KCONFIG, PAGE_SIZE};
fn cut_off(total: Range<PhysAddr>, cut: &Range<PhysAddr>) -> Vec<Range<PhysAddr>> {
let mut regions = Vec::new();
// no overlap at all
if cut.end <= total.start || total.end <= cut.start {
regions.push(total);
} else {
// no overlap on the left
if total.start < cut.start {
regions.push(total.start..align_down(cut.start));
}
// no overlap on the right
if cut.end < total.end {
regions.push(align_up(cut.end)..total.end);
}
}
regions
}
pub fn free_pmem_regions() -> Vec<Range<PhysAddr>> {
extern "C" {
fn end();
@ -31,23 +13,30 @@ pub fn free_pmem_regions() -> Vec<Range<PhysAddr>> {
static FREE_PMEM_REGIONS: InitOnce<Vec<Range<PhysAddr>>> = InitOnce::new();
FREE_PMEM_REGIONS.init_once(|| {
let initrd = super::INITRD_REGION.as_ref();
let dtb = Range::<PhysAddr> {
start: KCONFIG.dtb_paddr,
end: KCONFIG.dtb_paddr + KCONFIG.dtb_size,
};
let min_start = align_up(end as usize + PAGE_SIZE) - KCONFIG.phys_to_virt_offset;
let mut regions = Vec::new();
for r in super::MEMORY_REGIONS.iter() {
let base = align_up(r.start.max(min_start))..align_down(r.end);
let mut no_dtb = cut_off(base, &dtb);
let (start, end) = (align_up(r.start.max(min_start)), align_down(r.end));
if start >= end {
continue;
}
if let Some(initrd) = initrd {
for range in no_dtb {
let mut no_initrd = cut_off(range, initrd);
regions.append(&mut no_initrd);
// no overlap at all
if initrd.end <= start || end <= initrd.start {
regions.push(start..end);
continue;
}
// no overlap on the left
if start < initrd.start {
regions.push(start..align_down(initrd.start));
}
// no overlap on the right
if initrd.end < end {
regions.push(align_up(initrd.end)..end);
}
} else {
regions.append(&mut no_dtb);
regions.push(start..end);
}
}
regions

View File

@ -9,11 +9,12 @@ pub mod sbi;
pub mod timer;
pub mod vm;
use crate::{mem::phys_to_virt, utils::init_once::InitOnce, PhysAddr};
use alloc::{string::String, vec::Vec};
use core::ops::Range;
use zcore_drivers::utils::devicetree::Devicetree;
use crate::{mem::phys_to_virt, utils::init_once::InitOnce, PhysAddr};
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());
@ -55,6 +56,8 @@ 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() {
@ -63,15 +66,9 @@ pub fn timer_init() {
pub fn secondary_init() {
vm::init();
info!("cpu {} drivers init ...", crate::cpu::cpu_id());
drivers::intc_init().unwrap();
let plic = crate::drivers::all_irq()
.find("riscv-plic")
.expect("IRQ device 'riscv-plic' not initialized!");
info!(
"cpu {} enable plic: {:?}",
crate::cpu::cpu_id(),
plic.name()
);
plic.init_hart();
}

View File

@ -95,30 +95,6 @@ pub fn hart_stop() -> usize {
sbi_call(HSM_EID, SBI_HART_STOP_FID, 0, 0, 0)
}
// Just for T-HEAD C910 light
pub const BADDR: u64 = 0xffffffffe7014000;
pub fn uart_put(c: u8) {
let ptr = BADDR as *mut u32;
unsafe {
//LSR bit:THRE
while ptr.add(5).read_volatile() & (1 << 5) == 0 {}
//此时transmitter empty, THR有效位是8
ptr.add(0).write_volatile(c as u32);
}
}
pub fn uart_get() -> Option<u8> {
let ptr = BADDR as *mut u32;
unsafe {
//查看LSR的DR位为1则有数据
if ptr.add(5).read_volatile() & 0b1 == 0 {
None
} else {
Some((ptr.add(0).read_volatile() & 0xff) as u8)
}
}
}
hal_fn_impl! {
impl mod crate::hal_fn::console {
fn console_write_early(s: &str) {

View File

@ -7,7 +7,7 @@ fn get_cycle() -> u64 {
pub(super) fn timer_set_next() {
let cycles =
super::cpu::cpu_frequency() as u64 * 1_000_000 / super::super::timer::TICKS_PER_SEC;
sbi_rt::set_timer(get_cycle() + cycles);
super::sbi::set_timer(get_cycle() + cycles);
}
pub(super) fn init() {

View File

@ -1,9 +1,7 @@
use crate::context::TrapReason;
use crate::thread::{get_current_thread, set_current_thread};
use crate::IpiReason;
use alloc::vec::Vec;
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) {
@ -21,13 +19,8 @@ pub(super) fn super_timer() {
}
pub(super) fn super_soft() {
#[allow(deprecated)]
sbi_rt::legacy::clear_ipi();
let reasons: Vec<IpiReason> = crate::interrupt::ipi_reason()
.iter()
.map(|x| IpiReason::from(*x))
.collect();
debug!("Interrupt::SupervisorSoft, reason = {:?}", reasons);
super::sbi::clear_ipi();
info!("Interrupt::SupervisorSoft!");
}
#[no_mangle]
@ -45,10 +38,7 @@ pub extern "C" fn trap_handler(tf: &mut TrapFrame) {
TrapReason::Interrupt(vector) => {
crate::interrupt::handle_irq(vector);
if vector == SUPERVISOR_TIMER_INT_VEC {
let current_thread = get_current_thread();
set_current_thread(None);
executor::handle_timeout();
set_current_thread(current_thread);
}
}
other => panic!("Undefined trap: {:x?} {:#x?}", other, tf),

View File

@ -6,7 +6,6 @@ use core::slice;
use lock::Mutex;
use riscv::{asm, register::satp};
use crate::addr::{align_down, align_up};
use crate::utils::page_table::{GenericPTE, PageTableImpl, PageTableLevel3};
use crate::{mem::phys_to_virt, MMUFlags, PhysAddr, VirtAddr, KCONFIG};
@ -70,27 +69,8 @@ fn init_kernel_page_table() -> PagingResult<PageTable> {
MMUFlags::READ | MMUFlags::WRITE,
)?;
}
cfg_if! {
if #[cfg(any(feature = "board-fu740", feature = "board-c910light"))] {
extern "C" {
fn boot_stack();
fn boot_stack_top();
}
map_range(
boot_stack as usize,
boot_stack_top as usize,
MMUFlags::READ | MMUFlags::WRITE,
)?;
}}
// device tree
map_range(
phys_to_virt(align_down(KCONFIG.dtb_paddr)),
phys_to_virt(align_up(KCONFIG.dtb_paddr + KCONFIG.dtb_size)),
MMUFlags::READ,
)?;
// physical frames
for r in crate::mem::free_pmem_regions() {
info!("FREE PHY MEM: {:x?}", r);
map_range(
phys_to_virt(r.start),
phys_to_virt(r.end),
@ -117,11 +97,11 @@ hal_fn_impl! {
if old_token != vmtoken {
#[cfg(target_arch = "riscv64")]
let mode = satp::Mode::Sv39;
debug!("switch table {:x?} -> {:x?}", old_token, vmtoken);
unsafe {
satp::set(mode, 0, vmtoken >> 12);
asm::sfence_vma_all();
}
debug!("cpu {} switch table {:x?} -> {:x?}", crate::cpu::cpu_id(), old_token, vmtoken);
}
}
@ -156,20 +136,16 @@ hal_fn_impl! {
bitflags::bitflags! {
/// Possible flags for a page table entry.
struct PTF: usize {
const VALID = 1 << 0;
const READABLE = 1 << 1;
const WRITABLE = 1 << 2;
const EXECUTABLE = 1 << 3;
const USER = 1 << 4;
const GLOBAL = 1 << 5;
const ACCESSED = 1 << 6;
const DIRTY = 1 << 7;
const RESERVED1 = 1 << 8;
const RESERVED2 = 1 << 9;
#[cfg(feature = "thead-maee")]
const CACHEABLE = 1 << 62;
#[cfg(feature = "thead-maee")]
const STRONG_ORDER = 1 << 63;
const VALID = 1 << 0;
const READABLE = 1 << 1;
const WRITABLE = 1 << 2;
const EXECUTABLE = 1 << 3;
const USER = 1 << 4;
const GLOBAL = 1 << 5;
const ACCESSED = 1 << 6;
const DIRTY = 1 << 7;
const RESERVED1 = 1 << 8;
const RESERVED2 = 1 << 9;
}
}
@ -179,18 +155,11 @@ impl From<MMUFlags> for PTF {
return PTF::empty();
}
let mut flags = PTF::VALID;
if f.contains(MMUFlags::READ) {
flags |= PTF::READABLE;
}
if f.contains(MMUFlags::WRITE) {
flags |= PTF::READABLE | PTF::WRITABLE;
#[cfg(feature = "thead-maee")]
{
flags |= PTF::CACHEABLE;
}
} else if f.contains(MMUFlags::READ) {
flags |= PTF::READABLE;
#[cfg(feature = "thead-maee")]
{
flags |= PTF::CACHEABLE;
}
}
if f.contains(MMUFlags::EXECUTE) {
flags |= PTF::EXECUTABLE;
@ -198,10 +167,6 @@ impl From<MMUFlags> for PTF {
if f.contains(MMUFlags::USER) {
flags |= PTF::USER;
}
#[cfg(feature = "thead-maee")]
if f.contains(MMUFlags::DEVICE) {
flags |= PTF::STRONG_ORDER;
}
flags
}
}

View File

@ -47,7 +47,7 @@ pub(super) fn init() -> DeviceResult {
drivers::add_device(Device::Irq(irq));
#[cfg(not(feature = "no-pci"))]
#[cfg(not(feature = "loopback"))]
{
// PCI scan
use zcore_drivers::bus::pci;

View File

@ -5,7 +5,6 @@ use core::ops::Range;
use crate::drivers::all_irq;
use crate::drivers::prelude::{IrqHandler, IrqPolarity, IrqTriggerMode};
use crate::HalResult;
use alloc::vec::Vec;
use x86_64::instructions::interrupts;
hal_fn_impl! {
@ -73,14 +72,5 @@ hal_fn_impl! {
) -> HalResult {
Ok(all_irq().first_unwrap().msi_register_handler(block, msi_id, handler)?)
}
fn send_ipi(cpuid: usize, reason: usize) -> HalResult {
trace!("ipi [{}] => [{}]: {:x}", super::cpu::cpu_id(), cpuid, reason);
panic!("send_ipi unsupported for x86_64");
}
fn ipi_reason() -> Vec<usize> {
panic!("ipi_reason unsupported for x86_64");
}
}
}

View File

@ -1,20 +1,24 @@
use crate::context::TrapReason;
#![allow(dead_code)]
#![allow(clippy::identity_op)]
use trapframe::TrapFrame;
use crate::context::TrapReason;
pub(super) const X86_INT_LOCAL_APIC_BASE: usize = 0xf0;
pub(super) const _X86_INT_APIC_SPURIOUS: usize = X86_INT_LOCAL_APIC_BASE;
pub(super) const X86_INT_APIC_SPURIOUS: usize = X86_INT_LOCAL_APIC_BASE + 0x0;
pub(super) const X86_INT_APIC_TIMER: usize = X86_INT_LOCAL_APIC_BASE + 0x1;
pub(super) const _X86_INT_APIC_ERROR: usize = X86_INT_LOCAL_APIC_BASE + 0x2;
pub(super) const X86_INT_APIC_ERROR: usize = X86_INT_LOCAL_APIC_BASE + 0x2;
// ISA IRQ numbers
pub(super) const _X86_ISA_IRQ_PIT: usize = 0;
pub(super) const _X86_ISA_IRQ_KEYBOARD: usize = 1;
pub(super) const _X86_ISA_IRQ_PIC2: usize = 2;
pub(super) const X86_ISA_IRQ_PIT: usize = 0;
pub(super) const X86_ISA_IRQ_KEYBOARD: usize = 1;
pub(super) const X86_ISA_IRQ_PIC2: usize = 2;
pub(super) const X86_ISA_IRQ_COM2: usize = 3;
pub(super) const X86_ISA_IRQ_COM1: usize = 4;
pub(super) const _X86_ISA_IRQ_CMOSRTC: usize = 8;
pub(super) const _X86_ISA_IRQ_MOUSE: usize = 12;
pub(super) const _X86_ISA_IRQ_IDE: usize = 14;
pub(super) const X86_ISA_IRQ_CMOSRTC: usize = 8;
pub(super) const X86_ISA_IRQ_MOUSE: usize = 12;
pub(super) const X86_ISA_IRQ_IDE: usize = 14;
fn breakpoint() {
panic!("\nEXCEPTION: Breakpoint");

View File

@ -7,10 +7,6 @@ cfg_if! {
#[path = "arch/riscv/mod.rs"]
pub mod arch;
pub use self::arch::{sbi, timer_interrupt_vector};
} else if #[cfg(target_arch = "aarch64")] {
#[path = "arch/aarch64/mod.rs"]
pub mod arch;
pub use self::arch::timer_interrupt_vector;
}
}
@ -24,3 +20,11 @@ pub use self::arch::{config, cpu, interrupt, vm};
pub use super::hal_fn::{rand, vdso};
hal_fn_impl_default!(rand, vdso);
/// Non-SMP initialization.
#[cfg(any(not(feature = "smp"), doc))]
#[doc(cfg(not(feature = "smp")))]
pub fn init(cfg: crate::KernelConfig, handler: &'static impl crate::KernelHandler) {
boot::primary_init_early(cfg, handler);
boot::primary_init();
}

View File

@ -1,15 +1,6 @@
//! Thread spawning.
use alloc::sync::Arc;
use core::{any::Any, future::Future};
use crate::{config::MAX_CORE_NUM, utils::PerCpuCell};
#[allow(clippy::declare_interior_mutable_const)]
const DEFAULT_THREAD: PerCpuCell<Option<Arc<dyn Any + Send + Sync>>> = PerCpuCell::new(None);
static CURRENT_THREAD: [PerCpuCell<Option<Arc<dyn Any + Send + Sync>>>; MAX_CORE_NUM] =
[DEFAULT_THREAD; MAX_CORE_NUM];
use core::future::Future;
hal_fn_impl! {
impl mod crate::hal_fn::thread {
@ -17,18 +8,10 @@ hal_fn_impl! {
executor::spawn(future);
}
fn set_current_thread(thread: Option<Arc<dyn Any + Send + Sync>>) {
let cpu_id = super::cpu::cpu_id() as usize;
*CURRENT_THREAD[cpu_id].get_mut() = thread;
}
fn set_tid(_tid: u64, _pid: u64) {}
fn get_current_thread() -> Option<Arc<dyn Any + Send + Sync>> {
let cpu_id = super::cpu::cpu_id() as usize;
if let Some(arc_thread) = CURRENT_THREAD[cpu_id].get().as_ref() {
Some(arc_thread.clone())
} else {
None
}
fn get_tid() -> (u64, u64) {
(0, 0)
}
}
}

View File

@ -3,20 +3,25 @@
use alloc::boxed::Box;
use core::time::Duration;
use core::sync::atomic::{AtomicBool, Ordering};
use lock::Mutex;
use naive_timer::Timer;
#[allow(dead_code)]
pub(super) const TICKS_PER_SEC: u64 = 1;
pub(super) const TICKS_PER_SEC: u64 = 100;
lazy_static::lazy_static! {
static ref NAIVE_TIMER:Mutex<Timer> = Mutex::new(Timer::default());
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() {
super::arch::timer_init();
if !FIRST.load(Ordering::Relaxed) {
FIRST.store(true, Ordering::Relaxed);
super::arch::timer_init();
}
}
fn timer_now() -> Duration {
@ -24,7 +29,6 @@ hal_fn_impl! {
}
fn timer_set(deadline: Duration, callback: Box<dyn FnOnce(Duration) + Send + Sync>) {
debug!("Set timer at: {:?}", deadline);
NAIVE_TIMER.lock().add(deadline, callback);
}

View File

@ -19,17 +19,6 @@ impl Write for SerialWriter {
}
}
struct DebugWriter;
static DEBUG_WRITER: Mutex<DebugWriter> = Mutex::new(DebugWriter);
impl Write for DebugWriter {
fn write_str(&mut self, s: &str) -> Result {
crate::hal_fn::console::console_write_early(s);
Ok(())
}
}
cfg_if! {
if #[cfg(feature = "graphic")] {
use crate::utils::init_once::InitOnce;
@ -64,16 +53,6 @@ pub fn serial_write_fmt(fmt: Arguments) {
SERIAL_WRITER.lock().write_fmt(fmt).unwrap();
}
/// Writes a string slice into the serial through sbi call.
pub fn debug_write_str(s: &str) {
DEBUG_WRITER.lock().write_str(s).unwrap();
}
/// Writes formatted data into the serial through sbi call..
pub fn debug_write_fmt(fmt: Arguments) {
DEBUG_WRITER.lock().write_fmt(fmt).unwrap();
}
/// Writes a string slice into the graphic console.
#[allow(unused_variables)]
pub fn graphic_console_write_str(s: &str) {

View File

@ -112,53 +112,6 @@ impl TrapReason {
_ => Self::GernelFault(scause.code()),
}
}
#[cfg(target_arch = "aarch64")]
pub fn from(esr: usize) -> Self {
// TODO: check if is right
use crate::{Fault, Info, Kind, Source, Syndrome};
use cortex_a::registers::{ESR_EL1, FAR_EL1};
use tock_registers::interfaces::Readable;
let info = Info {
source: Source::from(esr & 0xffff),
kind: Kind::from((esr >> 16) & 0xffff),
};
let esr = ESR_EL1.get() as u32;
match info.kind {
Kind::Synchronous => match Syndrome::from(esr) {
Syndrome::Breakpoint => Self::SoftwareBreakpoint,
Syndrome::Svc(_) => Self::Syscall,
Syndrome::DataAbort { kind: _, level: _ } => Self::PageFault(
FAR_EL1.get() as _,
MMUFlags::READ | MMUFlags::WRITE | MMUFlags::USER,
),
Syndrome::InstructionAbort {
kind: Fault::Permission,
level: _,
} => Self::PageFault(FAR_EL1.get() as _, MMUFlags::EXECUTE | MMUFlags::USER),
Syndrome::PCAlignmentFault | Syndrome::SpAlignmentFault => Self::UnalignedAccess,
_ => Self::GernelFault(esr as usize),
},
Kind::Irq => Self::Interrupt(
#[cfg(not(feature = "libos"))]
{
use crate::hal_fn::mem::phys_to_virt;
use crate::KCONFIG;
zcore_drivers::irq::gic_400::get_irq_num(
phys_to_virt(KCONFIG.gic_base + 0x1_0000),
phys_to_virt(KCONFIG.gic_base),
)
},
#[cfg(feature = "libos")]
{
// TODO: interrupt in libOS
usize::MAX
},
),
_ => Self::GernelFault(esr as usize),
}
}
}
/// User context saved on trap.
@ -215,8 +168,6 @@ impl UserContext {
self.0.general.ra = _ra;
} else if #[cfg(target_arch = "x86_64")] {
error!("Please set return addr via stack!");
} else if #[cfg(target_arch = "aarch64")] {
self.0.general.x30 = _ra;
} else {
unimplemented!("Unsupported arch!");
}
@ -247,7 +198,7 @@ impl UserContext {
if #[cfg(target_arch = "x86_64")] {
TrapReason::from(self.0.trap_num, self.0.error_code)
} else if #[cfg(target_arch = "aarch64")] {
TrapReason::from(self.0.trap_num)
unimplemented!() // ESR_EL1
} else if #[cfg(target_arch = "riscv64")] {
TrapReason::from(riscv::register::scause::read())
} else {

View File

@ -20,13 +20,12 @@ bitflags! {
const EXECUTE = 1 << 4;
const USER = 1 << 5;
const HUGE_PAGE = 1 << 6;
const DEVICE = 1 << 7;
const RXW = Self::READ.bits | Self::WRITE.bits | Self::EXECUTE.bits;
}
}
numeric_enum! {
#[repr(u32)]
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[derive(Debug, PartialEq, Clone, Copy)]
/// Generic cache policy.
pub enum CachePolicy {
Cached = 0,
@ -36,164 +35,6 @@ numeric_enum! {
}
}
cfg_if! {
if #[cfg(target_arch = "aarch64")] {
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum Kind {
Synchronous = 0,
Irq = 1,
Fiq = 2,
SError = 3,
}
impl Kind {
pub fn from(x: usize) -> Kind {
match x {
x if x == Kind::Synchronous as usize => Kind::Synchronous,
x if x == Kind::Irq as usize => Kind::Irq,
x if x == Kind::Fiq as usize => Kind::Fiq,
x if x == Kind::SError as usize => Kind::SError,
_ => panic!("bad kind"),
}
}
}
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum Source {
CurrentSpEl0 = 0,
CurrentSpElx = 1,
LowerAArch64 = 2,
LowerAArch32 = 3,
}
impl Source {
pub fn from(x: usize) -> Source {
match x {
x if x == Source::CurrentSpEl0 as usize => Source::CurrentSpEl0,
x if x == Source::CurrentSpElx as usize => Source::CurrentSpElx,
x if x == Source::LowerAArch64 as usize => Source::LowerAArch64,
x if x == Source::LowerAArch32 as usize => Source::LowerAArch32,
_ => panic!("bad kind"),
}
}
}
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub struct Info {
pub source: Source,
pub kind: Kind,
}
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum Fault {
AddressSize,
Translation,
AccessFlag,
Permission,
Alignment,
TlbConflict,
Other(u8),
}
impl From<u32> for Fault {
fn from(val: u32) -> Fault {
use self::Fault::*;
// IFSC or DFSC bits (ref: D10.2.39, Page 2457~2464).
match val & 0b111100 {
0b000000 => AddressSize,
0b000100 => Translation,
0b001000 => AccessFlag,
0b001100 => Permission,
0b100000 => Alignment,
0b110000 => TlbConflict,
_ => Other((val & 0b111111) as u8),
}
}
}
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum Syndrome {
Unknown,
WfiWfe,
McrMrc,
McrrMrrc,
LdcStc,
SimdFp,
Vmrs,
Mrrc,
IllegalExecutionState,
Svc(u16),
Hvc(u16),
Smc(u16),
MsrMrsSystem,
InstructionAbort { kind: Fault, level: u8 },
PCAlignmentFault,
DataAbort { kind: Fault, level: u8 },
SpAlignmentFault,
TrappedFpu,
SError,
Breakpoint,
Step,
Watchpoint,
Brk(u16),
Other(u32),
}
/// Converts a raw syndrome value (ESR) into a `Syndrome` (ref: D1.10.4, D10.2.39).
impl From<u32> for Syndrome {
fn from(esr: u32) -> Syndrome {
use self::Syndrome::*;
let ec = esr >> 26;
let iss = esr & 0xFFFFFF;
match ec {
0b000000 => Unknown,
0b000001 => WfiWfe,
0b000011 => McrMrc,
0b000100 => McrrMrrc,
0b000101 => McrMrc,
0b000110 => LdcStc,
0b000111 => SimdFp,
0b001000 => Vmrs,
0b001100 => Mrrc,
0b001110 => IllegalExecutionState,
0b010001 => Svc((iss & 0xFFFF) as u16),
0b010010 => Hvc((iss & 0xFFFF) as u16),
0b010011 => Smc((iss & 0xFFFF) as u16),
0b010101 => Svc((iss & 0xFFFF) as u16),
0b010110 => Hvc((iss & 0xFFFF) as u16),
0b010111 => Smc((iss & 0xFFFF) as u16),
0b011000 => MsrMrsSystem,
0b100000 | 0b100001 => InstructionAbort {
kind: Fault::from(iss),
level: (iss & 0b11) as u8,
},
0b100010 => PCAlignmentFault,
0b100100 | 0b100101 => DataAbort {
kind: Fault::from(iss),
level: (iss & 0b11) as u8,
},
0b100110 => SpAlignmentFault,
0b101000 => TrappedFpu,
0b101100 => TrappedFpu,
0b101111 => SError,
0b110000 => Breakpoint,
0b110001 => Breakpoint,
0b110010 => Step,
0b110011 => Step,
0b110100 => Watchpoint,
0b110101 => Watchpoint,
0b111100 => Brk((iss & 0xFFFF) as u16),
other => Other(other),
}
}
}
}
}
/// The smallest size of a page (4K).
pub const PAGE_SIZE: usize = super::vm::PageSize::Size4K as usize;

View File

@ -1,82 +0,0 @@
use crate::{config::MAX_CORE_NUM, utils::mpsc_queue::MpscQueue};
use alloc::vec::Vec;
const REASON_SIZE: usize = 16;
static mut IPI_REASON0: [IpiEntry; REASON_SIZE] = [0; REASON_SIZE];
static mut IPI_REASON1: [IpiEntry; REASON_SIZE] = [0; REASON_SIZE];
static mut IPI_REASON2: [IpiEntry; REASON_SIZE] = [0; REASON_SIZE];
static mut IPI_REASON3: [IpiEntry; REASON_SIZE] = [0; REASON_SIZE];
static mut IPI_REASON4: [IpiEntry; REASON_SIZE] = [0; REASON_SIZE];
static mut IPI_REASON5: [IpiEntry; REASON_SIZE] = [0; REASON_SIZE];
static mut IPI_REASON6: [IpiEntry; REASON_SIZE] = [0; REASON_SIZE];
static mut IPI_REASON7: [IpiEntry; REASON_SIZE] = [0; REASON_SIZE];
pub type IpiEntry = usize;
type IRQueue = MpscQueue<'static, IpiEntry>;
lazy_static::lazy_static! {
static ref IPI_QUEUE: [IRQueue; MAX_CORE_NUM] = [
IRQueue::new(unsafe {&mut IPI_REASON0} ),
IRQueue::new(unsafe {&mut IPI_REASON1} ),
IRQueue::new(unsafe {&mut IPI_REASON2} ),
IRQueue::new(unsafe {&mut IPI_REASON3} ),
IRQueue::new(unsafe {&mut IPI_REASON4} ),
IRQueue::new(unsafe {&mut IPI_REASON5} ),
IRQueue::new(unsafe {&mut IPI_REASON6} ),
IRQueue::new(unsafe {&mut IPI_REASON7} ),
];
}
pub(crate) fn ipi_queue(cpuid: usize) -> &'static IRQueue {
&IPI_QUEUE[cpuid]
}
pub(crate) fn ipi_reason() -> Vec<usize> {
let cpu_id = crate::cpu::cpu_id() as usize;
let queue = ipi_queue(cpu_id);
queue.consume_entrys().iter().map(|entry| entry.1).collect()
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum IpiReason {
Invalid,
MockBlock { block_info: usize },
TlbShutdown { vpn: usize }, // unused
}
/// usize : 64bit
/// | type reason : 4bit | ipi info : 60bit |
///
/// MockBlock info : 60bit
/// | reserved : 60 bit |
///
const TYPE_SHIFT: usize = 60;
const TYPE_INVALID: usize = 0x0;
const TYPE_MOCK_BLOCK: usize = 0x1;
const TYPE_TLB_SHUTDOWN: usize = 0x2;
impl From<IpiEntry> for IpiReason {
fn from(r: IpiEntry) -> Self {
let ipi_type = r >> TYPE_SHIFT;
let ipi_info = r & 0x000FFFFFFFFFFFFF;
match ipi_type {
TYPE_MOCK_BLOCK => Self::MockBlock {
block_info: ipi_info,
},
TYPE_TLB_SHUTDOWN => Self::TlbShutdown { vpn: ipi_info },
_ => Self::Invalid,
}
}
}
impl From<IpiReason> for IpiEntry {
fn from(reason: IpiReason) -> Self {
match reason {
IpiReason::MockBlock { block_info: info } => (TYPE_MOCK_BLOCK << TYPE_SHIFT) | info,
IpiReason::TlbShutdown { vpn: info } => (TYPE_TLB_SHUTDOWN << TYPE_SHIFT) | info,
IpiReason::Invalid => 0,
}
}
}

View File

@ -8,5 +8,4 @@ pub(super) mod vm;
pub mod addr;
pub mod console;
pub mod context;
pub mod ipi;
pub mod user;

View File

@ -12,7 +12,6 @@ use core::{
// 来自用户空间的裸指针
/// Raw pointer from user land.
#[repr(transparent)]
#[derive(Copy, Clone)]
pub struct UserPtr<T, P: Policy>(*mut T, PhantomData<P>);
// 标识用户指针功能的基特征。
@ -178,7 +177,6 @@ impl<T, P: Read> UserPtr<T, P> {
/// Copies elements into a new [`Vec`].
///
/// The `len` argument is the number of **elements**, not the number of bytes.
#[allow(clippy::uninit_vec)]
pub fn read_array(&self, len: usize) -> Result<Vec<T>> {
if len == 0 {
Ok(Vec::default())
@ -279,39 +277,24 @@ impl<P: Write> UserPtr<u8, P> {
}
}
#[derive(Debug)]
#[repr(C)]
pub struct IoVec<P: Policy> {
pub struct IoVec<P: 'static + Policy> {
/// Starting address
ptr: UserPtr<u8, P>,
/// Number of bytes to transfer
len: usize,
}
impl<P: Policy> core::fmt::Debug for IoVec<P> {
fn fmt(&self, f: &mut Formatter) -> core::fmt::Result {
write!(f, "IoVec ptr:{:?} len :{:?}", self.ptr.0, self.len)
}
}
pub type IoVecIn = IoVec<In>;
pub type IoVecOut = IoVec<Out>;
pub type IoVecsOut = IoVecs<Out>;
/// A valid IoVecs request from user
#[derive(Debug)]
pub struct IoVecs<P: 'static + Policy> {
vec: Vec<IoVec<P>>,
}
impl<P: Policy> Debug for IoVecs<P> {
fn fmt(&self, f: &mut Formatter) -> core::fmt::Result {
write!(f, "IoVec len :{:?}", self.vec.len())
}
}
impl IoVecs<Out> {
pub fn new(iov_ptr: UserInPtr<IoVec<Out>>, iov_count: usize) -> IoVecs<Out> {
iov_ptr.read_iovecs(iov_count).unwrap()
}
}
impl<P: Policy> UserInPtr<IoVec<P>> {
pub fn read_iovecs(&self, count: usize) -> Result<IoVecs<P>> {
if self.0.is_null() {

View File

@ -47,10 +47,9 @@ pub struct Features {
impl VdsoConstants {
/// Set version string.
pub fn set_version_string(&mut self, s: &str) {
let bytes = s.as_bytes();
let len = bytes.len().min(64);
let len = s.len().min(64);
self.version_string_len = len as u64;
self.version_string.0[..len].copy_from_slice(&bytes[..len]);
self.version_string.0[..len].copy_from_slice(s.as_bytes());
}
}

View File

@ -145,11 +145,7 @@ pub trait GenericPageTable: Sync + Send {
fn unmap_cont(&mut self, start_vaddr: VirtAddr, size: usize) -> PagingResult {
assert!(is_aligned(start_vaddr));
assert!(is_aligned(size));
debug!(
"{:#x?} unmap_cont: {:#x?}",
self.table_phys(),
start_vaddr..start_vaddr + size
);
debug!("unmap_cont: {:#x?}", start_vaddr..start_vaddr + size);
let mut vaddr = start_vaddr;
let end_vaddr = vaddr + size;
while vaddr < end_vaddr {

View File

@ -7,5 +7,3 @@ pub(crate) static KCONFIG: InitOnce<KernelConfig> = InitOnce::new_with_default(K
#[cfg(not(feature = "libos"))]
pub(crate) static KCONFIG: InitOnce<KernelConfig> = InitOnce::new();
pub const MAX_CORE_NUM: usize = 8;

View File

@ -186,10 +186,4 @@ mod drivers_ffi {
extern "C" fn drivers_virt_to_phys(vaddr: VirtAddr) -> PhysAddr {
vaddr - KCONFIG.phys_to_virt_offset
}
use crate::hal_fn::timer::timer_now;
#[no_mangle]
extern "C" fn drivers_timer_now_as_micros() -> u64 {
timer_now().as_micros() as _
}
}

View File

@ -1,5 +1,5 @@
use alloc::{boxed::Box, string::String, sync::Arc, vec::Vec};
use core::{any::Any, future::Future, ops::Range, time::Duration};
use alloc::{boxed::Box, string::String, vec::Vec};
use core::{future::Future, ops::Range, time::Duration};
use crate::drivers::prelude::{IrqHandler, IrqPolarity, IrqTriggerMode};
use crate::{common, HalResult, KernelConfig, KernelHandler, PhysAddr, VirtAddr};
@ -18,12 +18,15 @@ hal_fn_def! {
}
/// Initialize the primary CPU at an early stage (before the physical frame allocator).
#[doc(cfg(feature = "smp"))]
pub fn primary_init_early(cfg: KernelConfig, handler: &'static impl KernelHandler) {}
/// The main part of the primary CPU initialization.
#[doc(cfg(feature = "smp"))]
pub fn primary_init();
/// Initialize the secondary CPUs.
#[doc(cfg(feature = "smp"))]
pub fn secondary_init() {}
}
@ -42,7 +45,7 @@ hal_fn_def! {
/// Physical memory operations.
pub mod mem: common::mem {
/// Convert physical address to virtual address.
pub fn phys_to_virt(paddr: PhysAddr) -> VirtAddr;
pub(crate) fn phys_to_virt(paddr: PhysAddr) -> VirtAddr;
/// Convert virtual address to physical address.
pub fn virt_to_phys(vaddr: VirtAddr) -> PhysAddr;
@ -134,10 +137,6 @@ hal_fn_def! {
/// NULL handler will effectively unregister a handler for a given msi_id within the
/// block.
pub fn msi_register_handler(block: Range<usize>, msi_id: usize, handler: IrqHandler) -> HalResult;
pub fn send_ipi(cpuid: usize, reason: usize) -> HalResult;
pub fn ipi_reason() -> Vec<usize>;
}
pub mod console {
@ -150,10 +149,10 @@ hal_fn_def! {
pub fn spawn(future: impl Future<Output = ()> + Send + 'static);
/// Set tid and pid of current task.
pub fn set_current_thread(thread: Option<Arc<dyn Any + Send + Sync>>) {}
pub fn set_tid(tid: u64, pid: u64);
/// Get tid and pid of current task.
pub fn get_current_thread() -> Option<Arc<dyn Any + Send + Sync>> { None }
pub fn get_tid() -> (u64, u64);
}
/// Time and clock functions.

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