Compare commits
No commits in common. "master" and "master" have entirely different histories.
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
prebuilt/**/* filter=lfs diff=lfs merge=lfs -text
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y $@
|
||||
pip3 install -r tests/requirements.txt
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -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__
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
2
LICENSE
|
|
@ -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.
|
||||
48
Makefile
|
|
@ -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.
|
||||
|
|
|
|||
278
README-arch.md
|
|
@ -1,278 +0,0 @@
|
|||
# zCore
|
||||
|
||||
[](https://github.com/rcore-os/zCore/actions)
|
||||
[](https://rcore-os.github.io/zCore/)
|
||||
[](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
|
||||
|
||||

|
||||
|
||||
[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
|
|
@ -1,270 +1,282 @@
|
|||
# zCore
|
||||
|
||||
[](https://github.com/rcore-os/zCore/actions)
|
||||
[](https://rcore-os.github.io/zCore/)
|
||||
[](https://github.com/rcore-os/zCore/actions)
|
||||
[](https://rcore-os.github.io/zCore/)
|
||||
[](https://coveralls.io/github/rcore-os/zCore?branch=master)
|
||||
[](https://github.com/rcore-os/zCore/issues)
|
||||
[](https://github.com/rcore-os/zCore/fork)
|
||||

|
||||

|
||||
|
||||
基于 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 和 Debian11,Ubuntu22.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 递归执行 B(A 依赖 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 目录对应位置。
|
||||

|
||||
|
||||
```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>
|
||||
|
|
|
|||
|
|
@ -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"]
|
||||
|
|
@ -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=?>
|
||||
```
|
||||
|
|
@ -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 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`,打上patch:https://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中通用存在。
|
||||
|
||||

|
||||
|
||||
zCore中先尝试把内核的`CACHE`,`SHARE`,`BUF`这些位在构建内核页表时置位上,启动发现问题依旧,依然停在切换页表`switch table`之后,原因不详???
|
||||
|
||||
既然基于RISCV标准进行自定义拓展的位,理论上应该是可以关闭的吧,于是继续在芯片手册中查找,果然在拓展状态寄存器`MXSTATUS`中找到了相应的设置位`MAEE`
|
||||
|
||||

|
||||
|
||||
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中设置对应位;
|
||||
|
||||

|
||||
|
||||
于是直接关闭虚拟内存的页表项拓展属性,设置`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:
|
||||
|
||||

|
||||
|
|
@ -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`,运行如下所示:
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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 开发板
|
||||
|
||||

|
||||
|
||||
```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)
|
||||
|
|
@ -1,257 +0,0 @@
|
|||
# zCore
|
||||
|
||||
[](https://github.com/rcore-os/zCore/actions)
|
||||
[](https://rcore-os.github.io/zCore/)
|
||||
[](https://coveralls.io/github/rcore-os/zCore?branch=master)
|
||||
[](https://github.com/rcore-os/zCore/issues)
|
||||
[](https://github.com/rcore-os/zCore/fork)
|
||||

|
||||

|
||||
|
||||
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.
|
||||
|
|
@ -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.64(2022-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");
|
||||
```
|
||||
|
||||
> 现有代码不完全满足以上标准,将逐步改正
|
||||
|
Before Width: | Height: | Size: 147 KiB |
|
Before Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 578 KiB |
|
Before Width: | Height: | Size: 5.7 MiB |
|
Before Width: | Height: | Size: 7.4 MiB |
|
Before Width: | Height: | Size: 119 KiB |
|
Before Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 61 KiB |
|
Before Width: | Height: | Size: 122 KiB |
|
Before Width: | Height: | Size: 166 KiB |
|
Before Width: | Height: | Size: 121 KiB |
|
Before Width: | Height: | Size: 2.8 MiB |
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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) => {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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!()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -86,7 +86,6 @@ pub fn usdelay(us: u64) {
|
|||
}
|
||||
|
||||
// 毫秒(ms)
|
||||
#[allow(unused)]
|
||||
pub fn msdelay(ms: u64) {
|
||||
usdelay(ms * 1000);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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和PRP2,Host就是通过这两个域告诉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;
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
pub mod interface;
|
||||
pub mod nvme_queue;
|
||||
|
||||
pub use interface::*;
|
||||
pub use nvme_queue::*;
|
||||
|
|
@ -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;
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 _) }
|
||||
}
|
||||
}
|
||||
|
|
@ -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(())
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
@ -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) => {
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
//! Event handler and device tree.
|
||||
|
||||
#![allow(unused_imports)]
|
||||
|
||||
mod event_listener;
|
||||
mod id_allocator;
|
||||
mod irq_manager;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -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!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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!()
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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()
|
||||
),
|
||||
}
|
||||
}
|
||||
|
|
@ -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>;
|
||||
|
|
@ -5,5 +5,4 @@
|
|||
pub struct KernelConfig {
|
||||
pub phys_to_virt_offset: usize,
|
||||
pub dtb_paddr: usize,
|
||||
pub dtb_size: usize,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -8,5 +8,4 @@ pub(super) mod vm;
|
|||
pub mod addr;
|
||||
pub mod console;
|
||||
pub mod context;
|
||||
pub mod ipi;
|
||||
pub mod user;
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 _
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||